2026年5月20日
2026年5月20日
WordPressのpre_get_posts後にページネーションが壊れる場合の解決方法
はじめに
pre_get_posts フィルターで posts_per_page を変更したり投稿タイプを追加すると、ページネーションのリンクが正しく生成されないことがあります。paginate_links() が使う max_num_pages はメインクエリの結果を参照するため、カスタムクエリと食い違いが生じます。
症状・原因
- 2ページ目以降のリンクが404になる
- ページネーションが1ページしか表示されない
- 最後のページを超えたリンクが生成される
- 投稿タイプ追加後にページ数が変わる
原因の仕組み:
paginate_links() は $GLOBALS['wp_query']->max_num_pages を参照します。pre_get_posts でクエリを変更すると found_posts と max_num_pages が更新されますが、posts_per_page の変更タイミングによってはズレが生じます。
解決手順
ステップ1:pre_get_postsの正しい書き方
// functions.php
add_action('pre_get_posts', function($query) {
// 管理画面とメイン以外のクエリは除外
if (is_admin() || !$query->is_main_query()) return;
// アーカイブページのみ変更
if ($query->is_archive() || $query->is_home()) {
$query->set('posts_per_page', 12);
$query->set('post_type', ['post', 'product']);
}
});
is_main_query() チェックが必須です。これがないとフィードやREST APIのクエリも変更されます。
ステップ2:paginate_linksにmax_num_pagesを渡す
// テンプレートファイル
global $wp_query;
echo paginate_links([
'base' => str_replace(999999999, '%#%', esc_url(get_pagenum_link(999999999))),
'format' => '?paged=%#%',
'current' => max(1, get_query_var('paged')),
'total' => $wp_query->max_num_pages, // ← ここが重要
]);
total に $wp_query->max_num_pages を渡すことで、変更後のクエリに基づいたページ数が計算されます。
ステップ3:カスタムWP_Queryの場合
// カスタムWP_Queryでページネーションを使う場合
$paged = get_query_var('paged') ?: 1;
$query = new WP_Query([
'post_type' => ['post', 'product'],
'posts_per_page' => 12,
'paged' => $paged,
]);
// ループの後にページネーション
echo paginate_links([
'current' => max(1, $paged),
'total' => $query->max_num_pages, // カスタムクエリの max_num_pages を使う
]);
ステップ4:found_postsフィルターで件数を調整
// found_posts が正しく計算されているか確認・修正
add_filter('found_posts', function($found_posts, $query) {
if (!is_admin() && $query->is_main_query() && $query->is_home()) {
// 必要に応じて件数を上書き
// $found_posts = custom_count_posts();
}
return $found_posts;
}, 10, 2);
ステップ5:パーマリンク設定を確認
wp rewrite flush --hard
ページネーションのURLが /page/2/ 形式で動作しない場合は、パーマリンクのリライトルールが壊れている可能性があります。
よくあるミスパターン
// NG:posts_per_page を直接変更している
add_filter('posts_per_page', function() {
return 12;
}); // paginate_links の total と一致しなくなる
// OK:pre_get_posts で変更
add_action('pre_get_posts', function($query) {
if (!is_admin() && $query->is_main_query()) {
$query->set('posts_per_page', 12);
}
});
注意事項
query_posts()は使用しないこと(メインクエリを壊してページネーションが確実に壊れます)- スタティックフロントページの場合は
is_home()ではなくis_front_page()を使います - カスタムタクソノミーのアーカイブには
is_tax()を使います
まとめ
pre_get_posts 後のページネーション問題は、paginate_links() の total パラメータに $wp_query->max_num_pages を渡すことで解決します。カスタム WP_Query を使う場合は $query->max_num_pages を参照してください。