WordPress 4.1のmeta_queryはAND条件の組をORで入れ子にする
公開日: 執筆:佐藤
WordPress 4.1では、meta_queryの中へ別のmeta_queryを入れられます。二つの条件を満たす組が複数あり、どれか一組に一致する投稿を探すなら、外側をOR、各組の内側をANDにします。
条件を一列へ並べてrelationを一つだけ指定しても、AかつB、またはCかつDにはなりません。先に条件を括弧で書き、それと同じ階層を配列で表してください。
検索条件を配列より先に括弧で書く
たとえば、次の二組のどちらかに一致する投稿を探すとします。
(region = east AND service_type = repair)
OR
(region = west AND service_type = maintenance)
これは説明用の仮例です。各投稿では、regionとservice_typeへ一つずつ値を保存しているものとします。地域が東で業務種別が修理の投稿、または、地域が西で業務種別が保守の投稿を対象にします。
外側のORは二つの組を結びます。各組のANDは、地域と業務種別を結びます。この括弧を消すと、どの地域と業務種別を一組として扱うのか分からなくなります。
外側のORへ二つのAND条件を入れる
WordPress Coreのquery改善に関する説明は、WordPress 4.1のWP_Meta_Queryが入れ子のqueryを扱えることを、ORの中へ二つのANDを置く例で示しています。
WP_Queryでは、仮例の条件を次のように書けます。
$query = new WP_Query(
array(
'post_type' => 'post',
'meta_query' => array(
'relation' => 'OR',
array(
'relation' => 'AND',
array(
'key' => 'region',
'value' => 'east',
'compare' => '=',
),
array(
'key' => 'service_type',
'value' => 'repair',
'compare' => '=',
),
),
array(
'relation' => 'AND',
array(
'key' => 'region',
'value' => 'west',
'compare' => '=',
),
array(
'key' => 'service_type',
'value' => 'maintenance',
'compare' => '=',
),
),
),
)
);
relationは、それと同じ階層にある条件をどう結ぶか指定します。外側のrelationは二つの配列をORで結び、内側のrelationは二つのmeta条件をANDで結びます。
keyはpost metaのkey、valueは比較する値です。この例では完全一致を求めるため、compareへ=を明記しています。実際のkeyと値は、保存されているpost metaと一致させてください。
平らなORとANDでは条件の組を表せない
四つの条件を平らに並べ、relationをORにすると、regionがeastであるだけの投稿も、service_typeがmaintenanceであるだけの投稿も対象になります。一組の両方を満たすという条件が消えます。
反対に、四つを平らに並べてANDにすると、一つの投稿へregionがeastとwestの両方を求めることになります。regionへ一つの値だけを保存する仮例では成立しません。
| 配列の形 | 意味 | 仮例での結果 |
|---|---|---|
四条件を平らなORで結ぶ |
どれか一条件に一致 | 対象が広すぎる |
四条件を平らなANDで結ぶ |
全条件に一致 | 成立しない |
二条件のANDを外側のORで結ぶ |
どちらか一組に一致 | 求める組合せになる |
SQLの断片を直接つないで括弧を補う前に、meta_queryの階層で条件を表します。WordPressが各階層をたどり、まとまりごとに括弧を付けた検索条件を組み立てます。
画面全体の投稿一覧を変える処理とは分ける
上の例は、必要な場所で新しいWP_Queryを作る場合です。テーマが表示している主な投稿一覧の条件を変える場合まで、新しいqueryへ置き換えるとは限りません。
WordPressが用意した投稿一覧を変更するなら、どの画面のmain queryを対象にするか判定し、pre_get_postsで引数を変える方法を検討します。custom queryを作る目的と、main queryを変更する目的を分けてください。
また、WordPress 4.1より前の環境へ、入れ子にしたmeta_queryが同じように解釈されるとは考えないでください。運用中のWordPress版を確認してから使います。
繰り返し検索する分類はtaxonomyも検討する
入れ子のmeta_queryが書けることと、検索条件をすべてpost metaへ保存すべきことは別です。地域や業務種別のように、投稿を繰り返し絞り込み、管理画面でも分類として選ばせたい情報なら、taxonomyの方が目的に合う場合があります。
どちらを選ぶかは、次の順で決めます。
- 情報を一件の投稿に付随する値として扱うか、複数投稿をまとめる分類として扱うか
- 一覧や検索で、その値をどの程度繰り返し使うか
- 値の追加、表記変更、統合を誰が管理するか
- 既存dataを変更する費用と、今後の運用時間をどう配分するか
外部へ実装を依頼する場合は、配列だけでなく、括弧で書いた検索条件、post metaのkey、値の正本、WordPress版を渡します。納品後に条件を変える担当者が配列の階層を追えるよう、目的をcodeの近くへコメントとして残してください。
最初の一手は、必要な検索条件を(A AND B) OR (C AND D)の形で一行に書くことです。次に、その括弧と同じ階層のmeta_queryを作り、該当する投稿と該当しない投稿を一件ずつ用意して結果を確認します。
関連記事

