2026年6月3日

2026年6月3日

WordPressのページネーションをカスタマイズする方法・ページ番号・前後リンク設定

はじめに

「投稿一覧のページ送りをカスタマイズしたい」「カスタムクエリにページネーションが効かない」——WordPressのページネーションはpaginate_links()とWP_Queryのpagedパラメータを正しく組み合わせることで実装できます。

症状・原因

カスタムループでページネーションが動作しない主な原因は、pagedパラメータの取得方法の誤りです。フロントページではpage、アーカイブページではpagedを使う必要があります。またthe_posts_pagination()paginate_links()の使い方を理解することが重要です。

解決手順

ステップ1:標準のページネーションを表示する

// テーマのテンプレートでページネーションを表示
// メインクエリに対してはthe_posts_pagination()を使用
the_posts_pagination( [
    'mid_size'           => 2,          // 現在ページ前後に表示するページ数
    'prev_text'          => '← 前のページ',
    'next_text'          => '次のページ →',
    'screen_reader_text' => 'ページナビゲーション',
    'type'               => 'plain',    // 'plain' | 'list' | 'array'
] );

// 前の投稿・次の投稿リンク(単一投稿ページ用)
the_post_navigation( [
    'prev_text' => '<span>← 前の記事</span><span>%title</span>',
    'next_text' => '<span>次の記事 →</span><span>%title</span>',
] );

ステップ2:paginate_links()でカスタムページネーションを作る

// paginate_links()でフルカスタム
function get_custom_pagination( $query = null ) {
    global $wp_query;
    $q = $query ?? $wp_query;

    $total   = $q->max_num_pages;
    $current = max( 1, get_query_var( 'paged' ) );

    if ( $total <= 1 ) return '';

    $links = paginate_links( [
        'base'      => str_replace( 999999999, '%#%', esc_url( get_pagenum_link( 999999999 ) ) ),
        'format'    => '?paged=%#%',
        'current'   => $current,
        'total'     => $total,
        'mid_size'  => 2,
        'end_size'  => 1,
        'prev_text' => '&laquo;',
        'next_text' => '&raquo;',
        'type'      => 'array',
    ] );

    if ( ! $links ) return '';

    $output = '<nav class="pagination" aria-label="ページナビ"><ul>';
    foreach ( $links as $link ) {
        $output .= '<li>' . $link . '</li>';
    }
    $output .= '</ul></nav>';

    return $output;
}

ステップ3:カスタムWP_Queryにページネーションを追加する

// カスタムクエリのページネーション(最も重要な実装)
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
// フロントページの場合は 'page' を使う
if ( is_front_page() ) {
    $paged = ( get_query_var( 'page' ) ) ? get_query_var( 'page' ) : 1;
}

$custom_query = new WP_Query( [
    'post_type'      => 'post',
    'posts_per_page' => 10,
    'paged'          => $paged,         // ← これが必須
    'category_name'  => 'news',
] );

while ( $custom_query->have_posts() ) {
    $custom_query->the_post();
    // 表示処理
}

// ページネーションを表示(カスタムクエリを渡す)
echo get_custom_pagination( $custom_query );

wp_reset_postdata();

ステップ4:AjaxでLoad Moreボタンを実装する

// functions.phpにAjaxハンドラーを追加
add_action( 'wp_ajax_load_more_posts',        'handle_load_more' );
add_action( 'wp_ajax_nopriv_load_more_posts', 'handle_load_more' );

function handle_load_more() {
    check_ajax_referer( 'load_more_nonce', 'nonce' );

    $page  = absint( $_POST['page'] ?? 1 );
    $query = new WP_Query( [
        'post_type'      => 'post',
        'posts_per_page' => 6,
        'paged'          => $page,
    ] );

    if ( ! $query->have_posts() ) {
        wp_send_json_error( 'no_posts' );
    }

    ob_start();
    while ( $query->have_posts() ) {
        $query->the_post();
        get_template_part( 'template-parts/post-card' );
    }
    $html = ob_get_clean();
    wp_reset_postdata();

    wp_send_json_success( [
        'html'     => $html,
        'has_more' => $page < $query->max_num_pages,
    ] );
}
// Load Moreボタンの処理
document.addEventListener('DOMContentLoaded', function() {
    const btn       = document.getElementById('load-more');
    const container = document.getElementById('posts-container');
    if (!btn) return;

    let page = 2; // 初期表示が1ページ目なので2から開始

    btn.addEventListener('click', async function() {
        btn.textContent = '読み込み中…';
        btn.disabled    = true;

        const form = new FormData();
        form.append('action', 'load_more_posts');
        form.append('nonce',  wpData.nonce);
        form.append('page',   page);

        const res  = await fetch(wpData.ajaxUrl, { method: 'POST', body: form });
        const data = await res.json();

        if (data.success) {
            container.insertAdjacentHTML('beforeend', data.data.html);
            page++;
            if (!data.data.has_more) btn.remove();
            else { btn.textContent = 'もっと見る'; btn.disabled = false; }
        }
    });
});

ステップ5:投稿数の設定を変更する

// カスタムクエリの投稿数をページタイプ別に変更
add_action( 'pre_get_posts', function( $query ) {
    if ( ! $query->is_main_query() || is_admin() ) return;

    if ( $query->is_category() ) {
        $query->set( 'posts_per_page', 12 ); // カテゴリーページは12件
    }
    if ( $query->is_search() ) {
        $query->set( 'posts_per_page', 20 ); // 検索結果は20件
    }
} );

注意事項

  • カスタムWP_Queryでpagedを設定しない場合、ページネーションのリンクは正しく表示されてもページ切り替えが機能しません。必ず'paged' => $pagedを含めてください。
  • フロントページ(is_front_page())ではget_query_var('paged')が0を返すことがあるため、get_query_var('page')も確認してください。
  • Ajaxページネーションの場合、URLが変わらないため検索エンジンに全ページがインデックスされません。SEOが重要なサイトでは通常のページネーションを優先してください。

まとめ

ページネーションの実装は「the_posts_pagination()でメインクエリ→paginate_links()でカスタムデザイン→WP_QueryのpagedパラメータでカスタムLoop→Ajaxでロードモア」の流れで構築できます。フロントページとアーカイブページでpagedパラメータの取得方法が違う点に特に注意してください。関連記事:WordPressでカスタム投稿タイプを登録する方法WordPressでAjaxを使った動的コンテンツを実装する方法

お気軽にご相談ください

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