本文へ移動

トラブル解決

WP_Queryを書いたのに一覧ページが変わらない原因
|メインクエリとサブクエリを確認

new WP_Query()は、その場に別の取得結果を作ります。カテゴリーや検索結果などWordPressが用意した一覧そのものを自動で置き換える処理ではありません。投稿は取得できているのに画面が変わらないときは、取得条件より先に、表示したい一覧を担当するループとクエリを確認します。

Huddly Huddly 投稿日: 2026年10月21日 読了目安: 10分

new WP_Query()を書いただけでは、元の一覧は変わらない

カテゴリー、検索結果、投稿一覧、投稿タイプアーカイブなどには、WordPressがURLに合わせて準備したメインクエリがあります。new WP_Query()は別のクエリを追加しますが、メインクエリの条件や結果は置き換えません。

既存の一覧を変えたいなら、対象を限定したpre_get_postsでメインクエリを実行前に変更します。別の一覧を追加したいなら、独自のWP_Queryを専用変数でループします。まず、表示したい一覧が、どのループとクエリに対応するか確認してください。

最初に「変えたい一覧」と「表示しているループ」を確認する

同じテンプレートの中にメインクエリと独自クエリがある場合、それぞれの結果は別に保持されます。一覧が変わらない症状では、取得コードより先に表示コードを調べると、原因を絞れることがあります。

確認すること変わらない例次の対応
何を変えたいかカテゴリーURLに元から出る投稿一覧メインクエリの変更を検討
どのループを表示しているか独自クエリを作った後もhave_posts()を使用専用変数のメソッドを使うか、メインを変更
どのテンプレートが使われているかarchive.phpを編集したがcategory.phpが優先テンプレート階層を確認
表示が更新されたか正しいコードでも古いHTMLが残るページ、サーバー、CDNのキャッシュを分けて確認
new WP_Query()の直後にhave_posts()を使っているだけなら、独自クエリではなくメインクエリを読んでいる可能性があります。

原因は取得結果と表示対象が別だから

WordPressのグローバル関数have_posts()とthe_post()は、現在のグローバル変数$wp_queryを使います。通常のメインループでは、この変数がメインクエリを指します。一方、$list_query = new WP_Query( $args )で取得した結果を表示するときは、$list_query->have_posts()と$list_query->the_post()を使います。

$list_query->have_posts()は、「$list_queryに表示する投稿が残っていますか」と問い合わせる書き方です。->の左に取得結果を持つクエリ、右に呼び出す処理を書きます。このようにオブジェクトに属する処理をメソッドと呼びます。

グローバル関数のhave_posts()と、オブジェクトのメソッドである$list_query->have_posts()は、調べる対象が違います。関数とメソッドを区別し、表示したい取得結果を持つオブジェクトのメソッドを選びます。

グローバルクエリは、現在の$wp_queryが指すクエリです。独自クエリを別の変数に作っても、その結果へ自動で切り替わるわけではありません。
処理対象となるクエリ代表的な用途
グローバル関数のループグローバル変数$wp_queryが指すクエリ。通常はメインクエリカテゴリー、検索結果、投稿一覧など、URLに対応するメインループ
$list_queryのループ$list_queryが指すWP_Queryオブジェクト記事下の関連記事、サイドバー、固定ページ内へ追加する投稿一覧
pre_get_posts内のset()フックへ渡された、取得処理の前のクエリ対象を絞り、既存の一覧の件数・投稿タイプ・並び順を変更

ここで先に決めるのは、「URLに応じてWordPressが取得する一覧を変更したい」のか、「別の一覧を追加したい」のかです。既存の一覧を変える場合はメインクエリ、別の一覧を足す場合は専用変数のループを使います。

pre_get_postsは、投稿を取得する前に処理を挟むためのアクションフックです。add_action()で自分の関数を登録すると、そのタイミングで実行されます。後の完成例では、この仕組みで取得前のメインクエリを変更します。

よくある失敗は独自WP_Queryを作ってメインループを表示すること

次の失敗例では$archive_queryに6件の条件を指定しています。しかし、表示部分はグローバル関数のhave_posts()とthe_post()なので、通常は元のメインクエリの結果が表示されます。クラシックテーマのarchive.phpなどで、メインループが始まる前に取得コードを追加した場面です。

クラシックテーマのテンプレート(またはテンプレートパーツ)で、一覧を表示したい位置に置く例です。投稿本文やfunctions.phpへ、そのまま貼るコードではありません。

PHParchive.php独自クエリを作ったのにメインループを表示する失敗例
$archive_query = new WP_Query(   [      'post_type'      => 'post',      'post_status'    => 'publish',      'posts_per_page' => 6,      'ignore_sticky_posts' => true,   ]); if ( have_posts() ) {   while ( have_posts() ) {      the_post();      the_title();   }}

この状態でデバッグすると、$archive_query->post_countには6件入っているのに、画面は「設定 → 表示設定」の件数のまま、ということがあります。取得できていても、表示するループが別のクエリを読んでいれば画面は変わりません。

別の一覧を表示する目的なら、取得部分は残し、上のif文から後ろを次のコードで置き換えます。ループも$archive_queryのメソッドを使うので、同じオブジェクトの取得結果を表示できます。修正前のメインループと重ねて出力しないようにしてください。

クラシックテーマのテンプレート(またはテンプレートパーツ)で、一覧を表示したい位置に置く例です。投稿本文やfunctions.phpへ、そのまま貼るコードではありません。

PHParchive.php取得した独自クエリを専用変数で表示する
if ( $archive_query->have_posts() ) {   while ( $archive_query->have_posts() ) {      $archive_query->the_post();      the_title();   }} wp_reset_postdata();

ただし、カテゴリーURLに元からある一覧そのものを変えたい場合は、この修正で別の一覧を足すのではなく、次のpre_get_postsを使います。

修正したループは、本番と分けたWordPress環境で、取得した投稿と表示が一致するか試します。検証や公開に使うサーバーをこれから用意する場合は、XserverのPHP対応やバックアップ条件も確認できます。

既存の一覧の変更か、別の一覧の追加かで直し方を分ける

選択肢の違いと、最初に見る点を次の表で整理します。

目的適した方法確認点
カテゴリーや検索結果そのものを変えるpre_get_posts公開側、メイン、対象画面を限定
記事下へ関連記事を追加するnew WP_Query専用変数でループし、最後に投稿データを戻す
固定ページの途中に投稿一覧を追加するnew WP_QueryまたはQuery Loop固定ページ自体のメインクエリを残す
一覧の見出しやHTMLだけを変える使われているテンプレートを編集クエリを追加する必要はない
ブロックテーマの一覧条件を変えるQuery Loopブロックまたはサイトエディターの設定を確認PHPテンプレートだけを前提にしない

アーカイブページに一覧を1つだけ出したいのに、同じ投稿を独自クエリで取り直すと、余分な取得処理が発生し、ページ送りも別に管理することになります。既存のメインクエリの条件を変更して、その結果を通常のループで表示すれば、URL・ページ判定・ページ数を同じクエリで扱えます。

既存のカテゴリー一覧を変えるならpre_get_postsを使う

次の例は、公開側のカテゴリーページにあるメインクエリだけを1ページ6件へ変更します。テンプレート側は通常のメインループをそのまま使えます。

子テーマのfunctions.phpなど、クエリより前に読み込まれるPHPファイルへ、関数と登録処理をまとめて1回追加します。既存のPHP開始タグの内側へ記述します。wptl_はこのサイトのサンプル用接頭辞で、WordPress必須の名前ではありません。変更する場合は、関数名とadd_action()の第2引数を同じ名前にそろえてください。

PHPfunctions.phpカテゴリーのメイン一覧を1ページ6件へ変更する
function wptl_change_category_list( 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_list' );

pre_get_postsはメイン専用ではなく、追加クエリにも発火します。そのためis_admin()、$query->is_main_query()、対象画面の3段階で絞ってから値を変更します。フック内のメイン判定では、グローバル関数ではなく渡された$queryのメソッドを使います。

別の一覧を足すなら独自クエリの変数でループする

現在のページに新着一覧を追加する目的なら、独自クエリの結果をその専用変数で表示します。

次のコードを子テーマのtemplate-parts/latest-posts.phpへ保存し、クラシックテーマの表示したい位置からget_template_part( ‘template-parts/latest-posts’ );で呼び出します。新規のPHPファイルなら先頭に<?phpを置き、既存のPHP内へ追加する場合は開始タグを重ねません。呼び出す側の1行もPHPの内側へ記述します。

個別記事内で試す場合は、single.phpなどのメインループのthe_post()より後から呼び出し、既存の記事タイトルや本文とは分けて表示します。ファイルを保存するだけでなく、表示したい位置から呼び出すところまでが設置です。

クラシックテーマのテンプレート(またはテンプレートパーツ)で、一覧を表示したい位置に置く例です。投稿本文やfunctions.phpへ、そのまま貼るコードではありません。

PHPtemplate-parts/latest-posts.php現在のページへ新着6件を追加する
$latest_query = new WP_Query(   [      'post_type'      => 'post',      'post_status'    => 'publish',      'posts_per_page' => 6,      'ignore_sticky_posts' => true,   ]); if ( $latest_query->have_posts() ) {   echo '<ul>';    while ( $latest_query->have_posts() ) {      $latest_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();

追加する一覧で使うthe_post()は、テンプレートタグが参照する投稿データを一時的に変更します。その後に表示するタイトルや本文を、ブラウザで開いているページの内容へ戻すため、追加ループの後でwp_reset_postdata()を実行します。

別の一覧を追加するときの取得条件は、WP Query Builderでも組み立てられます。表示件数6などの条件を入力し、生成コードをローカルのWordPressで試して、この記事の専用変数のループと比べてみてください。

追加する一覧の取得条件を作る

投稿タイプ・件数・絞り込みから$argsを作れます。取得結果の表示とループ後のリセットは、組み込むテンプレート側で確認します。

一覧が変わらないときは6段階で切り分ける

変更範囲を広げる前に、次の順番で原因を絞ります。

原因を確認する順番

  1. 1
    変更したいのが既存の一覧か追加する一覧かを決める
  2. 2
    画面のループがhave_posts()か、専用変数のhave_posts()か確認する
  3. 3
    WP_Query直後のpost_countとposts_per_pageを確認する
  4. 4
    実際に読み込まれたテンプレートを確認する
  5. 5
    pre_get_postsなら管理画面、メイン、対象画面の条件を確認する
  6. 6
    最後にページ、サーバー、CDNのキャッシュを消して再確認する
post_countが0なら取得条件を、1件以上あるのに画面だけ変わらないならループとテンプレートを先に調べます。

0件の場合は、投稿タイプ、公開状態、分類、カスタムフィールド条件などを確認します。取得できた投稿がある場合は、条件を増やす前に、その結果をどのコードが表示しているか追いかけます。

次のログは、上の新着一覧の$latest_query = new WP_Query( … );の直後、ループより前へ一時的に置きます。別ファイルを作るだけでは実行されず、変数が使えない場所へ置いても取得結果は確認できません。

PHPtemporary-debug.php独自クエリの条件と取得件数を一時的に確認する
error_log(   wp_json_encode(      [         'posts_per_page' => $latest_query->get( 'posts_per_page' ),         'post_count'     => $latest_query->post_count,         'max_num_pages'  => $latest_query->max_num_pages,      ],      JSON_UNESCAPED_UNICODE   ));

確認用ログは原因を特定したら削除します。公開画面にデバッグ値を表示せず、ローカル検証環境のログを使ってください。

debug.logへ出す場合は、ローカルのwp-config.phpでWP_DEBUGとWP_DEBUG_LOGを有効、WP_DEBUG_DISPLAYを無効にします。既存の定義を重複させず、検証後は元へ戻します。ログには内部の値が含まれるため、公開・共有しないでください。

編集したファイルが実際のテンプレートとは限らない

クラシックテーマでは、WordPressがテンプレート階層に従って、現在のURLに最も具体的なファイルを選びます。たとえばカテゴリーではcategory-slug.php、category-id.php、category.php、archive.php、index.phpの順に候補が変わります。archive.phpを編集しても、より優先されるcategory.phpが使われていれば、その変更は表示されません。

症状確認候補
カテゴリーだけ変わらないcategory.phpやcategory-slug.phpが優先されていないか
投稿タイプアーカイブだけ変わらないarchive-posttype.phpがないか
検索結果だけ変わらないsearch.phpが使われているか
ホームの投稿一覧だけ変わらないhome.phpとfront-page.phpを混同していないか
子テーマで変わらない親テーマと子テーマの同名ファイル、現在有効なテーマを確認

ファイル名の綴りや投稿タイプのslugが違う場合も、想定した候補が使われず、次の候補が選ばれます。推測だけでコードを移動する前に、次のログでWordPressが選んだファイルを確認できます。

次の関数と登録処理を、ローカルの子テーマのfunctions.phpへ一時的に1回追加し、対象URLを開きます。template_includeはテンプレートを読み込む直前のフィルターです。add_filter()で登録した関数はパスを記録し、受け取った値をそのまま返します。

PHPfunctions.php選ばれたテンプレートを変えずにローカルログへ記録する
function wptl_log_selected_template( $template ) {   error_log( 'Selected template: ' . $template );   return $template;}add_filter( 'template_include', 'wptl_log_selected_template', 999 );

ログで親テーマ・子テーマのどちらのパスかと、ファイル名を確認します。選ばれたパスを返さないと描画を壊すため、return $template;は省略しません。確認後はこの関数と登録処理を削除し、内部パスが含まれるログは公開しないでください。ブロックテーマではPHPの読み込み用ファイルが記録される場合があり、編集対象のブロックテンプレート名まで分かるわけではありません。

ブロックテーマではQuery Loopの設定も確認する

サイトエディターで作られたテンプレートでは、投稿一覧がQuery Loopブロックで表示されていることがあります。この場合、クラシックテーマのPHPファイルに追加した独自ループが、画面の一覧を担当していない可能性があります。

まず「外観 → エディター」で対象のアーカイブや検索テンプレートを開き、投稿テンプレートを含むQuery Loopがあるか確認します。現在のテンプレートからクエリーを継承する設定ならメインクエリを使い、独自条件ならブロック側の設定を使います。テーマ方式を確認してからPHP側の変更範囲を決めてください。

独自クエリへ置き換えるとページ送りも別管理になる

独自クエリを正しく表示できても、アーカイブのページ送りが元のメインクエリを参照していると、ページ数や現在ページが合いません。独自一覧には現在のpagedを渡し、ページリンクにはその独自クエリのmax_num_pagesを使う必要があります。

既存の一覧をpre_get_postsで変更する場合は、変更後の条件で同じメインクエリの総件数とページ数が計算されます。カテゴリーや検索結果の一覧そのものを変えたいだけなら、ページ送りを作り直さずに済むことも、メインクエリを変更する理由です。

ページ送りまで確認する場合は、表示件数とページ番号の渡し方を次の記事で確認できます。

キャッシュはクエリとテンプレートを確認した後に切り分ける

コードと表示対象が正しくても、ページキャッシュ、サーバーキャッシュ、CDN、ブラウザーキャッシュに古いHTMLが残ることがあります。ただし、最初からキャッシュだけを疑うと、独自クエリとメインループの取り違えを見落とします。

キャッシュ確認の順番

  1. 1
    ログや一時的な目印で新しいPHPが実行されたか確認する
  2. 2
    WordPressのページキャッシュを削除する
  3. 3
    サーバー側キャッシュがあれば対象URLを削除する
  4. 4
    CDNを使っていれば対象URLをパージする
  5. 5
    プライベートウィンドウまたはキャッシュ無効で再表示する

ブラウザーだけを更新したい場合は、使っているOSとブラウザーに合う操作を試します。これはブラウザーに残ったファイルを読み直す操作で、WordPress、サーバー、CDNのキャッシュ削除とは別です。

環境ブラウザー側の確認方法
WindowsのChrome・Edge・FirefoxCtrl + Shift + Rでキャッシュを無視して再読み込み
macOSのChrome・Edge・FirefoxCommand + Shift + Rでキャッシュを無視して再読み込み
Safariなどでキー操作が分からない場合新しいプライベートウィンドウで同じURLを開いて比較

ショートカットはChrome、Edge、Firefoxの公式案内で確認できます。プライベートウィンドウはサーバーやCDNのキャッシュを消す操作ではなく、ログイン状態などの条件も変わるため、表示が違うだけで原因を断定しません。

本番で直接試すのではなく、ローカルまたはステージングで原因を再現してから変更します。キャッシュ削除は対象URLを優先し、サイト全体への影響を抑えてください。

WP Query Builderで取得条件を組み立てて比較する

WP Query Builderでは、post_type、posts_per_page、並び順などの条件からPHPコードを生成できます。表示件数に6を入力し、生成されたposts_per_pageと、実際のテーマの取得条件を比べてみてください。生成コードをローカルのWordPressへ組み込んだ後、投稿が期待どおり表示されるか確認します。

WP Query Builder自体が実サイトの投稿を取得したり、表示中の一覧を置き換えたりするわけではありません。生成コードで投稿を取得できても既存のアーカイブが変わらない場合は、パラメーターの追加よりも、メインクエリへの適用方法・ループ変数・テンプレートを確認します。既存の一覧を変える場合は、必要な値を対象限定済みのpre_get_postsで設定します。

操作方法はWP Query Builderのチュートリアルで説明しています。生成した独自クエリをそのままアーカイブへ足す前に、既存の一覧の変更か追加する一覧かを決めます。

6件取得できても5件しか表示されない例

ここまでの違いを件数で見てみましょう。元のメイン一覧が5件で、追加クエリには掲載コードと同じ6件を指定した場合です。次の表は、WordPress 7.1/PHP 8.4.20のローカル環境で、公開済み投稿を使って得た結果です。

確認項目結果
メイン相当の表示件数5件
独自クエリの取得件数6件
失敗例の表示元のメイン相当の5件
専用変数へ直した表示独自クエリの6件
メイン相当の投稿ID独自クエリの実行前後で同一
メイン判定メイン相当はtrue、独自クエリはfalse

失敗例は元の5件、専用変数を使ったループは取得した6件を表示しています。取得件数の指定を増やしても、メイン側の5件と投稿IDは変わりません。この比較はWordPressを読み込んだコマンドラインで行ったものです。実サイトでは、対象URL・使用テンプレート・テーマ方式・キャッシュ構成も確認してください。

一覧が変わらないときによくある誤り

実装や公開へ進む前に、見落としやすい項目をまとめて確認します。

一覧が変わらないときに見直す項目

  • 独自WP_Queryを作ったあとも、グローバル関数のhave_posts()で表示している
  • カテゴリー一覧を変えたいのに、同じ一覧をテンプレートでもう一度取得している
  • functions.phpへnew WP_Query()を移せばメインになると思っている
  • pre_get_postsで管理画面、メイン、対象画面を限定していない
  • archive.phpを編集したが、実際には別のテンプレートが使われている
  • ブロックテーマのQuery Loopを確認せず、PHPテンプレートだけを変更している
  • 独自クエリのページ数とメインクエリのページリンクを混ぜている
  • 投稿0件の問題と、取得済み結果を表示していない問題を混同している
  • コードの実行を確認する前にキャッシュだけを繰り返し削除している

投稿自体が取得できない場合は、WP_Queryで投稿が表示されない原因と確認チェックリストで条件を確認します。取得できているのに既存の一覧が変わらない場合は、この記事のループ、メイン変更、テンプレートの順を使います。

pre_get_postsとテンプレート階層の公式資料

既存の一覧を変えるpre_get_posts、別の一覧を作るWP_Query、現在のURLで選ばれるテンプレートとループ後の戻し方は、次の公式資料で確認できます。

WordPress公式

確認に使った公式ドキュメント

取得条件を変える前に、一覧を表示するループを確認する

原因が見つかったら、一度に変更範囲を広げず、その箇所を直して同じURLで確認します。目的の一覧だけが変わり、関連記事や管理画面、後続ページに影響がないことまで確かめてから本番へ反映します。

修正後、本番へ反映する前の確認

  • 取得した投稿と画面に表示するクエリが一致している
  • 変更しない一覧や管理画面は元のままになっている
  • 実際に使われるテンプレートまたはQuery Loopで確認した
  • 2ページ目・最終ページでも表示とページ送りが一致する
  • 調査用コードを外し、問題時に変更を戻せる
WP Query BuilderBuilderで条件を組み直す条件を選び、WP_Queryのコードを画面で作れます。Builderでクエリを作る

この記事を書いた人

Huddly

Web制作 / フロントエンドエンジニア

WordPressとフロントエンド実装で迷いやすい点を、公式情報と検証結果を分けながら、初学者にも追いやすい順序で整理しています。

この記事の検証情報

検証環境

WordPress
7.1.4
PHP
8.3.36
テーマ
wpq-media + DDEV
対象
カスタム投稿 / taxonomy / meta_query

更新履歴

  • 2026年10月21日 初回公開

この記事を活用する

あとで見返す・共有する

お気に入りに保存できます。役に立ったポイントは、いいねや共有で教えてください。

任意のご支援 役に立ったときだけ、活動を応援できます OFUSEはサイト・記事制作に使います。支援の有無で、読める内容や使える機能は変わりません。