- 結論
- 原因・仕組み
- 手順(サンプルコード)
- 動作確認(検証環境と結果)
- posts_per_page が効かない原因と pre_get_posts の正しい書き方の注意点
- posts_per_page が効かない原因と pre_get_posts の正しい書き方でよくあるミス
- posts_per_page が効かない原因と pre_get_posts の正しい書き方のチェックリスト
- posts_per_page が効かない原因と pre_get_posts の正しい書き方のFAQ(よくある質問)
- 筆者の見解(posts_per_page が効かない原因と pre_get_posts の正しい書き方)
- posts_per_page が効かない原因と pre_get_posts の正しい書き方の関連項目
- 出典(一次情報)
結論
posts_per_page を指定したのに件数が変わらないときは、次の順で疑います。
- WP_Query に numberposts を渡している(WP_Query では numberposts は無効)
- pre_get_posts で、条件なしに posts_per_page を上書きしている(サブクエリや get_posts にも効く)
- メインクエリの件数を変えたいのに、テンプレート側で new WP_Query している
- 設定>表示設定の「1ページに表示する最大投稿数」が使われている(引数を渡していない)
メインクエリの件数を変えるなら、テンプレートで new WP_Query せず、pre_get_posts の中で $query->is_main_query() と is_admin() を確認してから set() します。
原因・仕組み
WP_Query は posts_per_page を渡さないと、設定>表示設定の値(既定 10)を使います。numberposts は get_posts() 専用の別名で、WP_Query に渡しても読まれません。
pre_get_posts は、クエリオブジェクトが作られた後、SQL を実行する前に走るアクションです。引数 $query は参照渡しで、set() で条件を書き換えられます。公式リファレンスでは、管理画面を巻き込まないよう is_admin() を確認し、メインクエリだけを対象にするため、グローバル関数の is_main_query() ではなく $query->is_main_query() を使うよう説明されています。
条件なしで書くと、同じページにあるウィジェットのクエリ、get_posts()、関連記事のクエリなど、あらゆる WP_Query が書き換わります。
手順(サンプルコード)
悪い例(そのままコピーしないでください)
// 悪い例: すべてのクエリが10件に書き換わる
add_action( 'pre_get_posts', function ( $query ) {
$query->set( 'posts_per_page', 10 );
} );
良い例(メインクエリだけ、フロントのカスタム投稿タイプ一覧だけ)
add_action( 'pre_get_posts', function ( $query ) {
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
if ( $query->is_post_type_archive( 'ks_book' ) ) {
$query->set( 'posts_per_page', 12 );
}
} );
条件の判定には、グローバル関数ではなく $query->is_post_type_archive() のようなメソッドを使います。pre_get_posts の時点ではグローバルの $wp_query がまだ確定していないことがあるためです。
サブクエリは引数で渡す
$q = new WP_Query( array(
'post_type' => 'post',
'posts_per_page' => 3, // numberposts ではなくこちら
) );
動作確認(検証環境と結果)
WordPress 7.1.2(日本語)、PHP 8.2.12、テーマ twentytwentyfive。表示設定の posts_per_page は 10、検証用の公開記事は12件です(testsposts-per-page-not-working-pre-get-posts.md に全文)。
| 確認内容 | 結果 |
|---|---|
| WP_Query(posts_per_page 指定なし) | 10件(表示設定の値) |
| WP_Query に numberposts=3 | 10件(効かない) |
| WP_Query に posts_per_page=3 | 3件 |
| WP_Query に posts_per_page=-1 | 12件(全件) |
| 条件なしの pre_get_posts で 10 に上書き後、posts_per_page=3 のクエリ | 10件(上書きされた) |
| 同じ状態で get_posts( numberposts=2 ) | 10件(get_posts にも効く) |
| is_admin() と is_main_query() を確認する pre_get_posts にした後、posts_per_page=3 のクエリ | 3件(巻き込まれない) |
| 手作りの new WP_Query() の is_main_query() | false |
get_posts() は既定でクエリ系フィルター(posts_where など)を無効にしますが、pre_get_posts は無効になりませんでした。「get_posts だから pre_get_posts の影響を受けない」と考えるのは間違いです。
posts_per_page が効かない原因と pre_get_posts の正しい書き方の注意点
- posts_per_page に -1 を渡すと全件を取得します。件数が多いサイトでは負荷が高くなるため、上限を決めてください。
- メインクエリの件数を変えたあと、ページ数が変わるため、パーマリンクの /page/N/ が404になる場合があります。フロント側のページネーションも合わせて確認してください。
- pre_get_posts で posts_per_page を変えても、設定>表示設定の値は変わりません。
- 管理画面の一覧(edit.php)にも pre_get_posts は走ります。is_admin() を必ず確認してください。
posts_per_page が効かない原因と pre_get_posts の正しい書き方でよくあるミス
- テーマの一覧ページで query_posts() を使い、メインクエリを上書きする(query_posts() の使い方|説明・引数・注意点)。
- if ( is_main_query() ) とグローバル関数で書いて、条件がずれる。
- カスタム投稿タイプのアーカイブで件数を変えたいのに、投稿タイプの判定を入れず、全アーカイブが変わる。
- 検証時にキャッシュプラグインが古い出力を返し、変更が反映されないと誤解する。
posts_per_page が効かない原因と pre_get_posts の正しい書き方のチェックリスト
- WP_Query に渡す件数の引数は posts_per_page か。
- pre_get_posts の先頭で is_admin() と
$query->is_main_query()を確認しているか。 - 対象のアーカイブや投稿タイプで絞り込んでいるか。
- ページ送りの URL(/page/2/ など)が404にならないか確認したか。
posts_per_page が効かない原因と pre_get_posts の正しい書き方のFAQ(よくある質問)
Q. offset を使うとページネーションが壊れます。
A. offset を指定すると、paged による位置計算が使われなくなります。ページネーションが必要なら、offset ではなく pre_get_posts と paged の組み合わせで設計してください。
Q. posts_per_page を get_option で取りたい。
A. get_option( 'posts_per_page' ) で取れます。検証環境では 10 でした。
Q. 特定のカテゴリだけ件数を変えたい。
A. pre_get_posts の中で $query->is_category( 'news' ) のように判定してから set() します。
筆者の見解(posts_per_page が効かない原因と pre_get_posts の正しい書き方)
私見では、pre_get_posts は便利な反面、影響範囲が最も広いフックのひとつです。「メインクエリか」「管理画面でないか」「どの一覧か」の3条件を、毎回セットで書く癖をつけるのがよいと考えます。件数を変えたいときにテンプレートで新しい WP_Query を作る書き方は、ページネーションの不具合につながりやすいので、避けたほうが安全です。
posts_per_page が効かない原因と pre_get_posts の正しい書き方の関連項目
- pre_get_posts フックの使い方|説明・引数・注意点
- is_main_query() の使い方|説明・引数・注意点
- WP_Query クラスの使い方|説明・引数・注意点
- get_posts() の使い方|説明・引数・注意点
- WP_Query カスタムクエリのページネーション
