TECHBLOG

WordPress > プラグイン

Advanced Custom Fields PRO 返り値を整形

Create:

Update:

Category:WordPressプラグイン

Series:Advanced Custom Fields PRO

[ Version.19 ]

概要

弊社で標準インストールするプラグイン「Advanced Custom Fields PRO」。

管理画面作成には欠かせないプラグインで、作成したい管理画面が、これひとつでほぼ全て作成できます。

返り値は、設定画面で指定できるのですが、残念なことにその「型」が一定ではありません。

一定でない例

公開後に、入力欄が増えることがありますが、当然ながら既存投稿の 該当 postmeta がDBにはありません。そんな時でもエラーにならない get_field ですが、型までは対応してくれません。

Warning

チェックボックスや繰り返しフィールドの配列の処理などで「配列でない」と Warning されることもあります。

functions.php

弊社では、これらに対処すべく返り値を全て吸収するように標準で対処しています。

functions.php で下記のクラスを include して、Advanced Custom Fields PRO の値を取得する際に使用します。

include_once 'xxx/functions_classes.php';

以下、functions_classes.php

返り値の整形(OoAttr)

以下、長いですがその一部です。セッター、ゲッターで整形しています。

これらをMVCのモデルのModelで使用します。

WordPressをMVCで構築

class OoAttr
{
	private $res;
	/**
	 * acf
	 * 	setter
	 */
	protected function acf($key, $post_id)
	{
		$this->res = get_field($key, $post_id);
		return $this;
	}
	/**
	 * get
	 * 	getter
	 */
	protected function get()
	{
		return $this->res;
	}
	/**
	 * disp
	 * 	getter
	 */
	protected function disp()
	{
		return $this->res === 'show';
	}
	protected function textarea()
	{
		$this->res = self::adjustTextarea($this->res);
		return $this;
	}
	protected function textareaToArr()
	{
		$this->textarea(); // <br>追加
		$this->res = $this->res ? explode('<br>', $this->res) : [];
		return $this;
	}
	protected function content($tb = "\t\t\t\t\t\t\t", $prefix = '', $suffix = '')
	{
		$this->res = self::adjustContent($this->res, $tb, $prefix, $suffix);
		return $this;
	}
	protected function trim($length = 70, $add_text = '・・・')
	{
		$this->res = self::removeWpTag($this->res);
		$this->res = mb_strlen($this->res) > $length ? mb_substr($this->res, 0, $length) . $add_text : $this->res;
		return $this;
	}
	protected function image($res_type = 'medium', $noimage = '/images/lib/parts/noimage_icon.svg')
	{
		if (!is_array($this->res) || !$this->res) {
			// this->res返り値がboth出ない時の判定
			$this->res = $this->res ? $this->res : $noimage;
		} elseif (!in_array($res_type, ['url', 'thumbnail', 'medium', 'medium_large', 'large', 'filename', 'caption'])) {
			$this->res = 'error_oo_arg_res_type_text';
		} else {
			if ($res_type === 'url') {
				$this->res = $this->res['url'] ?? $noimage;
			} elseif ($res_type === 'thumbnail') {
				$this->res = $this->res['sizes']['thumbnail'] ?? $noimage;
			} elseif ($res_type === 'medium') {
				$this->res = $this->res['sizes']['medium'] ?? $noimage;
			} elseif ($res_type === 'medium_large') {
				$this->res = $this->res['sizes']['medium_large'] ?? $noimage;
			} elseif ($res_type === 'large') {
				$this->res = $this->res['sizes']['large'] ?? $noimage;
			} elseif ($res_type === 'filename') {
				$this->res = $this->res['filename'] ?? '';
			} elseif ($res_type === 'caption') {
				$this->res = $this->res['caption'] ?? '';
			} else {
				$this->res = $noimage;
			}
		}
		return $this;
	}
	protected function date($format)
	{
		if (preg_match('/\A[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}\z/', $this->res)) {
			$timestamp = date_i18n('U', strtotime($this->res));
		} else {
			$timestamp = $this->res;
		}
		$this->res = date_i18n($format, $timestamp);
		return $this;
	}
	protected function radio($res_type = 'both')
	{
		if ($res_type === 'both') {
			$temp = (object) [
				'value' => $this->res->value ?? $this->res['value'] ?? $this->res ?? 'error_value',
				'label' => $this->res->label ?? $this->res['label'] ?? $this->res ?? 'error_label',
			];
		} elseif ($res_type === 'value') {
			$temp = $this->res->value ?? $this->res['value'] ?? $this->res ?? 'error_value';
		} elseif ($res_type === 'label') {
			$temp = $this->res->label ?? $this->res['label'] ?? $this->res ?? 'error_label';
		} else {
			$temp = 'error_type';
		}
		$this->res = $temp;
		return $this;
	}
	protected function select($res_type = 'both')
	{
		$this->radio($res_type);
		return $this;
	}
	protected function checkbox($res_type = 'both')
	{
		$this->res = is_array($this->res) ? $this->res : [];
		$res = [];
		foreach ($this->res as $v) {
			if ($res_type === 'both') {
				$temp = (object) [
					'value' => $v->value ?? $v['value'] ?? $v ?? 'error_value',
					'label' => $v->label ?? $v['label'] ?? $v ?? 'error_label',
				];
			} elseif ($res_type === 'value') {
				$temp = $v->value ?? $v['value'] ?? $v ?? 'error_value';
			} elseif ($res_type === 'label') {
				$temp = $v->label ?? $v['label'] ?? $v ?? 'error_label';
			} else {
				$temp = 'error_type';
			}
			$res[] = $temp;
		}
		$this->res = $res;
		return $this;
	}
	protected function link()
	{
		$this->res = is_array($this->res) ? $this->res : [];
		if (isset($this->res['title'], $this->res['url'], $this->res['target'])) {
			$res = (object) $this->res;
			$this->res = $res;
		}
		return $this;
	}
	protected function relation()
	{
		$this->res = is_array($this->res) ? $this->res : [];
		$arr = [];
		foreach ($this->res as $v) {
			if (get_post_status($v) === 'publish' || is_user_logged_in()) {
				$arr[] = $v;
			}
		}
		$this->res = $arr;
		return $this;
	}
	protected function repeat($child_key = false)
	{
		$this->res = is_array($this->res) ? $this->res : [];
		$res = []; // 配列とオブジェクトの混在回避
		foreach ($this->res as $v) {
			$res[] = (object) $v;
		}
		$this->res = $res;
		return $this;
	}
	protected function group($child_key = false)
	{
		$this->res = is_array($this->res) ? $this->res : [];
		if ($child_key && isset($this->res[$child_key])) {
			$res = $this->res[$child_key];
		} else {
			$res = (object) $this->res;
		}
		$this->res = $res;
		return $this;
	}
	private static function removeWpTag($tag)
	{
		$tag = preg_replace('/<!--more-->.+/is', '', $tag); // moreタグ以降削除
		$tag = strip_shortcodes($tag); // ショートコード削除
		$tag = strip_tags($tag); // タグ除去
		$tag = str_replace('&nbsp;', '', $tag); // 特殊文字の削除(現在スペースのみ)
		$tag = str_replace(["\r\n", "\n", "\r", "\t"], '', $tag); // 改行タブ除去
		return $tag;
	}
	private static function adjustTextarea($texts)
	{
		$texts = nl2br($texts, false); // <br>追加
		$texts = str_replace('<br />', '<br>', $texts); // html5タグ
		$texts = str_replace(["\r\n", "\n", "\r"], '', $texts); // 改行除去
		return $texts;
	}
	private static function adjustContent($content, $tb = "\t\t\t\t\t\t\t", $prefix = '', $suffix = '')
	{
		$content = str_replace(["\r\n", "\n", "\r"], '', $content); // 改行除去
		$content = str_replace('<br />', '<br>', $content); // html5タグ
		$content = str_replace('<p', "\n" . $tb . '<p', $content); // <p>改行
		$content = str_replace('<h', "\n" . $tb . '<h', $content); // <h>改行
		$content = str_replace('<ul', "\n" . $tb . '<ul', $content); // <ul>改行
		$content = str_replace('<ol', "\n" . $tb . '<ol', $content); // <ol>改行
		$content = str_replace('</ul', "\n" . $tb . '</ul', $content); // </ul>改行
		$content = str_replace('</ol', "\n" . $tb . '</ol', $content); // </ol>改行
		$content = str_replace('<li', "\n" . $tb . "\t" . '<li', $content); // <li>改行
		$content = trim($content); // 先頭/末尾の空白文字(" \t\n\r\0\x0B")除去
		$content = empty($content) ? '' : $prefix . $content . $suffix . "\n"; // prefix & suffix
		return $content;
	}
}

返り値の整形(Model)

上記のclassを継承してModelを作成します。

それぞれ、値がない場合も期待する型で返してくれます。

/**--------------------------------------------------------------
 *
 * XxModel
 *
 --------------------------------------------------------------*/
class XxModel extends OoAttr
{
	public function getAttr($post_id)
	{
		/* post */
		$post = (object) [];
		$post->post_id = $post_id;
		$post->post_title = get_the_title($post_id);
		$post->permalink = get_permalink($post_id);
		// dete
		$post->post_date = get_the_date('Y/n/j(D)', $post_id);
		// content
		$post->post_content = parent::post_content($post_id);
		// acf
		$post->acf_texts = $this->acf('acf_texts', $post_id)->textarea()->get();
		$post->acf_pic = $this->acf('acf_pic', $post_id)->image('medium')->get();
		$post->acf_radio = $this->acf('acf_radio', $post_id)->radio('both')->get();
		$post->acf_group = (object) [];
		$post->acf_group->texts = $this->acf('acf_group', $post_id)->group('texts')->textarea()->get();
		return $post;
	}
}
loading