「両方」ならAND、「どちらか」ならOR
tax_queryのrelationは、複数の条件グループをどうつなぐかを決める指定です。relation => ‘AND’ は「すべての条件を満たす投稿」、relation => ‘OR’ は「どれか1つでも条件を満たす投稿」を返します。
relationはtax_queryの中に条件が2つ以上あるときに意味を持ちます。この記事では、同じ2条件をANDとORで比べ、operatorやinclude_childrenとの違いも整理します。
まず「両方」か「どちらか」を日本語で決める
1条件の配列から確認したい場合はtax_queryの基本構造へ戻ります。カテゴリーだけ結果が合わない場合は、relationを増やす前にカテゴリー絞り込みが効かない原因を確認してください。
relationは複数の分類条件を「全部必要」と見るか、「どれかでよい」と見るかを指定します。
| relation | 意味 | 返る投稿のイメージ |
|---|---|---|
| AND | すべての条件を満たす | 条件が増えるほど結果は絞られやすい |
| OR | どれか1つでも条件を満たす | 条件が増えるほど結果は広がりやすい |
ANDはすべての条件を満たす投稿を返す
次は「お知らせカテゴリー(ID2)、かつ検証用タグ(ID7)」の例です。結果の違いを追いやすいように、比較対象を次の5投稿に限定します。投稿IDとタームIDは別の数字で、どちらもサイト固有です。
| 投稿ID | カテゴリー | 検証用タグ(ID7) |
|---|---|---|
| 10 | お知らせ(ID2) | あり |
| 11 | イベント案内(ID3) | あり |
| 12 | 制作ノート(ID4) | あり |
| 26 | お知らせ(ID2) | なし |
| 82 | 別のお知らせ(ID12) | なし |
クラシック子テーマのtemplate-parts/tax-comparison.phpへ保存し、表示したいテンプレートのメインループ内でthe_post()の後にget_template_part( ‘template-parts/tax-comparison’ );を呼びます。投稿本文やfunctions.phpの直下に貼るコードではありません。確認後は呼び出しと確認用ファイルを撤去します。
現在のWP Query Builder実画面では、詳細モードから「post / publish / 6」「post__in: 26,12,11,10,82」「orderby: post__in」、Tax Queryへ「category / term_id / 2 / include_children=false」と「post_tag / term_id / 7」を入力し、relationをAND、ignore_sticky_postsをtrue、自動最適化をオフにしました。そこで生成された次の$argsは編集せず使用しています。
クラシックテーマのテンプレート(またはテンプレートパーツ)で、一覧を表示したい位置に置く例です。投稿本文やfunctions.phpへ、そのまま貼るコードではありません。
<?php$args = array( 'post_type' => 'post', 'post_status' => 'publish', 'posts_per_page' => 6, 'orderby' => 'post__in', 'post__in' => array( 26, 12, 11, 10, 82 ), 'tax_query' => array( 'relation' => 'AND', array( 'taxonomy' => 'category', 'field' => 'term_id', 'operator' => 'IN', 'include_children' => false, 'terms' => 2 ), array( 'taxonomy' => 'post_tag', 'field' => 'term_id', 'operator' => 'IN', 'terms' => 7 ) ), 'ignore_sticky_posts' => true); $query = new WP_Query( $args ); if ( $query->have_posts() ) { echo '<ul>'; while ( $query->have_posts() ) { $query->the_post(); printf( '<li><a href="%s">%s</a>(ID: %d)</li>', esc_url( get_permalink() ), esc_html( get_the_title() ), get_the_ID() ); } echo '</ul>';} else { echo '<p>条件に一致する投稿はありませんでした。</p>';} wp_reset_postdata();Builderが生成したのは$argsまでです。続くWP_Query、表示ループ、0件時の文、投稿IDの表示、エスケープ、wp_reset_postdata()は用途に合わせて手動で追加しています。orderby => ‘post__in’により、条件に合った投稿は比較用のID列の順で表示します。
relationは各条件の中ではなく、2つの条件を包むtax_query直下に置きます。カテゴリーはinclude_children => falseとして、指定したターム自体の付与を見ます。
post__inは比較対象を固定するための指定です。全投稿から絞り込むなら行ごと削除し、空配列を「対象なし」の意味では使わないでください。
比較対象5投稿のうち、お知らせカテゴリーと検証用タグの両方が付いているのはID10です。
分類条件を切り替える作業は、本番と分けた環境で行います。サーバー上に試す場所を用意する場合は、XserverのPHP対応やバックアップ条件も確認できます。
ORはどれかの条件を満たす投稿を返す
同じ5投稿・同じ2条件で、relationだけをORへ変えます。最初のコードの$args定義直後、$query = new WP_Query( $args );より前へ次の1行を置いてください。取得・表示・リセットの部分は変えません。
引数や処理の一部分だけを示した例です。このまま単独で貼らず、テンプレート内のWP_Queryとループへ組み込んでください。
$args['tax_query']['relation'] = 'OR';結果はID26・12・11・10の4件です。両方に属するID10も、1件として含まれます。「お知らせの中でも検証用タグ付きだけ」ならAND、「お知らせも検証用タグ付きもまとめる」ならORです。

カテゴリーだけのID26、タグだけのID12・11、両方のID10が表示されます。両方ないID82は含まれません。
| 条件 | 表示される投稿ID | 読み取り方 |
|---|---|---|
| カテゴリー2だけ | 26・10 | 条件Aの対象 |
| タグ7だけ | 12・11・10 | 条件Bの対象 |
| A AND B | 10 | 両方の対象に共通する投稿 |
| A OR B | 26・12・11・10 | どちらかの対象に含まれる投稿 |
relationのANDとoperatorのANDは別物
relation => ‘AND’は条件グループ同士、operator => ‘AND’は1つの条件内にある複数termsの判定です。include_childrenは階層タクソノミーで子タームを含めるかを決めます。
| 指定 | 置く場所 | 何を決めるか |
|---|---|---|
| relation | tax_queryまたは入れ子グループの直下 | 複数の条件配列をAND / ORでつなぐ |
| operator | 各条件配列の内側 | 1条件内でtermsをどう判定するか決める |
| include_children | 階層taxonomyの条件内 | 子タームを検索範囲へ含めるか決める |
たとえば、2つのタクソノミー条件をどちらも満たしたいなら、外側のrelationをANDにします。1つのtaxonomy内で複数termsの扱いを変えたい場合は、条件内のoperatorを確認します。
既存コードは、外側のrelation、各条件のoperator、include_childrenの順に読むと整理しやすくなります。
次は「お知らせ(ID2)とイベント案内(ID3)の両カテゴリーが付いた投稿」を探す差分です。最初の$args定義後、new WP_Queryの前に置きます。ORの差分とは同時に貼らず、1例ずつ比べてください。
引数や処理の一部分だけを示した例です。このまま単独で貼らず、テンプレート内のWP_Queryとループへ組み込んでください。
$args['tax_query'] = [ [ 'taxonomy' => 'category', 'field' => 'term_id', 'terms' => [ 2, 3 ], 'operator' => 'AND', 'include_children' => false, ],];比較対象5投稿には両カテゴリーが付いた投稿がないため、結果は0件です。operatorだけをINへ変えると、どちらかのカテゴリーが付いたID26・11・10の3件になります。relationをORにしても、この1条件の中のoperator => ‘AND’がINへ変わるわけではありません。
relationとoperatorの役割が分かったら、WP Query Builderで同じ2条件を組み立てられます。生成したtax_queryを最初の$argsへ渡し、対象の投稿IDが一致するか比べます。
AND・ORの取得条件を組み立てる
taxonomy、field、terms、relationから$argsを作れます。比較対象のpost__inや表示ループ、入れ子のグループは、この記事の例と合わせて確認してください。
複雑な条件はネストで表現する
入れ子にすると「お知らせカテゴリー、または(検証用タグかつイベント案内カテゴリー)」も表せます。最初の$args定義後、new WP_Queryの前に次の差分を置き、同じ表示ループへ渡します。
引数や処理の一部分だけを示した例です。このまま単独で貼らず、テンプレート内のWP_Queryとループへ組み込んでください。
$args['tax_query'] = [ 'relation' => 'OR', [ 'taxonomy' => 'category', 'field' => 'term_id', 'terms' => [ 2 ], 'include_children' => false, ], [ 'relation' => 'AND', [ 'taxonomy' => 'post_tag', 'field' => 'term_id', 'terms' => [ 7 ], ], [ 'taxonomy' => 'category', 'field' => 'term_id', 'terms' => [ 3 ], 'include_children' => false, ], ],];お知らせのID26・10に、タグとイベント案内の両方が付いたID11が加わり、結果はID26・11・10の3件です。タグだけのID12は内側のANDに合わないため外れます。
結果が合わないときに確認する順番
結果が合わない時はrelationだけでなく、taxonomy、field、terms、投稿へのターム付与を確認します。slugとterm ID、登録名と表示名の取り違えにも注意してください。
確認の順番
- 1tax_queryを1条件だけにして結果が返るか見る
- 2taxonomy名が登録名と一致しているか確認する
- 3fieldがslug / term_id / nameのどれか確認する
- 4termsに実在する値を入れているか確認する
- 5最後にrelationをAND / ORで切り替えて件数の変化を見る
この順番で、条件Aだけ、条件Bだけ、AND、ORの4通りを比べます。条件AやBだけでも0件なら、relationではなくtaxonomy、field、terms、投稿へのターム付与を見直します。空の条件配列を動的に作っていないかも確認してください。
WP Query Builderでは、カテゴリーやタグなどの条件を画面で選び、生成される$argsと条件の意味を日本語で確認できます。ANDとORの位置が分かりにくいときは、まず2条件だけを設定して、画面の説明と生成コードを見比べてください。
tax_queryのrelationとネストの公式資料
指定方法とネスト例はWP_Query、条件の検証やSQL組み立てはWP_Tax_Queryの公式資料で確認できます。
公式リンク
公式ドキュメント
最後に確認したいこと
- relationは複数のtax_query条件をつなぐ指定だと理解している
- ANDはすべて満たす、ORはどれかを満たすと説明できる
- relationとoperatorのANDを混同していない
- 結果が合わないときは1条件ずつ減らして確認できる
- 複雑な条件は先に日本語で書き出してからコード化できる
この記事の検証情報
検証環境
- WordPress
- 7.1.4
- PHP
- 8.3.36
- テーマ
- wpq-media + DDEV
- 対象
- カスタム投稿 / taxonomy / meta_query
更新履歴
- 2026年9月25日 初回公開
この記事を活用する
あとで見返す・共有する
お気に入りに保存できます。役に立ったポイントは、いいねや共有で教えてください。



