今ある一覧を変えるならpre_get_posts、別の一覧を足すならWP_Query
カテゴリー、検索結果、投稿一覧、投稿タイプアーカイブなど、WordPressがURLに合わせて用意したメインクエリの条件を変えるならpre_get_postsを使います。new WP_Query()は別の取得結果を作るため、元の一覧は自動では変わりません。
記事下の関連記事、サイドバーの新着、固定ページ内の商品一覧など、現在のページへ別の一覧を追加するならWP_Queryを使います。最初に「変える」か「追加する」かを決めてください。
変えたい一覧に合わせて方法を選ぶ
迷ったら、まず「どの一覧を変えたいか」から考えてみましょう。よくある目的ごとに分けると、選びやすくなります。
| やりたいこと | 選ぶ方法 | 理由 |
|---|---|---|
| カテゴリー一覧を1ページ6件に変える | pre_get_posts | WordPressが作るメインクエリのposts_per_pageを実行前に変える |
| 検索結果から固定ページを除外する | pre_get_posts | 検索のメインクエリへpost_typeを設定する |
| 記事本文の下に関連記事を3件足す | WP_Query | 現在の記事とは別の投稿取得とループを作る |
| 固定ページの途中に新着記事を5件足す | WP_QueryまたはQuery Loop | 固定ページ1件のメインクエリは残し、別の一覧を追加する |
| 古いquery_posts()を置き換える | 元の目的で分ける | メイン変更ならpre_get_posts、追加する一覧ならWP_Query |
一覧を変更する処理と、新しく追加する処理の違い
WP_Queryは投稿の取得を扱うクラスです。new WP_Query( $args )で作ったオブジェクトが、取得した投稿やループの進み具合を持ちます。
pre_get_postsは投稿を取得する関数ではなく、取得前に処理を挟むためのアクションフックです。add_action()で自分の関数を登録すると、WordPressがそのタイミングで関数を呼び出します。登録した関数の中で、これから実行されるクエリの条件を変更します。
| 比較項目 | pre_get_posts | new WP_Query() |
|---|---|---|
| 主な役割 | これから実行するクエリの条件を変更する | 別の取得条件を持つクエリを作って実行する |
| 対象 | メイン・追加・管理画面のクエリにも動くので、条件で絞る | コードで作成したWP_Queryオブジェクト |
| 値の指定 | $query->set()で必要な項目だけ変更する | $argsを渡して投稿タイプ・件数・絞り込みなどを指定する |
| 結果の表示 | 条件を変更したクエリを、その一覧のループが使う | 専用変数に入れたオブジェクトのメソッドでループする |
| 登録・実行する場所 | functions.phpなど、対象クエリの実行前に読み込まれる場所 | テンプレートパーツなど、追加する一覧を表示する位置 |
| 投稿データのリセット | 取得条件の変更だけなら不要 | 独自ループでthe_post()を使った後に戻す |
pre_get_postsには、変更対象のWP_Queryが参照で渡されます。コールバック内で新しいWP_Queryを返すのではなく、渡された$queryへset()で値を入れます。
pre_get_postsはSQL実行前、WP_Queryはその場で追加実行する
WordPressはURLを解析してメイン用のWP_Queryを準備し、クエリ変数とページ種別の判定を設定します。その後、SQLを組み立てて取得する前にpre_get_postsが発火します。ここで表示件数や投稿タイプを変更すると、その条件でメインクエリが実行されます。
テンプレートが選ばれた後にnew WP_Query( $args )を書く場合、メインクエリはすでに実行済みです。独自クエリはその位置で別途実行されるため、元のメイン結果やページ判定を置き換えません。
一覧ページが表示されるまで
- 1URLからページ種別とメインクエリ変数を準備する
- 2pre_get_postsで対象を限定し、必要な値だけ変更する
- 3変更後の条件でメインクエリを実行する
- 4WordPressがテンプレートを選ぶ
- 5テンプレートが各ループを表示する。new WP_Queryがあれば、その位置で別の取得処理を実行する
カテゴリーのメイン一覧を6件へ変える基本例
次のコードは、管理画面リクエストを除外し、カテゴリーアーカイブのメインクエリだけを対象にします。
子テーマのfunctions.phpなどへ、関数とadd_action()をまとめて1回だけ追加します。既存のPHP開始タグの内側へ記述し、クエリの取得後に読み込まれるアーカイブテンプレートへは置きません。wptl_はサンプル用接頭辞です。別名にする場合は、関数名と登録する名前をそろえてください。
子テーマのfunctions.phpまたは機能プラグインに置く例です。対象画面と実行条件を確認し、検証環境で試してから本番へ反映してください。
function wptl_change_category_archive( WP_Query $query ) { if ( is_admin() || ! $query->is_main_query() ) { return; } if ( $query->is_category() ) { $query->set( 'posts_per_page', 6 ); }}add_action( 'pre_get_posts', 'wptl_change_category_archive' );is_admin()で管理画面のリクエストを除外し、$query->is_main_query()でメインクエリだけに限定し、$query->is_category()でカテゴリーアーカイブだけに絞っています。3つの対象確認を通った後に値を変更します。
フックには、今から処理するクエリが$queryとして渡されます。$query->is_main_query()は「このクエリはメインですか」と調べる書き方です。->の左にあるクエリの処理を、右側の名前で呼び出しています。
グローバル関数is_main_query()は別のグローバル変数$wp_queryを調べるため、フック内では使いません。判定対象の違いはis_main_query()で対象クエリを限定する方法で確認できます。
このフックは本番と分けたWordPress環境で、カテゴリーの件数だけが変わり、管理画面や別の一覧へ影響しないか確認します。検証や公開に使うサーバーをこれから用意する場合は、XserverのPHP対応やバックアップ条件も確認できます。
記事の下などへ関連記事を足すWP_Queryの基本例
一覧を追加するときは、用途が分かる専用変数へWP_Queryオブジェクトを入れます。関連記事枠の基本形として、まず現在の記事以外の通常投稿を最大3件表示します。カテゴリーなどで関連性を絞る条件は、この例には含めていません。
次のコードを子テーマのtemplate-parts/related-posts.phpへ保存し、クラシックテーマのsingle.phpからget_template_part( ‘template-parts/related-posts’ );で呼び出します。新規PHPファイルなら先頭に<?phpを置き、既存のPHP内へ追加するときは開始タグを重ねません。呼び出す側の1行もPHPの内側へ記述します。
single.phpのメインループでthe_post()を呼んだ後、記事本文の下など、一覧を表示したい位置から呼び出してください。パーツを保存するだけでは表示されません。既存の関連記事枠がある場合は二重表示を避けます。
クラシックテーマのテンプレート(またはテンプレートパーツ)で、一覧を表示したい位置に置く例です。投稿本文やfunctions.phpへ、そのまま貼るコードではありません。
$related_query = new WP_Query( [ 'post_type' => 'post', 'post_status' => 'publish', 'posts_per_page' => 3, 'post__not_in' => [ get_queried_object_id() ], 'ignore_sticky_posts' => true, ]); if ( $related_query->have_posts() ) { echo '<ul>'; while ( $related_query->have_posts() ) { $related_query->the_post(); printf( '<li><a href="%1$s">%2$s</a></li>', esc_url( get_permalink() ), esc_html( get_the_title() ) ); } echo '</ul>';} wp_reset_postdata();この処理は、もともと表示されている一覧を変えません。追加したWP_Queryのthe_post()によって、テンプレートタグが参照する投稿データが一時的に変わるため、最後にwp_reset_postdata()で戻します。
戻す位置と理由はwp_reset_postdata()が必要な理由で確認できます。関連性の条件も付けたい場合は、同じカテゴリーから関連記事を取得する方法へ進んでください。
関連記事枠などの一覧を追加するときは、WP Query Builderで投稿タイプや件数を整理できます。3件の基本形を作り、この記事の表示ループと合わせてローカルで試してみてください。
投稿一覧の取得条件を作る
投稿タイプ・件数・並び順などから$argsを作れます。既存の一覧を変更する場合は、必要なパラメーターと値を選び、対象を限定したpre_get_postsで設定します。
pre_get_postsは対象を3段階で限定する
pre_get_postsはメインクエリ専用フックではありません。テンプレート内で作る追加のWP_Queryにも動きます。条件なしで件数や投稿タイプを変えると、サイドバー、関連記事、管理画面など、変えたくない一覧にも影響します。
対象を限定する順番
- 1公開ページだけを変えるならis_admin()で管理画面リクエストを除外する
- 2メインだけかを$query->is_main_query()で確認する
- 3カテゴリー、検索、投稿タイプアーカイブなど対象画面を$queryのメソッドで確認する
- 4必要なquery varだけを$query->set()で変更する
3番目の画面条件は、目的に応じて変えます。カテゴリー一覧の件数ならis_category()、検索結果の投稿タイプならis_search()というように、変える一覧を次の表で選びます。
| 対象画面 | フック内で使う候補 | 変更例 |
|---|---|---|
| カテゴリーアーカイブ | $query->is_category() | posts_per_page、orderby |
| 検索結果 | $query->is_search() | post_type、posts_per_page |
| 投稿一覧 | $query->is_home() | 除外カテゴリー、表示件数 |
| 投稿タイプアーカイブ | $query->is_post_type_archive( 'news' ) | 表示件数、並び順 |
| 管理画面 | is_admin()で通常は除外 | 管理一覧を変える別要件なら専用条件を設計 |
管理画面を変えること自体が禁止なのではありません。公開ページだけを変えるつもりならis_admin()で管理画面リクエストを除外し、管理一覧を変える要件なら投稿タイプや画面を別途限定します。
pre_get_postsでは使える条件分岐のタイミングに注意する
pre_get_postsは実際の投稿取得より前に動くため、クエリ結果に依存する一部の条件分岐はまだ使えません。公式資料ではis_front_page()はこの時点で期待どおり動かず、is_home()は使える例として説明されています。
フック内では、渡された$queryのメソッドと$query->get()を使って対象を判断します。$query->get()は、post_typeやposts_per_pageなど、そのクエリに入っている取得条件を読み取るメソッドです。固定フロントページ、投稿ページ、独自のURL変数などは、サイトの「設定 → 表示設定」と実際の取得条件(query var)をローカルで確かめます。
ページ送りはメイン変更の方が既存URLとつながりやすい
カテゴリーや検索などのメインクエリでは、pagedというクエリ変数(query var)に現在のページ番号が入ります。pre_get_postsでposts_per_pageなどを変更すれば、同じメインクエリのfound_postsとmax_num_pagesが変更後の条件で計算されます。ページリンクは、テンプレートがこのメインクエリの値を使って表示します。
アーカイブテンプレート内で同じ一覧をnew WP_Query()し直す場合は、pagedを独自クエリへ渡し、ページリンクにも独自クエリのmax_num_pagesを使う必要があります。元のメインクエリのページ数と混ぜると、2ページ目が同じ、空ページ、404などの原因になります。
offsetはどちらのクエリでもページネーションを壊す可能性があります。単純に先頭数件を飛ばしたいだけでも、ページごとのoffsetと総件数の補正が必要かを確認してください。
先頭の投稿を飛ばすケースはWP_Queryのoffsetとページネーションの注意点で確認できます。paged・ページ数・リンクをつないだ完成例は表示件数とページネーションの設定方法を参照してください。固定フロントページではpageも関係するため、通常のアーカイブと分けて確認します。
pre_get_postsでは通常リセット不要、追加WP_Queryでは必要
pre_get_postsはメインクエリの取得条件を変えますが、新しいループを追加しません。テンプレートは変更後のメインループを通常どおり進めるため、この変更だけを理由にwp_reset_postdata()を追加する必要はありません。
独自のWP_Queryでthe_post()を使ったら、追加ループの直後でwp_reset_postdata()を実行します。違いは、表示に使う投稿データを切り替えたかどうかです。取得条件だけの変更と、追加の投稿を表示するループを分けて考えると、戻す場所も判断しやすくなります。
WP Query Builderで取得条件を整理する
WP Query Builderは、独自のWP_Queryへ渡す$argsを組み立てる場所です。追加する一覧なら生成した$argsを独自クエリで使えます。メイン一覧をpre_get_postsで変える場合は、必要な値だけを$query->set()へ移します。
たとえばWP Query Builderでposts_per_page、orderby、orderを確認した後、pre_get_postsのフック登録、is_admin()、$query->is_main_query()、ページ種別の条件はWordPress側で追加します。生成コードを貼るだけでメインクエリを変更するのではなく、必要なパラメーターとその設定値を選んで使います。
操作手順はWP Query Builderの使い方で説明しています。生成コードはローカルのWordPressへ組み込んで動作を確かめます。一覧を追加するのか、メインクエリを変更するのかに合わせて、この記事の実装例と比べてみてください。
メインの5件だけを6件へ変えるとどうなる?
元のカテゴリー一覧も追加一覧も5件ずつ取得する場合、掲載フックで変わるのはメイン側だけです。次の表は、WordPress 7.1/PHP 8.4.20のローカル環境で、公開済みの通常投稿を使って得た結果です。メインが6件になり、追加一覧の5件はそのままになっている点を見てください。
| 確認項目 | 結果 |
|---|---|
| pre_get_postsの実行時点 | 今回の新規クエリでは、フック内のrequestが空だった |
| メイン判定 | $query->is_main_query()はメイン相当でtrue、追加クエリでfalse |
| メイン相当のposts_per_page | 5から6へ変更され、取得件数6 |
| 追加WP_Queryのposts_per_page | 5のままで、取得件数5 |
| is_admin() | 管理画面ではないコマンドライン環境ではfalse |
追加クエリでもフックは動きましたが、メインだけを選ぶ条件があるので、そちらの5件は変わりませんでした。自分のサイトで試すときも、変えたい一覧だけでなく、検索や管理画面などが元のままか見ておくと安心です。
一覧を変える方法を決めるときのよくある間違い
うまく動かないときは、次の項目を上から見直します。
先に見直したい7項目
- アーカイブを変えたいのに、テンプレートで同じ条件のnew WP_Query()を作る
- 記事下へ別の一覧を足したいのに、条件なしでpre_get_postsを使う
- pre_get_posts内でグローバル関数is_main_query()を使う
- is_admin()だけで止め、メインクエリと対象画面を限定しない
- 単一ページのメインクエリを投稿一覧へ無理に変形する
- メインクエリのページ数と独自WP_Queryのmax_num_pagesを混ぜる
- 独自ループ後にwp_reset_postdata()を書かない
うまくいかないときは、ローカルで独自クエリを一時的に外し、元の一覧に戻るか見てみましょう。pre_get_postsを使っているなら、管理画面の除外、メイン判定、ページ種別、設定値の順にたどると、どこで対象が広がったのかを探しやすくなります。
pre_get_postsとWP_Queryの公式資料
pre_get_postsが動く時点と対象の絞り方、独自WP_Queryとの使い分け、追加ループ後の戻し方は、次の公式資料で確認できます。
WordPress公式
確認に使った公式ドキュメント
既存の一覧と追加する一覧を分けて実装する
変更後は、目的の一覧だけでなく、元のまま残す一覧も確認します。取得件数が合っていても、ページ送りや後に続く記事タイトルがずれていれば、まだ本番へ反映せず原因を切り分けてください。
本番へ反映する前の確認
- 目的の一覧だけが変わり、管理画面や他の一覧は元のままである
- フックは取得前に登録され、渡された$queryのメソッドで対象を限定している
- 追加パーツは表示したい位置から呼び出され、二重表示がない
- ページ送りと、追加ループ後の投稿データが正しい
- ローカルで確認を終え、問題時に変更を戻せる
この記事の検証情報
検証環境
- WordPress
- 7.1.4
- PHP
- 8.3.36
- テーマ
- wpq-media + DDEV
- 対象
- カスタム投稿 / taxonomy / meta_query
更新履歴
- 2026年10月23日 初回公開
この記事を活用する
あとで見返す・共有する
お気に入りに保存できます。役に立ったポイントは、いいねや共有で教えてください。






