【WordPress】前後記事のさらに前後記事データを取得して出し分けをする方法

# はじめに
Web制作会社のエムハンドでエンジニアをしてる@yokinoです。
WordPressで前後記事のさらに前後記事データを取得して出し分けをする方法について書きます。

WordPressの記事ページに、前後記事へのリンクを設置することがありますが、
たまに記事によっては「直接外部サイトに飛ばしたい」「PDFに飛ばしたい」といった要望があります。
それらはカスタムフィールドを用いて実装することができますが、
要望にあるような記事にはデータは存在するものの、記事ページでは本文が空っぽになっています。
できれば前後記事リンクではそういった記事ページは飛ばして、通常の記事ページをリンク先に設定したいですよね。

この記事では、前後記事が「外部サイトへ飛ばす記事」か「PDF記事」のとき、
さらに前後記事を取得して通常の記事をリンク先に設定する方法をまとめます。
# カスタムフィールドの設定
![カスタムフィールド01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127393/bb88fab4-601a-c5e3-1c3b-2c0a8b590f7f.png)
プラグイン[Advanced Custom Fields](https://ja.wordpress.org/plugins/advanced-custom-fields/)で「外部URL」と「PDF」フィールドを作成します。
フィールド名はそれぞれ、post_url, post_pdfとします。

# ベースのhtml
ベースになるhtmlを書きます。
```html
<ul class="c-pager02">
	<li class="c-pager02__prev"><a href="">前へ</a></li>
	<li class="c-pager02__next"><a href="">次へ</a></li>
	<li class="c-pager02__all"><a href="">一覧へ</a></li>
</ul>
```
# phpとhtml
```php:php
$main_post = $post; //$postを入れておく
$prev_post = get_previous_post(); // 前の記事を取得
$next_post = get_next_post(); // 次の記事を取得

//前の記事があるか
if ( $prev_post ) {
	while(true) {
		//外部URLとPDFがないならその記事を設定すればいいので必要なデータを返し、ループを終了
		if ( !get_field( 'post_url', $prev_post->ID ) && !get_field( 'post_pdf', $prev_post->ID ) ) {
			$prev_flag = true;
			$prev_url = get_permalink( $prev_post->ID );
			break;
		//外部URLとPDFのどちらか一方が存在するとき、さらに過去の記事のデータを見に行く
		} elseif ( get_field( 'post_url', $prev_post->ID ) || get_field( 'post_pdf', $prev_post->ID) ) {
			$prev_flag = false;
			$post = $prev_post; //前の記事をグローバル$postに上書き
			$prev_post = get_previous_post(); //上書きしたpost（前の記事）の前の記事を取得
			if ( !$prev_post ) { //前の記事がないなら処理終了
				break;
			}
		}
	}
}

//次の記事があるか
if ( $next_post ) {
	while(true) {
		//外部URLとPDFがないならその記事を設定すればいいので必要なデータを返し、ループを終了
		if ( !get_field( 'post_url', $next_post->ID ) && !get_field( 'post_pdf', $next_post->ID) ) {
			$next_flag = true;
			$next_url = get_permalink( $next_post->ID );
			break;
		//外部URLとPDFのどちらか一方が存在するとき、さらにあとの記事のデータを見に行く
		} elseif ( get_field( 'post_url', $next_post->ID ) || get_field( 'post_pdf', $next_post->ID) ) {
			$next_flag = false;
			$post = $next_post; //次の記事をグローバル$postに上書き
			$next_post = get_next_post(); //上書きしたpost（次の記事）の次の記事を取得
			if ( !$next_post ) { //次の記事がないなら処理終了
				break;
			}
		}
	}
}

$post = $main_post; //$postをもとに戻す
```

```html:html
<ul class="c-pager02">
	<?php if ( $prev_post && $prev_flag ) : ?>
		<li class="c-pager02__prev"><a href="<?php echo $prev_url; ?>">前へ</a></li>
	<?php endif; ?>
	<?php if ( $next_post && $next_flag ) : ?>
		<li class="c-pager02__next"><a href="<?php echo $next_url; ?>">次へ</a></li>
	<?php endif; ?>
	<li class="c-pager02__all"><a href="">一覧へ</a></li>
</ul>
```

# ざっくり解説

まずグローバル変数`$post`を別の変数に入れておく。
`get_previous_post()`と`get_next_post()`はグローバル変数`$post`にある前後の記事情報を取得してくれる。
つまり`$post`を前後の情報で上書きした状態で`get_previous_post()`と`get_next_post()`を実行すれば、さらに前後の記事情報を取得できる。
取得した記事に「外部URL」または「PDF」が設定されていれば、`$post`を上書きしてさらに前後の記事を取得する。
通常の記事または記事がなくなるまで処理をさせる。
最後には`$post`を元に戻すために、予め別の変数に入れておいた`$post`で`$post`を上書きする。

# さらに
表示上では良い感じになりましたが、外部URLだろうがPDFだろうが、そのための記事ページは存在しています。アクセスできてしまいます。
もしもXML Sitemapsなどでsitemap.xmlに含まれていた場合はクロールの対象になります。
都度除外設定するのは手間がかかるので、そういったページにアクセスがあった場合は一覧ページにリダイレクトさせるか、設定した「外部URL」や「PDF」に飛ばす処理をsingle.phpに入れておきましょう。
※get_header()よりも前に

```php:single.php
//一覧にリダイレクトさせる場合
if ( get_field( 'post_url' ) || get_field( 'post_pdf' ) ) {
	wp_redirect( home_url() . '/xxx/', 301 ); exit;
}
//外部URLにリダイレクトさせる場合
if ( get_field( 'post_url' ) ) ) {
	wp_redirect( get_field( 'post_url' ), 301 ); exit;
}
//PDFにリダイレクトさせる場合
if ( get_field( 'post_pdf' ) ) ) {
	wp_redirect( get_field( 'post_pdf' ), 301 ); exit;
}
```

# おわりに

以上が前後記事のさらに前後記事データを取得して出し分けをする方法でした。

WordPressサイトを構築するうえで、よく使う関数が何をやっているのか、実行するとどういったデータを返してくれるのか、
実装することで他にどういった影響があるのかを調べたり考えれるようになると応用がききます。
一つの答えに導いたときの達成感を得ることができます。とても楽しいですね。

https://www.m-hand.co.jp/recruit/