WordPressでは投稿詳細ページに前後リンクを設定することがよくあります。たとえば以下のような感じですね。
この前後リンクを出力するPHPコードは以下のようになっています。get_next_postとget_previous_post関数を利用して前後の記事情報を取得し、get_permalinkの関数にIDを引数として渡すようになっています。
<div class="p-post-link">
<?php $next_post = get_next_post();
if ($next_post) :
?>
<div class="p-post-link__next">
<a class="p-post-link__next-link" href="<?php echo get_permalink($next_post->ID); ?>">前へ</a>
</div>
<?php endif; ?>
<?php $prev_post = get_previous_post();
if ($prev_post) :
?>
<div class="p-post-link__prev">
<a class="p-post-link__prev-link" href="<?php echo get_permalink($prev_post->ID); ?>">次へ</a>
</div>
<?php endif; ?>
</div>
だいたいの案件ではこのようなコードをsingle.phpに書けば前後リンクを設定できますが、以前、特定の記事を前後リンクから除外したいという要件があったため、こちらのコードに加えてひと手間加えるコードを書きました。以下にそのやり方を記述していきます。
まずは、カスタムフィールドを用いて、各記事に前後リンクを設定するかどうかという真偽値を用意します。今回私はAdvanced Custom Fieldsを用いました。設定例としては以下のような感じですね。
今回は、フィールドのスラッグをexistence, フィールドタイプは真偽値として、初期値はチェックをつけて真としています。投稿画面では以下のような見た目になっています。
では、もし投稿画面でチェックを外した場合には前後リンクからその記事を除外するように、以下のようなPHPコードをsingle.phpに記述します。
// カスタムフィールドのexistenceがtrueの投稿のみ前後リンクに出力
<div class="p-post-link">
<?php
$current_post_date = get_the_date('Y-m-d H:i:s');
$current_post_id = get_the_ID();
// 次の投稿を取得するカスタムクエリ
$next_post_args = array(
'post_type' => 'post', //任意の投稿タイプ
'posts_per_page' => 1,
'meta_query' => [
'relation' => 'OR',
[
'key' => 'existence',
'value' => '1',
'compare' => '='
],
[
'key' => 'existence',
'compare' => 'NOT EXISTS'
]
],
'orderby' => 'date',
'order' => 'ASC',
'date_query' => array(
array(
'after' => $current_post_date,
),
),
'post__not_in' => array($current_post_id),
);
$next_post_query = new WP_Query($next_post_args);
$next_post = $next_post_query->have_posts() ? $next_post_query->posts[0] : null;
// 前の投稿を取得するカスタムクエリ
$prev_post_args = array(
'post_type' => 'post', //任意の投稿タイプ
'posts_per_page' => 1,
'meta_query' => [
'relation' => 'OR',
[
'key' => 'existence',
'value' => '1',
'compare' => '='
],
[
'key' => 'existence',
'compare' => 'NOT EXISTS'
]
],
'orderby' => 'date',
'order' => 'DESC',
'date_query' => array(
array(
'before' => $current_post_date,
),
),
'post__not_in' => array($current_post_id),
);
$prev_post_query = new WP_Query($prev_post_args);
$prev_post = $prev_post_query->have_posts() ? $prev_post_query->posts[0] : null;
if ($next_post) : ?>
<div class="p-post-link__next">
<a class="p-post-link__next-link" href="<?php echo get_permalink($next_post->ID); ?>">前へ</a>
</div>
<?php endif; ?>
<?php if ($prev_post) : ?>
<div class="p-post-link__prev">
<a class="p-post-link__prev-link" href="<?php echo get_permalink($prev_post->ID); ?>">次へ</a>
</div>
<?php endif; ?>
<?php wp_reset_postdata(); ?>
</div>
次の投稿、前の記事を取得するカスタムクエリを作成して前後記事の情報を取得しています。$current_post_date = get_the_date(‘Y-m-d H:i:s’);でまず、現在の記事の投稿日時を取得し、date_queryパラメータに格納しているのが分かると思います。同時に、カスタムクエリに対してmeta_queryパラメータで、keyをexistenceにし、value=1(真)であるという設定もしています。
また、’compare’ => ‘NOT EXISTS’というOR条件も追加していますが、これに関しては、もし既に存在する記事にACFで新たにフィールドを追加した場合に、初期値を真と設定していてもフィールドの値はnullとなっているためです。私はこの事実に気づかずに少し時間を溶かしてしまったので皆さんもお気をつけください。
以上のコードをsingle.phpに記述することによって、投稿画面でカスタムフィールドのチェックを外したら、前後リンクからその記事が消えるようになりました!実装機会は少ないかもしれませんが、記事に真偽値のカスタムフィールドを追加して条件付けするという考え方は他の実装にも応用できますので、ご参考までにどうぞ。