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検索は要するにキーワード検索ですので、ちょっと不便なことも起こりそうです。
ACFプラグインで"Relation > 関連"で投稿(物件)とデザイナー(複数可)を紐付け。で投稿ページに紐付けたデザイナーが手掛けた別の投稿(物件)を表示したいだけなんだけどな。もうちょい考えんといかん。
— Sho Doi (@show_web) April 8, 2013
LIKEじゃなくてIN使いたいし、この場合だと検索条件増やしてるだけなのでvalueの数を制限しなくちゃいけない。ACFプラグインはいろいろ用意されてるから簡単な解決方法がありそうなんだけど見つからんなー。
— Sho Doi (@show_web) April 8, 2013
このように複数の条件を使いたいという場合、本来カスタムフィールドの検索を行うmeta_queryで「LIKE」ではなく「IN」を指定し、配列で複数の値を渡すこともできるのですが、この様にシリアライズ化されてしまっている場合はLIKEしか使えませんので、ちょっと困りますね。一応、回避策を考えてみました。LIKE検索をORでつなぐという方法。
もし meta_query で ‘IN’, ‘NOT IN’, ‘BETWEEN’, or ‘NOT BETWEEN’ のいずれかを使った検索を使う予定があるときは、ACFの設定は慎重に行ったほうがいいと思います。でもまあ、気をつけていれば一応、問題ないのかなと思いますので、今後も気をつけてACFを使おうと思います。
Custom Field Parameters (Codex)
ACFのフィールドを使った検索についてツイートしていたら色々な意見をいただきました。
@show_web @HissyNC @digitalcube @shinichiN まー、meta_valueはテキスト型でインデックスもかかってないので、meta_valueで検索することを前提に設計しちゃうとACFの仕様に関係なくデータが増えたら修羅場になりますね。
— Takayuki Miyauchi (@miya0001) April 8, 2013
@HissyNC @show_web そうそう、カスタムタクソノミーならインデックスきいてるのでいいですよ。
— Takayuki Miyauchi (@miya0001) April 8, 2013
@HissyNC そもそもカスタムフィールドで検索するのが間違いでは?postmeta データベースの設計が検索を想定していないっぽい。
— Fumito Mizuno (@ounziw) April 9, 2013
@HissyNC 検索でカスタムフィールドを使うなら、 advanced custom fields じゃないほうがいいですね。acf は管理画面の使い易さ重視なので。その辺の実装は案件に応じて選べば良いけど、そういう情報があまり無いのが問題かな。
— Fumito Mizuno (@ounziw) April 9, 2013
確かに、単に複数の投稿で何かしらの共通項を作りたい場合はタクソノミーのほうがいいと思います。また、WordPressのカスタムフィールドはそもそも検索に向いていないということで、その辺を理解した上で使う必要がありそうです。