本文へ移動

WP_Queryトラブルシュート

WP_Queryの表示件数が合わない原因
|posts_per_pageの確認方法

posts_per_pageを5にしたのに、画面には4件や6件出ていませんか。まずWP_Queryが何件取得したかをpost_countで確認し、実際に画面へ出した件数と比べて原因を探します。

Huddly Huddly 投稿日: 2026年8月27日 更新日: 2026年8月27日 読了目安: 7分

取得した件数と画面に出した件数を分けて確認する

posts_per_pageは、WP_Queryが1ページで取得する件数の指定です。まず3件や5件を指定し、post_countで実際の取得件数を確認します。post_countは、今回posts配列へ入った投稿数です。

指定値と違えば絞り込み条件を、post_countは合っているのに画面へ出た記事数が違えば、別ループやcontinueなどの表示処理を確認します。

多い・少ない・1ページ目だけ違う症状を分ける

ページごとの件数だけがずれる場合はページネーションの確認順を先に見ると原因を絞れます。全件取得の指定が混ざっている場合は、posts_per_page=-1になっていないかも合わせて確認してください。

「指定より多い」「少ない」「1ページ目だけ違う」「ページ送りでずれる」のどれかで、最初に見る場所が変わります。

症状まず疑う原因本文で確認する場所
指定件数より多く見える別ループ、ループ外出力、テンプレートパーツの複数呼び出し取得件数と表示件数を分ける節
指定件数より少ない絞り込み条件、公開状態、ループ内のcontinue絞り込み条件を1つずつ外す節
1ページ目だけ内容・順序・件数が違うホームの先頭固定表示固定表示の投稿を確認する節
アーカイブや検索だけ件数が違うposts_per_archive_page、pre_get_postsメインクエリの変更を確認する節
ページ送りで投稿が欠ける・重なるoffsetとpagedの併用、ページ番号の取得ミスoffsetとpagedを確認する節

ここでいう「画面に出した件数」は、記事カードや一覧の行として実際に表示した数です。WP_Queryが5件取得しても、テンプレート内で一部を表示しなければ画面は4件になります。反対に、別ループや固定出力を足せば6件に見えることがあります。

最初に確認する順番

最初にposts_per_pageへ3を指定し、WP_Queryが本当に3件取得したかを確認します。次に、画面へ出した記事カードや一覧の行を数えます。2つの数が同じなら取得条件を、違うなら表示処理を調べます。

原因を切り分ける6ステップ

  1. 1
    posts_per_pageへ3などの小さい値を指定する
  2. 2
    対象WP_Queryのpost_countと投稿IDを確認する
  3. 3
    実際に画面へ出した記事カードや一覧の行を数える
  4. 4
    post_countと画面の表示件数を比べる
  5. 5
    post_countが違うなら絞り込み条件を1つずつ外す
  6. 6
    画面だけ違うなら別ループ、continue、テンプレートの重複を確認する

まずposts_per_pageを3や5へ変えてみると、指定した数だけ取得・表示できているかを目で確認しやすくなります。

まずは最小例で件数を確認する

次のコードは、通常の投稿を3件だけ取得する最小例です。まずはこの形で、画面に3件だけ出るかを確認します。カテゴリーやカスタムフィールドの条件は、最初の切り分けでは外しておきます。

原因を切り分けるための一時的な確認コードです。ローカルなどの検証環境だけで使い、確認後は削除してください。

PHPtemplate-parts/latest-posts.php表示件数の切り分けに使う最小のWP_Query例
$args = [   'post_type'      => 'post',   'post_status'    => 'publish',   'posts_per_page' => 3,]; $test_query      = new WP_Query( $args );$displayed_count = 0; error_log( 'post_count: ' . $test_query->post_count );error_log( 'post_ids: ' . implode( ',', wp_list_pluck( $test_query->posts, 'ID' ) ) ); if ( $test_query->have_posts() ) {   echo '<ul>';   while ( $test_query->have_posts() ) {      $test_query->the_post();      echo '<li><a href="' . esc_url( get_permalink() ) . '">';      echo esc_html( get_the_title() );      echo '</a></li>';      $displayed_count++;   }   echo '</ul>';} error_log( 'displayed_count: ' . $displayed_count ); wp_reset_postdata();

このコードのポイントは、post_countで取得件数、post_idsで取得した投稿ID、displayed_countで画面へ出した件数を分けて記録することです。displayed_countは、記事カードや一覧の行を出力した直後に増やします。3つの値はローカル環境のデバッグログで確認し、確認後は一時的なログ出力を外してください。

post_countが3なら、WP_Queryは指定どおり3件取得しています。displayed_countだけが3でなければ、取得条件ではなく、ループ内の表示条件や別の出力を確認します。post_count自体が3でなければ、post_typepost_status、カテゴリーやカスタムフィールドなど、指定した絞り込み条件が想定どおりかを見直します。

また、WP_Querythe_post()を使った後は、最後にwp_reset_postdata()を入れます。これは表示件数そのものを直すためではなく、その後のテンプレートタグが別クエリの投稿を参照し続けないようにするためです。

表示件数がずれる原因を順に確認する

最小例の件数が合っているなら、実際の一覧に含まれる条件や外部処理を1つずつ確認します。原因を同時に直そうとせず、表示件数が変わった箇所を記録しながら進めてください。

原因1:posts_per_pageが想定どおりに効いていない

posts_per_pageは、WP_Queryで「1ページに何件表示するか」を指定する基本の引数です。未指定や数値の0はサイトの表示件数へ置き換わるため、0件にする指定にはなりません。切り分けでは1以上の整数を使い、-1は全件取得になって通常のページ分割をしない、と分けて覚えてください。

そのため、自分では「3件のつもり」でも、実際の$argsposts_per_pageが入っていなければ、管理画面の「1ページに表示する最大投稿数」が使われることがあります。まずは$argsを見て、件数指定が本当にそのクエリに渡っているかを確認してください。

直前の最小例では、posts_per_pageを3と明示しています。まずそのまま3件になるか確認し、合わない場合は同じテンプレート内の別ループや、pre_get_postsによる上書きを疑います。同じ指定だけを抜き出したコードは重ねず、最小例を切り分けの基準にしてください。

アーカイブページや検索結果ページだけ件数が違う場合は、posts_per_archive_pageを確認します。クエリオブジェクトがアーカイブまたは検索と判定されたときにposts_per_pageを上書きするため、主にそのページのメインクエリで問題になります。

つまり、通常のサブクエリでは期待どおりでも、アーカイブや検索のメインクエリでは別の指定が効いている可能性があります。特定ページだけ件数が違う場合は、テンプレートの$argsだけでなく、テーマのfunctions.phpやプラグイン側の処理も確認してください。

子テーマのfunctions.phpまたは機能プラグインに置く例です。対象画面と実行条件を確認し、検証環境で試してから本番へ反映してください。

PHPfunctions.php検索結果だけ表示件数を変更するpre_get_postsの例
function wpq_search_result_count( $query ) {   if ( is_admin() || ! $query->is_main_query() ) {      return;   }    if ( $query->is_search() ) {      $query->set( 'posts_per_page', 10 );   }}add_action( 'pre_get_posts', 'wpq_search_result_count' );

このコードの目的は、検索結果のメインクエリだけを10件へ変えることです。! $query->is_main_query()で通常のセカンダリWP_Queryを除外しているため、この修正版がサイドバー等の独自ループまで変える説明にはなりません。対象条件がない別のpre_get_posts処理が存在しないかは、テーマとプラグインを横断して確認します。

原因3:固定表示の投稿が混ざっている

ホームの1ページ目だけ内容・順序・件数が違う場合は、先頭固定表示を確認します。既定のignore_sticky_posts=falseでは、結果内の固定投稿を先頭へ移します。さらに条件に合う固定投稿が元の結果外に残っている場合、WordPressが追加取得して先頭へ挿入する経路もあるため、単なる並べ替えだけとは限りません。

ignore_sticky_posts => trueは先頭への特別扱いを止める指定です。条件に一致する固定投稿を一覧から完全に除外したい場合は、post__not_inget_option( ‘sticky_posts’ )のIDを渡すなど、別の除外条件が必要です。

原因4:offsetとpagedの組み合わせでページ送りがずれている

ページ送りで表示件数が合わないときは、offsetpagedを疑います。公式リファレンスでは、offsetはスキップする投稿数を指定する引数ですが、pagedの設定を上書き・無視し、ページネーションを壊す可能性があると注意されています。

たとえば「先頭3件を除いて、次の投稿から一覧表示したい」という理由でoffsetを使うと、1ページ目は期待どおりでも、2ページ目以降で件数や開始位置がずれることがあります。offset分はfound_postsから自動では差し引かれないため、最終ページ数、欠落、重複を自分で調整する必要があります。ページネーションを使う一覧では、まずoffsetを外してpagedだけで動くか確認しましょう。

offsetを外し、posts_per_pagepagedだけで1ページ目・2ページ目の投稿IDを比べます。表示数が同じでも開始位置がずれれば、記事の欠落や重複として見えます。

原因5:pre_get_postsやプラグインで条件が変わっている

自分のテンプレートに書いた$argsが正しく見えるのに件数が合わない場合は、pre_get_postsやプラグインによる変更を確認します。pre_get_postsは、クエリ変数が作られた後、実際のクエリが実行される前に発火するフックです。

公式リファレンスでは、pre_get_postsを使うときは、どのクエリを変更しているかに注意し、is_admin()$query->is_main_query()などで対象を絞ることが推奨されています。対象を絞らないと、メインクエリだけでなく、サイドバーやフッターなどのカスタムループまで意図せず変える可能性があります。

対象条件がない処理は、複数のクエリへ影響し得ます。メインクエリだけを変えるなら、前に示した検索結果の例のようにis_admin()$query->is_main_query()、ページ種別の条件をそろえます。件数のトラブルでは、条件が広すぎないかだけでなく、別のフックが後から同じ値を上書きしていないかも確認してください。

post_countとfound_postsの違いも確認する

デバッグ中にpost_countfound_postsを見て、「件数が合わない」と感じることがあります。この2つと、画面へ出した記事数は別です。post_countは、そのWP_Queryオブジェクトのposts配列に現在入っている件数です。

found_postsは件数制限前に条件へ一致した総件数で、max_num_pagesの計算に使われます。ループ内のcontinueや条件分岐で表示を飛ばせば、画面の件数はpost_countより少なくなります。

つまり、1ページあたり3件表示しているとき、post_countが3で、found_postsが20になることは自然です。no_found_rows => trueでは通常の総件数計算を省くため、ページネーション用の総件数確認には使えません。

原因を切り分けるための一時的な確認コードです。ローカルなどの検証環境だけで使い、確認後は削除してください。

PHPdebug.php現在ページの件数と総件数を分けて確認する例
$query = new WP_Query( [   'post_type'      => 'post',   'posts_per_page' => 3,] ); error_log( 'post_count: ' . $query->post_count );error_log( 'found_posts: ' . $query->found_posts );error_log( 'max_num_pages: ' . $query->max_num_pages );

このコードのポイントは、今回取得した件数と、条件に一致した総件数を分けて確認することです。found_postsが多いからといって、画面に全件出るわけではありません。

指定件数より少ないときは取得条件と表示条件を分ける

post_count自体が少ないなら、最初に「どの投稿を取得したいのか」と、実際の絞り込み条件が一致しているかを確認します。post__inpost__not_in、著者、日付、検索語、親投稿、tax_querymeta_query、公開状態を1つずつ外し、どの条件で候補が減るかを見ます。非公開投稿を閲覧できる権限の違いも結果へ影響します。

post_countは合っているのに画面だけ少ない、または多い場合は、ループ内のcontinue、ループ外の固定出力、同じテンプレートパーツ・ショートコードの複数呼び出しを数えてください。同じ投稿IDが複数見える場合は、複数ループと除外IDも続けて確認します。

公式資料で確認したいポイント

表示件数のトラブルは、ブログ記事の断片的なサンプルだけを見ると混乱しやすい部分です。posts_per_pageoffsetpagedignore_sticky_postsなどは、それぞれ単独では分かりやすくても、組み合わせたときに挙動が変わります。

WP_Query公式リファレンスのPagination Parametersを確認し、メインクエリを変更している場合はpre_get_postsの対象条件を見直します。the_post()を使う別クエリでは、最後にwp_reset_postdata()を入れます。

公式リンク

公式ドキュメント

表示件数は小さい例から順番に切り分ける

表示件数が合わないときは、最初から複雑な条件を直そうとしないほうが早く解決できます。まずはpost_typepost_statusposts_per_pageだけの最小例で期待どおりの件数になるかを確認します。

そのうえで、固定表示の投稿、アーカイブ用の件数指定、offsetpagedpre_get_poststax_querymeta_queryの順に戻していくと、どこで件数が変わるのかを見つけやすくなります。

修正後の表示件数を確認

  • 対象WP_Queryのpost_countと画面へ出した記事数が意図どおりになった
  • found_postsとmax_num_pagesを総件数・総ページ数として確認した
  • 1ページ目と2ページ目で投稿IDの欠落・重複がない
  • 先頭固定表示を有効・無効にしたときの違いが要件どおりになった
  • pre_get_postsがメインクエリだけを対象にしている
WP Query BuilderBuilderで条件を組み直す条件を選び、WP_Queryのコードを画面で作れます。Builderでクエリを作る

この記事を書いた人

Huddly

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

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

この記事の検証情報

検証環境

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

更新履歴

  • 2026年8月27日 本文と補助情報を更新
  • 2026年8月27日 初回公開

この記事を活用する

あとで見返す・共有する

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

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