フォロー

📝【団長のデバッグ道場🔥 vol.15】WP_Query で posts_per_page が効かないときのチェックリスト

posts_per_page => 5 にしたのに全部出る…バグか?」──そんな声を現場でよく聞きます。
しかし諸君、そのほとんどは WordPress の仕様通り に動いているだけだ! 原因を見抜けば、解決は一瞬である。


🧩 症状再現:5件だけ出したいのに全件表示

$args = [
  'post_type'      => 'news',
  'posts_per_page' => 5,
];
$query = new WP_Query( $args );

本来なら 5 件だけ取得されるはずが、ページ上には 全投稿がズラッと表示
そしてクエリオブジェクトの $query->found_posts を見ると、期待通り 5 件ではなく全件数……。


🔍 真犯人:pre_get_postsmain query を改変していた!

テーマやプラグインでよく見かける、下記のような pre_get_posts フィルター。

add_action( 'pre_get_posts', function( $query ) {
  // フロント & カスタム投稿アーカイブで件数変更
  if ( ! is_admin() && $query->is_post_type_archive( 'news' ) ) {
    $query->set( 'posts_per_page', -1 );
  }
} );

もし $query->is_main_query() をチェックしていないと、管理画面はもちろん、別途生成した WP_Query にまで影響してしまいます。
結果、先ほど生成したローカルクエリでも posts_per_page書き換えられ、LIMIT が無効化されていた──というわけだ。


🛠️ 解決策:3 ステップで再発防止

  1. is_main_query() を必ず併用
    if ( $query->is_main_query() && 条件 ) { ... }
  2. 管理画面と REST API を除外
    if ( is_admin() || wp_doing_rest() ) { return; }
  3. WP_Query を使うときは wp_reset_postdata() で後始末

📖 チェックリスト(コピペ保存推奨)

  • posts_per_page が想定外 → pre_get_posts を疑え
  • フィルター内で is_main_query() を忘れていないか
  • 開発テーマ・プラグインのカスタムループが wp_reset_postdata() しているか

🔧 ベストプラクティス:件数変更は functions.php ではなく archive-*.php 側で制御

「ニュース一覧だけ 5 件にしたい」など明確な用途があるなら、テンプレートファイルでローカルクエリを発行したほうが安全です。親クエリを書き換えないので、他ページやプラグインへの副作用ゼロ!

/**
 * archive-news.php
 * "news" カスタム投稿を 5 件ずつページング表示するサンプル
 */

$paged = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;

$args  = [
  'post_type'      => 'news',
  'posts_per_page' => 5,
  'paged'          => $paged,
];

$news_query = new WP_Query( $args );

if ( $news_query->have_posts() ) :
  while ( $news_query->have_posts() ) :
    $news_query->the_post();
    // ▼ ここで記事カードやタイトルを出力
    get_template_part( 'template-parts/content', 'news' );
  endwhile;

  // ページネーション(例)
  the_posts_pagination( [
    'total' => $news_query->max_num_pages,
  ] );

  wp_reset_postdata();
endif;

この方法ならpre_get_posts に頼らず、一覧レイアウトに合わせて件数やソート条件を自在にカスタムできます。


🧠 まとめ

  • posts_per_page が効かない原因の多くはクエリ書き換え
  • フィルターを使うなら is_main_query()影響範囲を限定
  • ローカルクエリの後は wp_reset_postdata() を忘れずに。

🔥 団長のエール

設定が反映されないとき、我々はつい「WordPress のバグか?」と疑う。だが違う!
それは “仕様” を知らぬがゆえの 落とし穴 だ。
仕様を知れば恐れは消え、バグは味方に変わる。
戦え、エンジニア諸君!! 仕様の深淵を覗き込み、クエリを制する者となれ🔥

コメントする