記事一覧の下に付けるページネーション(ページ送り)は、プラグインを使わなくてもWordPress標準の関数だけで実装できます。この記事では、簡単な順に3つの方法を解説します。
- 方法1:
the_posts_pagination()——メインクエリなら1行(まずはこれ) - 方法2:
paginate_links()——HTML構造や表示を細かく制御したい場合 - 方法3:カスタムWP_Queryのループにページネーションを付ける場合
方法1:the_posts_pagination()(メインクエリなら1行)
アーカイブや一覧テンプレート(メインクエリ)なら、WP標準の the_posts_pagination() を置くだけでページ番号付きのページ送りが表示されます。
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 に用意します。
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'));
}
'format' => 'page/%#%' は「投稿名」などのきれいなパーマリンク用です。基本(?p=123)設定のサイトでは動かないため、その場合は format を '&paged=%#%' に変えるか、base/format を省略してWPの自動判定に任せてください。方法3:カスタムWP_Queryにページネーションを付ける
自作の WP_Query ループでは、①クエリに paged を渡す ②total にそのクエリの max_num_pages を渡すの2点が必要です。
$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になりません。
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);
}
});
①表示件数は
pre_get_posts で変えているか(テンプレート内のクエリ差し替えはNG) ②設定 → パーマリンクを再保存したか(リライトルール更新) ③カスタム投稿なら has_archive の設定は正しいか。それでも解決しない場合は記事が404になる原因と対処法(完全解説)で切り分けてください。固定ページ・フロントページでは「page」と「paged」に注意
カスタムWP_Queryを固定ページのテンプレートや静的フロントページで使う場合、ページ番号はクエリ変数 paged ではなくpage に入ります。get_query_var('paged') だけを見ていると、何ページ目を開いても常に1ページ目が表示されるバグになります。
// 通常の一覧は 'paged'、固定ページ・静的フロントは 'page' に入る
$paged = get_query_var('paged') ? get_query_var('paged') : max(1, get_query_var('page'));
方法3のカスタムWP_Queryを固定ページで使うときは、$paged の取得をこの形にしてください。固定ページ本文の分割(<!--nextpage-->)については固定ページにページネーションを表示する方法で解説しています。
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 | 前へ・次へのテキスト | ‘«’ / ‘»’ |
| type | 戻り値の形式 | ‘plain’ / ‘array’ / ‘list’ |
| add_args | リンクに付けるクエリ引数 | array('foo' => 'bar') |
| add_fragment | リンク末尾のフラグメント | ‘#section’ |
・2ページ目以降をnoindexにしない——Googleは分割ページを正常にクロール・評価します。noindexにすると2ページ目以降の記事リンクの発見が遅れます
・canonicalは各ページ自身に向ける——全ページを1ページ目に向けるのは誤りです
・
rel="prev/next" の設置指示は古い情報——Googleは2019年にサポート終了を公表しており、現在は不要ですよくある質問(FAQ)
mid_size(現在ページの前後に出す番号の数)を指定してください。the_posts_pagination(array('mid_size' => 2)); のように書きます。また、総ページ数が1のときはページネーション自体が表示されません。'paged' => max(1, get_query_var('paged')) を渡しているか、②paginate_links() の total にそのクエリの max_num_pages を渡しているか。メインクエリの値を渡すと総ページ数がずれます。pre_get_posts で posts_per_page を変更してください。あわせて設定 → パーマリンクの再保存(リライトルール更新)も確認します。固定ページで使っている場合は page / paged の取り違えも疑ってください。paginate_links() の出力には .page-numbers クラスが付きます(現在ページは .page-numbers.current)。Cocoonテーマでは既定のスタイルが定義済みです。さらに読み込みを非同期化したい場合はページネーションをAjaxで非同期読み込みにする方法、件数表示は「全◯件中◯件目」を実装する方法も参考になります。まとめ
- まずは
the_posts_pagination(array('mid_size' => 2))(メインクエリは1行) - 細かく制御:
paginate_links()(base/formatはパーマリンク設定に注意) - カスタムWP_Query:
pagedを渡す+totalはそのクエリのmax_num_pages - 404対策:表示件数は
pre_get_postsで変更+パーマリンク再保存 - 固定ページ・フロント:ページ番号は
pageに入る(pagedと併読) - SEO:2ページ目以降のnoindex・1ページ目へのcanonical集約はしない
「1行で済む標準関数 → 細かい制御 → カスタムクエリ」の順に選び、404と page/paged の2大ハマりに気をつければ、プラグインなしでも堅牢なページネーションが実装できます。
