【WordPressカスタムフィールド検索】meta_queryで、シリアライズ値が入ったフィールドを持つ記事をヒットさせるには?

      2021/02/23   3310文字

【WordPressカスタムフィールド検索】meta_queryで、シリアライズ値が入ったフィールドを持つ記事をヒットさせるには

今回は、ちょっと需要があるかもしれない『WordPressカスタムフィールド検索』について取り上げます。
ネットを検索すると『シリアライズ値(a:〇〇:{i:△△;s:◇◇:”〇〇”}みたいな形式)のフィールドが絡むと、検索がめんどくさい』という意見が見受けられますが、この形式のフィールドは絞り込み検索に使えるのでしょうか?さっそく検証していきましょう。

シリアライズ値が入ったフィールドってどんな形式に?(例:_wp_attachment_metadeta)

シリアライズ値が入ったフィールドってどんな形式
このサイトでもちょくちょく取り上げていますが、カスタムフィールドで複数項目が1つのフィールドに入っている場合、このようなシリアライズされた形式になっています。
a:〇〇:{i:△△;s:◇◇:”〇〇”}のような形のフィールド(最初のaは、配列arrayのaと要素数・s:〇〇は文字列型(string)とバイト数)で、一部では検索時にめんどくさいともいわれています。

しかし、このフィールドを取れたりすると、WPカスタムフィールド検索を実装するとき自由度があがるので、『ちょっとやってみるか』となったわけです。

なお、実験には、いつものように・・・

管理人が作成した、WP著作権フリー曲サイトを使用します(曲作りより開発がメインになってるとか言わないでね笑)。
このサイトでは『ビットレート(1秒間に送受信できるデータ量)』が、128kbps・320kbpsなど複数混在しており、探せたらラクかなと思ったからです。


データベース上では、SQLを使って、わりとサックリヒットさせることができました。この形式のフィールドをWordPressのフロント側から検索してもヒットさせることができると、自由度が一気に上がります。
なお、過去記事(リンク)でもちょっと書いたように、『このフィールドにencoder_options”;s:6:”CBR320″というような記述がある』ので、『CBR128』で、記事をヒットさせてみます

下準備~サブループ検索用ファイルと、テスト用記事を用意し、シリアライズフィールドをコピペ(postを取りたいため)

サブループ検索用ファイルを作って、wp-blog-header.phpを読み込み、フォームを用意する


今回の『シリアライズされたフィールドをもつ記事を取ってみよう』では、通常のメインループではなく、カスタムフィールドを使ったサブループを使うので、『メインループを取るようになっているsearch.php(テーマ組み込み)』のほかに、サブループ検索用ファイル(〇〇search.phpみたいな別名)を用意しました。

そのままではWPの記事を拾わないので『require($_SERVER[‘DOCUMENT_ROOT’] .’/wp-blog-header.php’);』を読み込んで、検索対応できるようにします。
フォームは『input type=”radio” name=”bitrate” value=”128″』のようにし、この値が変数$bitrateに格納されます。最初は一覧を表示させておいて、この変数$bitrate値が入っているときは、別クエリが動くように条件分岐します

postを取りたいため、フィールドをテスト記事にコピペ(_wp_attachment_metadetaは、添付ファイルのメタデータ)

ここで投稿タイプの問題が出てきます。管理人的には『絞り込んで記事(投稿タイプpost)が出るようにしたかった』のですが、『_wp_attachment_metadeta』は、投稿タイプpostのメタデータではなく、添付ファイル (attachment)のメタデータです。そのため、『投稿タイプpostを取るクエリでは出ない』となります。
(*投稿タイプattachmentを取る方法もありますが、長くなるので省きます)


そこでテスト用記事を制作。目的の『CBR128が、フィールド内にあるオーディオデータ』を貼り付けて・・


シリアライズ化してある、_wp_attachment_metadetaの内容を、テストで作ったフィールドにコピペしました。テスト環境はこれでok。あとは、クエリを調整して、このフィールドをもつ記事がヒットするようにします。

シリアライズ値が入ったカスタムフィールドを持つ記事を、検索でヒットさせるコード

コード(はしょっています)

*注:テスト用につき、条件は『CBR128』のものしか書いていません(192などは未実装)。

ポイント~meta_compareの値が『IN』や『=』では、シリアライズされたフィールドを取れない

meta_compareの値が『IN』や『=』では、シリアライズされたフィールドを取れない
この手のフィールドの厄介なところは、よく使われる書き方だと出てこないところ。例えば、いろんな値があるからといって、『配列のいずれか含む』という『’value’=> array(‘CBR128′,’128000′),’compare’ => ‘in’』という書き方ではでません。

meta_compareの値が『IN』や『=』では、シリアライズされたフィールドを取れない
もちろん、値を持っているとはいえ、完全に一致するわけでもないので『’value’=> ‘CBR128′,’compare’ => ‘=’』(一致)でも出ません。

実行結果~正規表現(’compare’ => ‘REGEXP’)だと取れる

正規表現('compare' => ‘REGEXP’)だと取れる” width=”480″ height=”327″ class=”aligncenter size-full wp-image-7690″ /><br />
上記のgithub gistコードに書いていた、<strong>『’compare’ => ‘REGEXP’』</strong>でやってみた結果です。うまくシリアライズされたフィールド内に『CBR128』の値がある記事をヒットさせることができました。
</p>
<h3><span id=実行結果~〇〇を含む(’compare’ => ‘like’)でも取れる

〇〇を含む('compare' => ‘like’)でも取れる” width=”480″ height=”310″ class=”aligncenter size-full wp-image-7691″ /><br />
〇〇を含む(’compare’ => ‘like’)で行ってみたところ、こちらでも該当の記事を取ることができました。『クエリ実行速度が遅い』といわれるlike・REGEXP検索ですが、単体だとスピードはそんなに気になりません。<br />
ただし、この手のフィールドがいっぱいあったり『’relation’ => ‘OR’』でつないだりすると、<strong>がっつりスピードが落ちる</strong>ので、なるべくこの手のフィールドが少ないように設計できると良いかもです(体験談)。
</p>
<h2><span id=参考リンク(WordPress codex)

あとがき・まとめ

  • WPカスタムフィールドでは、複数項目のフィールドはシリアライズ化されて入っている
  • meta_compareの値が『IN』や『=』では、シリアライズされたフィールドを取れない
  • meta_compareの値が『REGEXP』や『like』だとヒットさせることができる
  • ただし、条件によっては実行速度が一気に落ちるので、見越した設計ができるとベター

まとめるとこんなところでしょうか。今回はかなりシンプルな感じなので、割とサックリ実装できましたが、実際の運用では他の条件もかかわってきます(組み合わせによっては難しい)。シリアライズされたフィールドの取り方も押さえつつ、負荷の少ないクエリで取れるように設計できると、使うユーザーもストレスなく利用できると思うので、いろいろと検討できればと思います。
(うまく検索システム作って、管理人のサイトにも実装します)


【カテゴリ】 - PHP・データベースetc
【タグ】 - , ,

  関連記事

【WordPressで覚えよう】PHP「->」(オブジェクト演算子/アロー演算子)・「=>」(ダブルアロー演算子)の違い
WordPressユーザーが覚えると便利な条件分岐~投稿記事・固定ページ指定して表示/非表示
【PHP etc.プログラム学習サイトコードコピペ】全角引用符・バッククオートが入ってて動かない件に注意
YouTube Data APIを使って、PHPで『タイトル・動画id・サムネイル画像』などを取得してみる(Search: listリソース)
【WPカスタマイズ】プラグイン不使用、テーマに関連記事表示機能を実装しPV・滞在時間を上げる
【別に止めなくてOK】WordPressサイトなどに、アメブロ・fc2など無料ブログの更新情報を表示して連携する方法
侍エンジニア塾ブログにあったPHPコードをシンプルに書いてみる(foreachで配列キーや値取得・continueで空要素スキップ)
PHP・shuffleやarrayを使った、画像ランダム表示方法~メインビジュアルやバナー・テキストにも利用可能
WordPress記事一覧ページの『本文からの抜粋』を表示する関数と、その文字数の調整方法をチェックする
【WordPress更新情報表示】php/wp組み込みファンクション(fetch_feed)で取得と、プラグインで表示どちらが良い?
【WordPress】記事文字数のカウント方法(コア機能・プラグイン)チェックと、フロントへの出力について
WordPress一覧表示で、特定のカテゴリ/投稿を表示しないようにするには?→category_not_in・post_not_inで