Blog

Advanced Custom Fieldsプラグインを使う際の注意点など

Posted by admin at 8:51 日時 2013/04/09

[2013/07/29 追記] Advanced Custom Fieldsで検索して来られる方が多いのですが、基礎的な使い方を知りたい方はこちらの書籍などがお勧めです。WordPress Advanced Custom Fields の使い方


Advanced Custom Fields(ACF)というWordPressのカスタムフィールドを拡張するプラグインが最近メジャーバージョンアップしまして、以前から気になっていたデータの持ち方についてちょっと調べてみました。

ACFのフィールドグループはカスタム投稿タイプ「acf」の投稿データとしてwp_postsに保存されています。

wp_postsからフィールドグループのpost_idを割り出し、wp_postmetaテーブルを検索してみます。すると、フィールドグループ内の各カスタムフィールドのデータがシリアライズされて格納されていました。

アンシリアライズするとこんな感じ。これは単に設定が保存されているだけですね。

array(10) {    ["key"]=>    string(19) "field_5162f24a9a8f4"    ["label"]=>    string(4) "text"    ["name"]=>    string(4) "text"    ["type"]=>    string(4) "text"  ...

次に、実際に投稿のカスタムフィールドとしてACFで設定したフィールドに入力して保存すると、データベースにどんなデータが保存されるのか。今度は作成した投稿のIDでwp_postmetaテーブルを検索してみます。

meta_id	post_id	meta_key	meta_value  167	1355	text	テキスト  168	1355	_text	field_5162f24a9a8f4  169	1355	number	123  170	1355	_number	field_5162f2589a8f5

カスタムフィールド text の場合、ちゃんと text がメタキーとしてデータが保存されています。同名のキーで先頭にアンダーバーを付けたものも作られていて、こちらはACFのフィールドキーが格納されています。このフィールドキーのデータがないと、ACFのget_field関数で正しくデータを読み込むことができなくなってしまいます。

例えば、画像フィールドは返り値が画像のオブジェクトか、URLか、IDか選べますが、試しに該当するデータを消してみると、選択した形式ではなく保存されている素のデータ(ID)が返ってきます。これは、すでにあったカスタムフィールドの値をACFで表示しようと思った時も同様の問題が発生しますが、管理画面から一度でも保存すればこのアンダーバーで始まるデータが作られますので、get_field関数が使えるようになります。

でも、管理画面からいちいち保存するのも面倒なので、なんとかアンダーバーで始まるフィールド参照用のデータを一括で生成するAPIが無いものかと思ってるんですが、見つけられていません。

このように一つの値を保存する場合はまだ、WordPress標準のデータの持ち方と同じなので良いのですが、もし複数の値を保存している場合は、シリアライズ化されてしまうようです。例えば、ページとページを関連付ける relational フィールドの場合。

meta_id	post_id	meta_key	meta_value  187	1355	relation	a:3:{i:0;s:1:"1";i:1;s:3:"155";i:2;s:3:"156";}  188	1355	_relation	field_5162f2d89a8fe

見事にシリアライズされちゃってます。アンシリアライズするとこういうデータ。

array(3) {    [0]=>    string(1) "1"    [1]=>    string(3) "155"    [2]=>    string(3) "156"  }

テキストデータの配列ですね。テキストは投稿IDを指している模様。WordPressではカスタムフィールドのキーの重複が許される(同じキーで複数のデータが保存できる)ので、シリアライズ化して無理やりひとつにまとめる必要性は無いと思うんですが、どうなんでしょう。

他にも複数指定できるフィールドがいくつかあるので試してみたのですがいずれもシリアライズ化して格納するようです。

色々なフィールドを試してみた

Twitterでちょっと話題になっていたのを見かけたのですが、このようにシリアライズ化されてしまうと、検索がやっかいであると。ACFの開発者も認めているようで、meta_queryのcompareのに「LIKE」を使い、ダブルクオーテーションで囲むとシリアライズ化されたデータでも検索できるよ、としています。

/*  *  Query posts for a relationship value.  *  This method uses the meta_query LIKE to match the string "123" to the database value a:1:{i:0;s:3:"123";} (serialized array)  */    $posts = get_posts(array(  	'post_type' => 'post',  	'meta_query' => array(  		array(  			'key' => 'custom_relationship', // name of custom field  			'value' => '"123"', // matches exaclty "123", not just 123. This prevents a match for "1234"  			'compare' => 'LIKE'  		)  	)  ));    if( $posts )  {  	//...  }

コード引用元:ACF { Relationship

ただし、LIKE検索は要するにキーワード検索ですので、ちょっと不便なことも起こりそうです。

このように複数の条件を使いたいという場合、本来カスタムフィールドの検索を行うmeta_queryで「LIKE」ではなく「IN」を指定し、配列で複数の値を渡すこともできるのですが、この様にシリアライズ化されてしまっている場合はLIKEしか使えませんので、ちょっと困りますね。一応、回避策を考えてみました。LIKE検索をORでつなぐという方法。

もし meta_query で ‘IN’, ‘NOT IN’, ‘BETWEEN’, or ‘NOT BETWEEN’ のいずれかを使った検索を使う予定があるときは、ACFの設定は慎重に行ったほうがいいと思います。でもまあ、気をつけていれば一応、問題ないのかなと思いますので、今後も気をつけてACFを使おうと思います。

Custom Field Parameters (Codex)

ACFのフィールドを使った検索についてツイートしていたら色々な意見をいただきました。

確かに、単に複数の投稿で何かしらの共通項を作りたい場合はタクソノミーのほうがいいと思います。また、WordPressのカスタムフィールドはそもそも検索に向いていないということで、その辺を理解した上で使う必要がありそうです。


Share this entry