pre_get_postsでは$query->is_main_query()を使う
カテゴリー一覧の件数だけを変えたつもりなのに、関連記事や管理画面の一覧まで変わった場合は、pre_get_postsの対象を絞れていない可能性があります。フックの中では、グローバル関数ではなく、渡された$query->is_main_query()を使ってメインクエリだけを選びます。
ただし、メインクエリは管理画面にもあります。公開ページの表示だけを変えたい場合は、まずis_admin()で管理画面リクエストを除外し、カテゴリーや検索などのページ条件も$queryで確認します。
変えたくない一覧まで変わったら対象を見直す
まず、なぜpre_get_postsでは変更対象を絞る必要があるのかを、カテゴリー一覧の件数を変える例で確認します。意図した一覧以外まで変わったときは、コードがどのクエリにも作用していないかを順に切り分けます。
たとえば、カテゴリー一覧を10件から6件へ変えたいとします。変更後に、サイドバーの新着記事まで6件になったり、管理画面の投稿一覧へ同じ条件が入ったりしたら、変更対象が広すぎます。
WordPressは、ブラウザで開いたページの内容を決めるメインクエリのほかに、テーマ、ブロック、ウィジェット、プラグインなどが追加のWP_Queryを実行することがあります。pre_get_postsはメインクエリだけでなく、これらの追加クエリに対しても実行されます。
メイン一覧だけを変えたい場合、$query->is_main_query()がfalseならそこで処理を終えます。サイドバーや関連記事の追加クエリはfalseになるため、その後のset()まで進まず、元の取得条件を保てます。
| 判定 | 分かること | 分からないこと |
|---|---|---|
| $query->is_main_query() | 渡されたクエリがメインか | 管理画面リクエストか、カテゴリーか、検索か |
| is_admin() | 管理画面リクエストか | メインか、利用者が管理者権限か |
| $query->is_category() | カテゴリーアーカイブか | メインか、管理画面か |
| $query->is_search() | 検索結果か | メインか、追加クエリか |
グローバル関数とメソッドは調べる対象が違う
グローバル関数is_main_query()は、呼び出すときに調べたいWP_Queryオブジェクトを指定する関数ではありません。現在のグローバル$wp_queryとメイン用の$wp_the_queryを比較するため、pre_get_postsのコールバックへ渡された$queryを直接調べる用途には使いません。
メソッド$query->is_main_query()は、そのWP_Queryオブジェクト自身がメイン用オブジェクトと同じかを判定します。フックが追加クエリのために発火した場合でも、渡された対象を正しく判定できます。
$query->is_main_query()は、「この$queryはメインクエリですか」と問い合わせる書き方です。->の左に調べたいクエリ、右に呼び出す処理を書きます。このようにオブジェクトに属する処理をメソッドと呼びます。
フックの中では、渡されてきたクエリ自身を調べます。is_main_query()だけでなく、$query->is_main_query()と書くのが大切です。| 書き方 | 調べる対象 | 主な使用場所 |
|---|---|---|
| is_main_query() | グローバルの現在クエリ | テンプレートなど、渡されたWP_Queryオブジェクトがない場所 |
| $query->is_main_query() | 変数$queryが指すクエリ | pre_get_postsなど、対象のWP_Queryが引数で渡されるフック |
WordPress公式リファレンスは、pre_get_posts内でグローバル関数を呼ぶと誤用通知を出し、渡されたオブジェクトのメソッドを使うよう案内しています。
グローバル関数では追加クエリを見分けられない
次のコードは、カテゴリー一覧を6件へ変えるつもりで書いた失敗例です。pre_get_postsへ渡された$queryではなく、グローバルクエリを判定しています。
管理画面とページ種別の条件もないため、この失敗例をそのまま実サイトへ追加しないでください。
function wptl_wrong_main_check( WP_Query $query ) { if ( ! is_main_query() ) { return; } $query->set( 'posts_per_page', 6 );}add_action( 'pre_get_posts', 'wptl_wrong_main_check' );追加クエリの処理中でも、グローバル$wp_queryがメインを指していれば、関数側はtrueになることがあります。そのまま渡された$queryを変更すると、本来除外したかった追加クエリへ設定が入ります。
まず直すのは、判定する1行です。フックへ渡された$queryのメソッドに変えると、追加クエリはfalseとなり、そこで処理を終えられます。
次の断片で、上の関数内のif文を置き換えます。functions.phpの関数外へ単独で貼るコードではありません。
if ( ! $query->is_main_query() ) { return;}このあとに管理画面リクエストを除外する条件と、カテゴリー一覧かどうかの条件を足します。完成形は次のセクションで確認できます。
管理画面を除外し、カテゴリー一覧だけを変える
次の例では、まずis_admin()がtrueになる管理画面リクエストを除外し、次にメインクエリ以外を除外します。残ったクエリがカテゴリーアーカイブのときだけ、表示件数を6件へ変更します。
子テーマのfunctions.phpなど、クエリが実行される前に読み込まれるPHPファイルへ、関数とadd_action()をまとめて1回だけ追加します。既存のPHP開始タグの内側へ記述し、先ほどの失敗例は残しません。記事本文や、取得が済んだ後のアーカイブテンプレートへ貼るコードではありません。
function wptl_change_main_category_query( WP_Query $query ) { if ( is_admin() || ! $query->is_main_query() ) { return; } if ( ! $query->is_category() ) { return; } $query->set( 'posts_per_page', 6 );}add_action( 'pre_get_posts', 'wptl_change_main_category_query' );早期returnで対象外を先に除くと、「どの条件で止まるか」を1つずつ確認できます。条件式を1行へ詰めても動きますが、調査中は役割ごとに分ける方がログを取りやすくなります。
完成例は本番と分けたWordPress環境で、カテゴリー一覧だけが6件になり、管理画面や関連記事は変わらないか試します。検証や公開に使うサーバーをこれから用意する場合は、XserverのPHP対応やバックアップ条件も確認できます。
対象は4段階の順で限定する
上から順に進めると、確認漏れを減らせます。
pre_get_postsの確認順
- 1管理画面を変えないならis_admin()で除外する
- 2メインだけを変えるなら$query->is_main_query()で追加クエリを除外する
- 3カテゴリー、検索、投稿一覧などページ種別を$queryのメソッドで限定する
- 4変更前のquery varを$query->get()で確認し、必要な値だけset()する
3番目のページ条件は、変えたい一覧に合わせて選びます。カテゴリー一覧ならis_category()、検索結果ならis_search()というように、目的と条件を対応させます。
| 目的 | ページ条件の例 | 変更する値の例 |
|---|---|---|
| カテゴリー一覧の件数を変える | $query->is_category() | posts_per_page |
| 検索結果を投稿だけにする | $query->is_search() | post_type |
| 投稿ページの一覧を変える | $query->is_home() | posts_per_page、category__not_in |
| newsアーカイブを日付順にする | $query->is_post_type_archive( 'news' ) | orderby、order |
画面条件も、可能な限りフックへ渡された$queryのメソッドを使います。どの値が入っているか不明な場合は、$query->get( ‘post_type’ )や$query->get( ‘posts_per_page’ )をローカルのログで確認します。
is_admin()は管理者ユーザーの判定ではない
この判定は意味を取り違えやすいため、先に次の注意点を押さえます。
is_admin()は、現在のリクエストがWordPressの管理画面用インターフェースかを判定します。ログイン中の利用者が管理者権限を持つかどうかは判定しません。管理画面にも投稿一覧などのメインクエリがあります。そのため$query->is_main_query()だけを条件にすると、公開ページだけを変えたい処理が管理一覧にも適用される可能性があります。公開ページだけを対象にする場合は、is_admin()を別に確認します。
| 知りたいこと | 使うもの |
|---|---|
| 管理画面リクエストか | is_admin() |
| メインクエリか | $query->is_main_query() |
| ユーザーに特定権限があるか | current_user_can() |
| カテゴリーアーカイブか | $query->is_category() |
メイン判定だけで終わらずページ条件も加える
管理画面を除外しても、単一投稿、固定ページ、検索、カテゴリー、日付アーカイブなどには、それぞれメインクエリがあります。ページ条件を書かずにpost_typeや表示件数を変えると、変えたくない公開ページにも影響します。
function wptl_limit_main_search_to_posts( WP_Query $query ) { if ( is_admin() || ! $query->is_main_query() ) { return; } if ( $query->is_search() ) { $query->set( 'post_type', 'post' ); }}add_action( 'pre_get_posts', 'wptl_limit_main_search_to_posts' );pre_get_postsは実際の取得前に発火するため、結果取得後でなければ成立しない条件分岐は使えません。公式資料ではis_front_page()がこの時点で期待どおり動かない例が示されています。固定フロントページでは$queryのquery varと「設定 → 表示設定」の内容をローカルで見比べてください。
この検索用コードもfunctions.phpへ1回登録します。管理画面と独自クエリを除いたうえで、検索結果だけを通常投稿に限定します。カテゴリー一覧の件数変更とは別の目的なので、必要な処理だけ採用してください。
追加クエリを変えるときも対象を1つに絞る
要件によっては、プラグインが作る一覧や、自分で追加した特定の一覧をpre_get_postsで変更することもあります。その場合、メインを除外するためにif ( $query->is_main_query() ) { return; }と書けますが、それだけではサイト内のすべての追加クエリが候補になります。
「メインではない」だけでは、関連記事も新着一覧も対象になります。変えたい追加一覧だけを見分ける目印も必要です。たとえば、一覧を作るときの取得条件に、その用途だけで使う名前を付けます。このようなクエリに渡す値をquery varと呼びます。自分でテンプレートに書ける一覧なら、フックで後から変更するより、new WP_Query( $args )の$argsを直接直す方が分かりやすいこともあります。
次の例では、フッターの新着一覧を作るときだけ、識別用のwptl_contextを渡します。
取得部分を子テーマのtemplate-parts/footer-news.phpに置き、クラシックテーマのfooter.phpからget_template_part( ‘template-parts/footer-news’ );で呼び出す想定です。新規のPHPファイルなら先頭に<?phpを置きます。既存のPHP内へ追加する場合は、開始タグを重ねません。呼び出す側の1行もPHPの内側へ記述します。
クラシックテーマのテンプレート(またはテンプレートパーツ)で、一覧を表示したい位置に置く例です。投稿本文やfunctions.phpへ、そのまま貼るコードではありません。
$footer_query = new WP_Query( [ 'post_type' => 'post', 'posts_per_page' => 5, 'wptl_context' => 'footer_news', ]);この断片は投稿を取得するだけで、一覧は描画しません。既存の描画ループより前へ置き、$footer_query->the_post()で表示する場合はループ後にwp_reset_postdata()で投稿データを戻します。単に3件表示したいだけなら、上のposts_per_pageを3へ直せば十分です。
フックで対象を識別する仕組みを試す場合は、次の関数と登録処理を先にfunctions.phpへ1回追加します。管理画面・メインクエリを除外し、wptl_contextが一致する追加クエリだけを5件から3件へ変更します。
function wptl_change_named_secondary_query( WP_Query $query ) { if ( is_admin() || $query->is_main_query() ) { return; } if ( 'footer_news' !== $query->get( 'wptl_context' ) ) { return; } $query->set( 'posts_per_page', 3 );}add_action( 'pre_get_posts', 'wptl_change_named_secondary_query' );独自query varは用途を識別するためのサイト側の約束です。第三者プラグインのクエリを変える場合は、そのプラグインが提供する専用フックや引数がないか先に確認します。
自分で作るフッター一覧なら、まずWP Query Builderで投稿タイプや取得件数を整理できます。フックを使うかどうかとは分けて、一覧に必要な条件を確認します。
追加する一覧の取得条件を整理する
投稿タイプや件数から$argsを作れます。この記事のメイン判定、管理画面の除外、識別用query varは生成結果とは別に実装します。
グローバル関数を使える場所もある
テンプレートで現在のグローバルクエリがメインかを確認したい場合は、引数なしのis_main_query()を使えます。ただし、通常のページテンプレートではページ種別や目的がすでに明確なことも多く、必要のない判定を増やす必要はありません。
| 場所 | 推奨する判定 |
|---|---|
| pre_get_postsのコールバック | $query->is_main_query() |
| WP_Queryを引数で受け取る別フック | 渡されたオブジェクトのis_main_query() |
| テンプレートで現在のグローバルクエリを確認 | is_main_query() |
| 独自WP_Queryの作成直後 | $custom_query->is_main_query()で役割確認はできるが、通常は独自と分かっている |
関数名だけを暗記するのではなく、「今どのWP_Queryオブジェクトを調べたいか」で関数とメソッドを選びます。
条件が効かないときは判定値を同じログへ出す
対象を限定したのに変更されない、または別の一覧まで変わる場合は、フック内で判定値とquery varを同じ行へ記録します。次の関数と登録処理を、ローカルのfunctions.phpへ一時的に追加してください。temporary-debug.phpというファイルを作るだけでは実行されません。
function wptl_log_pre_get_posts_target( WP_Query $query ) { error_log( wp_json_encode( [ 'admin' => is_admin(), 'main' => $query->is_main_query(), 'category' => $query->is_category(), 'search' => $query->is_search(), 'post_type' => $query->get( 'post_type' ), 'posts_per_page'=> $query->get( 'posts_per_page' ), ], JSON_UNESCAPED_UNICODE ) );}add_action( 'pre_get_posts', 'wptl_log_pre_get_posts_target', 999 );ローカルで対象URLを1回表示し、目的のクエリと追加クエリの行を比べます。確認後はログ処理を削除し、公開画面にデバッグ値を表示しないようにします。
WordPressのdebug.logへ出す場合は、ローカルのwp-config.phpでWP_DEBUGとWP_DEBUG_LOGを有効、WP_DEBUG_DISPLAYを無効にします。既存の定義があれば編集し、重複して追加しません。確認後は設定を元に戻し、URLや入力値が入る可能性のあるログは公開・共有しないでください。
追加クエリでもtrueになるのはなぜ?
違いが出るのは、追加クエリを処理しているときです。次の表では、グローバルの現在クエリがメインを指したまま、追加のWP_Queryも実行しています。WordPress 7.1/PHP 8.4.20のローカル環境で得た値を、列ごとに見比べてください。
| 確認項目 | メイン相当 | 追加WP_Query |
|---|---|---|
| $query->is_main_query() | true | false |
| is_main_query()関数 | true | true |
| is_admin() | false | false |
| フック内の関数呼び出し | 誤用通知あり | 誤用通知あり |
右の列では、グローバル関数はメイン側を見てtrue、渡された追加クエリのメソッドはfalseです。関数側のtrueを信じて処理を続けると、追加クエリまで変えてしまいます。誤用通知も、フック内でグローバル関数を使ったことを知らせています。
この比較はWordPressを読み込んだPHPのコマンドライン環境で行いました。管理画面からのリクエストではないため、表のis_admin()はどちらもfalseです。実サイトでは、対象の公開URLに加えて管理画面、検索、カテゴリー、追加した一覧をそれぞれ確認します。
is_main_query()でよくある間違い
実装や公開へ進む前に、見落としやすい項目をまとめて確認します。
条件が広がりすぎたときに見直す項目
- pre_get_posts内でグローバル関数is_main_query()を使っている
- $query->is_main_query()だけで公開ページも限定できたと思っている
- is_admin()を管理者権限の判定として使っている
- メイン判定だけでカテゴリーや検索などのページ条件を書いていない
- 追加クエリを対象にするためmainを除外し、ほかの追加クエリを限定していない
- 単一投稿のメインクエリをquery varだけで無理にアーカイブへ変えている
- is_front_page()など、フックの実行時点で使えない条件を前提にしている
- 誤用通知を非表示にし、関数とメソッドの取り違えを残している
既存の一覧を変えるか、別の一覧を追加するか迷う場合は、pre_get_postsとWP_Queryの違いを先に確認します。WP_Queryを書いたのに一覧が変わらない場合は、メインクエリとサブクエリの確認順から切り分けます。
is_main_query()とpre_get_postsの公式資料
関数とメソッドの違い、pre_get_posts内での注意、is_admin()が判定する範囲を確認したいときは、次の公式資料を参照します。
WordPress公式
確認に使った公式ドキュメント
3つの判定を分けてから値を変更する
対象の一覧が変わっただけでは確認は終わりません。変えたくない管理画面や関連記事が元のままかも確認し、調査用のログを外してから本番へ反映します。
本番へ反映する前の確認
- 渡された$queryのメソッドで判定し、誤用通知が出ていない
- 管理画面と対象外のページには変更が入らない
- 追加一覧を変える場合は、その一覧だけの目印で限定した
- 対象の一覧と、変更しない関連記事・管理画面を実際に確認した
- 調査用のログを外し、問題時に変更を戻せる
この記事の検証情報
検証環境
- WordPress
- 7.1.4
- PHP
- 8.3.36
- テーマ
- wpq-media + DDEV
- 対象
- カスタム投稿 / taxonomy / meta_query
更新履歴
- 2026年10月19日 初回公開
この記事を活用する
あとで見返す・共有する
お気に入りに保存できます。役に立ったポイントは、いいねや共有で教えてください。







