[WordPress]記事ページに同カテゴリーのページネーションを設置する方法


WordPressを利用する際、カテゴリーページやアーカイブページではページネーションを利用すると思いますが、記事ページ（single.php）にもページネーションを設置したいという依頼がありました。
あまり需要は無いと思いますが、 **同一カテゴリーに所属する記事へのページネーション**の設置方法を記録しておきます。

## 仕様

* 検証バージョン：WordPress 4.7.4
* 記事は **一つのカテゴリーにのみ所属**（複数カテゴリーに適用する場合はforeach等でアレンジしてください）

## コード
### single.phpに記述するコード
ページネーションを設置する箇所に以下のコードを記入し、3行目の
```$pagination = 5;```
の数字を、任意の数に書き換えてください。（※半角数字）
<img alt="ページネーション表示イメージ" src="https://qiita-image-store.s3.amazonaws.com/0/62022/bada3cbc-4245-a8d5-2d18-ec5ca6dbeb9e.png" width="493">

```php:single.php
<ul class="pagination">
<?php
$pagination = 5;	// 1ページに表示するページ送りの最大数

$cat = get_the_category();
$cat = $cat[0];
$catname = get_cat_name($cat->term_id);		// カテゴリー名を取得
$catid = get_cat_ID($catname);				// カテゴリーIDを取得

$post_id = get_the_ID();	// 現在の投稿IDを取得
$post_id_array = array();	// 取得したくない投稿情報ID（複数指定する場合は,で区切る）

// 投稿記事のカテゴリ内で新着から何番目かを確認
$args = array( 'posts_per_page' => -1, 'category' => $catid, 'exclude' => $post_id_array );
$posts = get_posts( $args );
$posts_ids = array();

foreach ( $posts as $post ) {
	$posts_ids[] += $post->ID;
}

$post_current = array_search($post_id, $posts_ids);		// 現在の記事番号（順番）を取得
$post_last = count($posts_ids);							// 同じカテゴリー内の記事数
$post_last_group = $post_last - $pagination;			// 最後尾のページ送りグループ
$post_last_switch = $post_last - ($pagination - 1);		// 最後の5つに切り替えるする記事番号

// 最大値が1〜4まで前後のリンク数が異なる
switch ($pagination) {
	case 1:
		$post_prev = $post_current;
		$post_next = $post_current + 1;
		break;

	case 2:
		$post_prev = $post_current;
		$post_next = $post_current + 2;
		break;

	case 3:
		$post_prev = $post_current - 1;
		$post_next = $post_current + 2;
		break;

	case 4:
		$post_prev = $post_current - 1;
		$post_next = $post_current + 3;
		break;

	default:
		$post_prev = $post_current - 2;
		$post_next = $post_current + 3;
		break;
}

wp_reset_postdata();

// 「次へ（新しい記事へ）」リンクの設定
if ($post_last >= $pagination && $post_current > ($pagination - 2)) {
	if ($pagination != $post_last) {
		echo '<li><a href="'.get_permalink($posts_ids[0]).'">&laquo;&nbsp;最新</li>';
		next_post_link('<li>%link</li>','&laquo;&nbsp;次へ',true);
	}
}

// 記事数が最大数以上ある場合
// 例）最大数が5個で、記事が5個以上ある場合
if($post_last >= $pagination) {
	if ($post_current < ($pagination - 1)) {
		$is_first = true;

		for ($i=0; $i < $pagination; $i++) {
			if ($i == $post_current) {
				// 現在のページ
				echo '<li class="active"><a href="#">'.($i+1).'</a></li>';
			} else {
				// その他のページ
				echo '<li><a href="'.get_permalink($posts_ids[$i]).'">'.($i+1).'</a></li>';
			}
		}
	} else if ($post_current >= $post_last_switch) {
		$is_last = true;

		for ($i=$post_last_group; $i < $post_last; $i++) {
			if ($i == $post_current) {
				// 現在のページ
				echo '<li class="active"><a href="#">'.($i+1).'</a></li>';
			} else {
				// その他のページ
				echo '<li><a href="'.get_permalink($posts_ids[$i]).'">'.($i+1).'</a></li>';
			}
		}
	} else {
		for ($i=$post_prev; $i < $post_next; $i++) {
			if ($i == $post_current) {
				// 現在のページ
				echo '<li class="active"><a href="#">'.($i+1).'</a></li>';
			} else {
				// その他のページ
				echo '<li><a href="'.get_permalink($posts_ids[$i]).'">'.($i+1).'</a></li>';
			}
		}
	}
} // ここまで / 記事数が最大数以上ある場合

// 記事数が最大数未満の場合
else {
	for ($i=0; $i < $post_last; $i++) {
		if ($i == $post_current) {
				// 現在のページ
			echo '<li class="active"><a href="#">'.($i+1).'</a></li>';
		} else {
				// その他のページ
			echo '<li><a href="'.get_permalink($posts_ids[$i]).'">'.($i+1).'</a></li>';
		}
	}
} // ここまで / 記事数が最大数未満の場合

// 「前へ（古い記事へ）」リンクの設定
if ($post_last >= $pagination && $is_last == false && $post_next <= $post_last && $pagination != $post_last) {
	if ($pagination == 2 && $post_current != ($post_last - 2)) {
		previous_post_link('<li>%link</li>','前へ&nbsp;&raquo;',true);
		echo '<li><a href="'.get_permalink(end($posts_ids)).'">最古&nbsp;&raquo;</li>';
	} else if($pagination != 2) {
		previous_post_link('<li>%link</li>','前へ&nbsp;&raquo;',true);
		echo '<li><a href="'.get_permalink(end($posts_ids)).'">最古&nbsp;&raquo;</li>';
	}
}
?>
</ul>
```

サンプルでは```<ul>```タグを使用しており、現在のページに該当する```<li>```タグに```active```というclassを付与しています。
なお、サンプルはBootstrapのページネーション用cssを使用しています。


### 出力されるHTML例

```html
<ul class="pagination">
	<li><a href="/post1">«&nbsp;最新</a></li>
	<li><a href="/post4" rel="next">«&nbsp;次へ</a></li>
	<li><a href="/post3">3</a></li>
	<li><a href="/post4">4</a></li>
	<li class="active"><a href="#">5</a></li>
	<li><a href="/post6">6</a></li>
	<li><a href="/post7">7</a></li>
	<li><a href="/post6" rel="prev">前へ&nbsp;»</a></li>
	<li><a href="/post10">最古&nbsp;»</a></li>
</ul>
```

## 動作
基本は現在の記事を中心に、

* 設定した記事数分の前後記事へのリンク
* 番号リンクとは別に直前・直後記事へのリンク
* 左右端に最新・最古記事へのリンク


が表示されます。
<img alt="ページネーション表示イメージ" src="https://qiita-image-store.s3.amazonaws.com/0/62022/1ecadf8e-3acf-82ab-0c3f-4ef61b24ba09.png" width="493">


最新から5個目（設定した記事数）までの記事にいる場合は「最新」「次へ」リンクは表示されません。
<img alt="最新から設定した記事数までの表示イメージ" src="https://qiita-image-store.s3.amazonaws.com/0/62022/942820eb-9478-e7b2-83e8-2e44239d0c7f.png" width="340">

同じく最古から5個目までの記事にいる場合は「最古」「前へ」リンクは表示されません。
<img alt="最古から設定した記事数までの表示イメージ" src="https://qiita-image-store.s3.amazonaws.com/0/62022/3153b30d-7f77-ead2-992d-99e0365013e4.png" width="346">


カテゴリー内の記事数が設定した記事数より少ない場合は、前後と最新・最古のリンクは表示されません。
<img alt="設定した記事数より少ない場合の表示イメージ" src="https://qiita-image-store.s3.amazonaws.com/0/62022/b247bb90-6112-7af1-8727-f153bfa3a07a.png" width="141">


以上になります。

必要な機能は取り揃えていると思います。

---

下記のページを参考にさせていただきました。ありがとうございます。

▼WordPressで、投稿記事と同じカテゴリー内の前後数件の記事を一覧出力する
https://hack-le.com/wplistcatzengo/