【WordPress】プラグインなしでページネーションを実装する方法|the_posts_pagination・paginate_links・WP_Query対応

記事一覧の下に付けるページネーション(ページ送り)は、プラグインを使わなくてもWordPress標準の関数だけで実装できます。この記事では、簡単な順に3つの方法を解説します。

3つの方法の使い分け

  • 方法1the_posts_pagination()——メインクエリなら1行(まずはこれ)
  • 方法2paginate_links()——HTML構造や表示を細かく制御したい場合
  • 方法3カスタムWP_Queryのループにページネーションを付ける場合
スポンサーリンク

方法1:the_posts_pagination()(メインクエリなら1行)

アーカイブや一覧テンプレート(メインクエリ)なら、WP標準の the_posts_pagination() を置くだけでページ番号付きのページ送りが表示されます。

テンプレート:1行でページネーション
the_posts_pagination(array(
  'mid_size'  => 2,        // 現在ページの前後に出す番号の数
  'prev_text' => '« 前へ',
  'next_text' => '次へ »',
));
まずはこの方法で足りるか確認
「前へ・次へしか出ない」ときは mid_size を指定すれば番号が出ます。アーカイブテンプレートへの組み込み例はカスタム投稿の一覧ページを作成する方法を参照してください。

なお、標準関数は用途別に3つあります。番号なしの「前へ・次へ」だけでよければ、さらにシンプルな the_posts_navigation() も使えます。

関数 表示 向いている場面
the_posts_navigation() 前へ・次へのみ 最小限のページ送り
the_posts_pagination() ページ番号+前へ・次へ 一般的な一覧ページ(推奨)
paginate_links() 戻り値を自由に加工 HTML構造や条件を細かく制御

方法2:paginate_links() で細かく制御する

出力HTMLやリンク形式を細かく制御したい場合は、paginate_links() をラップした関数を functions.php に用意します。

functions.php:ページネーション関数
function custom_pagination($numpages = '', $pagerange = 2, $paged = '') {
  if (empty($paged)) {
    $paged = max(1, get_query_var('paged')); // 1ページ目は0が返るため1に
  }
  if ($numpages == '') {
    global $wp_query;
    $numpages = $wp_query->max_num_pages ? $wp_query->max_num_pages : 1;
  }

  $links = paginate_links(array(
    'base'      => get_pagenum_link(1) . '%_%',
    'format'    => 'page/%#%',
    'total'     => $numpages,
    'current'   => $paged,
    'show_all'  => false,
    'end_size'  => 1,
    'mid_size'  => $pagerange,
    'prev_next' => true,
    'prev_text' => '«',
    'next_text' => '»',
    'type'      => 'plain',
  ));

  if ($links) {
    echo '<nav class="custom-pagination">' . $links . '</nav>';
  }
}

テンプレート側では次のように呼び出します。第2引数は数値(現在ページの前後に出す番号の数)です。

テンプレート:関数を呼び出す
if (function_exists('custom_pagination')) {
  custom_pagination($wp_query->max_num_pages, 2, get_query_var('paged'));
}
base / format はパーマリンク設定に依存する
'format' => 'page/%#%' は「投稿名」などのきれいなパーマリンク用です。基本(?p=123)設定のサイトでは動かないため、その場合は format'&paged=%#%' に変えるか、base/format を省略してWPの自動判定に任せてください。

方法3:カスタムWP_Queryにページネーションを付ける

自作の WP_Query ループでは、①クエリに paged を渡す ②total にそのクエリの max_num_pages を渡すの2点が必要です。

カスタムWP_Query+ページネーション
$paged = max(1, get_query_var('paged'));

$my_query = new WP_Query(array(
  'category_name'  => 'news',
  'posts_per_page' => 10,
  'paged'          => $paged, // ① 現在ページをクエリに渡す
));

while ($my_query->have_posts()) : $my_query->the_post();
  the_title('<h2>', '</h2>');
endwhile;
wp_reset_postdata();

echo paginate_links(array(
  'total'   => $my_query->max_num_pages, // ② このクエリの総ページ数
  'current' => $paged,
  'mid_size' => 2,
));

2ページ目以降が404になるときの対処

ページネーション自作で最も多いトラブルが「2ページ目が404になる」問題です。主な原因は表示件数の食い違いです。テンプレート内のクエリで posts_per_page を変えても、WordPress本体は「設定 → 表示設定 → 1ページに表示する最大投稿数」を基準に総ページ数を計算するため、「本体の計算では存在しないページ」へのアクセスが404になります。

一覧の表示件数を変えたいときは、テンプレート内ではなくpre_get_posts でメインクエリ自体を変更します。これなら総ページ数の計算も一致し、404になりません。

functions.php:表示件数はpre_get_postsで変更する(404対策)
add_action('pre_get_posts', function ($query) {
  if (is_admin() || !$query->is_main_query()) {
    return;
  }
  // 例:newsカテゴリーの一覧だけ12件表示にする
  if ($query->is_category('news')) {
    $query->set('posts_per_page', 12);
  }
});
404チェックリスト
①表示件数は pre_get_posts で変えているか(テンプレート内のクエリ差し替えはNG) ②設定 → パーマリンクを再保存したか(リライトルール更新) ③カスタム投稿なら has_archive の設定は正しいか。それでも解決しない場合は記事が404になる原因と対処法(完全解説)で切り分けてください。

固定ページ・フロントページでは「page」と「paged」に注意

カスタムWP_Queryを固定ページのテンプレートや静的フロントページで使う場合、ページ番号はクエリ変数 paged ではなくpage に入りますget_query_var('paged') だけを見ていると、何ページ目を開いても常に1ページ目が表示されるバグになります。

PHP:アーカイブでも固定ページでも動く現在ページ取得
// 通常の一覧は 'paged'、固定ページ・静的フロントは 'page' に入る
$paged = get_query_var('paged') ? get_query_var('paged') : max(1, get_query_var('page'));

方法3のカスタムWP_Queryを固定ページで使うときは、$paged の取得をこの形にしてください。固定ページ本文の分割(<!--nextpage-->)については固定ページにページネーションを表示する方法で解説しています。

CSSで見た目を整える

style.css:ページネーションのスタイル
.custom-pagination {
  text-align: center;
  margin: 20px 0;
}

.custom-pagination a,
.custom-pagination span {
  margin: 0 2px;
  padding: 5px 10px;
  display: inline-block;
  border: 1px solid #ccc;
  color: #333;
}

.custom-pagination a:hover {
  background-color: #f7f7f7;
}

.custom-pagination .current {
  background-color: #0073aa;
  color: #fff;
  border-color: #0073aa;
}

途中の「…(ドット)」の表記を変えたい場合はページネーションの「…」を変更・編集する方法を参照してください。

paginate_links() の主なパラメータ

パラメータ 説明
base リンクのベースURL get_pagenum_link(1) . '%_%'
format ページ番号が入る形式 'page/%#%'
total 総ページ数 $wp_query->max_num_pages
current 現在のページ番号 max(1, get_query_var('paged'))
show_all 全ページ番号を表示するか true / false
end_size 先頭・末尾に出す番号の数 1
mid_size 現在ページの前後に出す番号の数 2
prev_next 前へ・次へリンクの表示 true / false
prev_text / next_text 前へ・次へのテキスト ‘&laquo;’ / ‘&raquo;’
type 戻り値の形式 ‘plain’ / ‘array’ / ‘list’
add_args リンクに付けるクエリ引数 array('foo' => 'bar')
add_fragment リンク末尾のフラグメント ‘#section’
分割ページのSEOでやりがちな誤り
2ページ目以降をnoindexにしない——Googleは分割ページを正常にクロール・評価します。noindexにすると2ページ目以降の記事リンクの発見が遅れます
canonicalは各ページ自身に向ける——全ページを1ページ目に向けるのは誤りです
rel="prev/next" の設置指示は古い情報——Googleは2019年にサポート終了を公表しており、現在は不要です

よくある質問(FAQ)

Q「前へ」「次へ」しか表示されず、ページ番号が出ません。
Amid_size(現在ページの前後に出す番号の数)を指定してください。the_posts_pagination(array('mid_size' => 2)); のように書きます。また、総ページ数が1のときはページネーション自体が表示されません。
QカスタムWP_Queryでページネーションが動きません。
A2点確認してください。①クエリ引数に 'paged' => max(1, get_query_var('paged')) を渡しているか、②paginate_links()totalそのクエリの max_num_pages を渡しているか。メインクエリの値を渡すと総ページ数がずれます。
Q2ページ目にアクセスすると404になります。
A多くは表示件数の食い違いが原因です。テンプレート内で件数を変えず、pre_get_postsposts_per_page を変更してください。あわせて設定 → パーマリンクの再保存(リライトルール更新)も確認します。固定ページで使っている場合は page / paged の取り違えも疑ってください。
Qデザインはどのクラスに当てればよいですか?
Apaginate_links() の出力には .page-numbers クラスが付きます(現在ページは .page-numbers.current)。Cocoonテーマでは既定のスタイルが定義済みです。さらに読み込みを非同期化したい場合はページネーションをAjaxで非同期読み込みにする方法、件数表示は「全◯件中◯件目」を実装する方法も参考になります。

まとめ

  • まずは the_posts_pagination(array('mid_size' => 2))(メインクエリは1行)
  • 細かく制御paginate_links()(base/formatはパーマリンク設定に注意)
  • カスタムWP_Querypaged を渡す+total はそのクエリの max_num_pages
  • 404対策:表示件数は pre_get_posts で変更+パーマリンク再保存
  • 固定ページ・フロント:ページ番号は page に入る(paged と併読)
  • SEO:2ページ目以降のnoindex・1ページ目へのcanonical集約はしない

「1行で済む標準関数 → 細かい制御 → カスタムクエリ」の順に選び、404と page/paged の2大ハマりに気をつければ、プラグインなしでも堅牢なページネーションが実装できます。