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_postsmax_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 を参照してください。

お気軽にご相談ください

お見積りへ お問い合わせへ