WordPressにおける絞り込み検索の実装では「Advanced Custom Fields(ACF)× Search & Filter Pro」の組み合わせが個人的におすすめですが、Pro版は年間$20かかるので、独自にコードを書いて実装することがあります。普段からKOTORIさんのブログを参考にするのですが、毎回よく分からなくなるので備忘録として残しておきます。
Contents
ポイント
- Advanced Custom Field の出力は特殊なので Custom Field Template(CFT)を使うべし
- カテゴリ検索以外は meta_query に追加するべし
- 検索フォーム側の
value=""
の言葉で検索できる- ただしlabelや値(priceやtrueなど)ではうまく検索できず
- 検索フォーム側はクエリを連結して投げるだけで、絞り込み処理は検索結果一覧(search.phpやindex.php)に書く
wp_reset_query();
を忘れないように
実装する前に確認しておいた方がいいこと
コードを書く前に以下の点を確認しておくのがおすすめです。
- どの場所に(サイドバー、トップ、検索結果、固定ページ、投稿記事)
- どんなタイプの検索項目を
- それぞれ何の選択肢で
- 範囲指定の場合、単位(刻み幅)はいくつで
- 何項目実装するのか
- モバイルでの表示位置は?
- ヘッダーなどにある標準の検索フォームは非表示にするか
- AMPページでも動かすのか
- そもそもテーマに sidebar.php がちゃんと存在しているか
また独自実装だと、原則最初に決めた項目・順番・選択肢は後から(管理画面からは)変更不可ですが、クライアント側で初めに項目や選択肢が決まってない・ぼんやりしていることが多く、要件を詰めたりと実装以外の工数がかかることが多いです。このあたりをしっかり踏まえて見積もりをしましょう。(そう考えると素直にSearch & Filter Proをおすすめするのが、双方にとって負担が楽で一番いいかなぁ..)
コード
キーワード検索、チェックボックス、ドロップダウン、価格帯で絞る場合のサンプルコードです。KOTORIブログさんのコードほぼそのままですが、if文の追加や改行などを私なりにアレンジしてます。
注意点
なぜACFでなくCFTを使うのか
ACFで作成したカスタムフィールドはDBへの登録が特殊なようでうまく絞り込みできません(何をkeyにしていいか分からなかった)。その特殊性ゆえに get_field('price');
のように書くだけで、カスタムフィールドの値を取得できたりするのですが、Search & Filter Proと組み合わせない限り、CFTを使用した方が確実です。
ただし今回は検索フォーム側に選択肢を直に書いていますが、ACFの独自関数などを使えば、ACFで増やした選択肢が検索フォームにも自動反映されるとかもできそうではありました。
カスタムフィールドの検索は基本 meta_query に追加すべし
カテゴリ検索は tax_query
を使いますが、カスタムフィールド はチェックボックスも範囲選択もドロップダウン(<select></select>
)も、すべて meta_query
に追加でいけます。
標準のキーワード検索フォームの機能を損なわないように注意
検索フォームのキーワード検索を利用すれば、URLに hoge.com/?s="りんご"&low_price="300円"
のようにクエリがつきますが、WordPress標準の検索フォームで検索すると /?s="りんご"
しかクエリがつきません。なので、検索結果一覧側である search.php や index.php で、仮に(標準の検索フォームを使われて)クエリにpriceなどが付いてない時もきちんとキーワード検索できるようにしないといけません。
$low = $_GET['low'];
$high = $_GET['high'];
// どちらか価格帯のクエリが存在している時だけ metaquerysp[] に追加する
if($low || $high) {
if(!($low == 0 && $high == 9999999)) {
$metaquerysp[] = array(
'key'=>'my_price',
'value'=>array( $low, $high ),
'compare'=>'BETWEEN',
'type'=>'NUMERIC',
);
}
}
また価格帯で絞る時など、初期値が「下限なし」〜「上限なし」のようになっていると、その下限なし/上限なしのvalueがクエリとして渡されてしまうので、その場合も metaquerysp[]
に値が追加されないようにしないといけません。
$low = $_GET['low'];<br>$high = $_GET['high'];
if($low || $high) {
// ただし値が初期値の場合はスルー
if(!($low == 0 && $high == 9999999)) {
$metaquerysp[] = array(
'key'=>'my_price',
'value'=>array( $low, $high ),
'compare'=>'BETWEEN',
'type'=>'NUMERIC',
);
}
}