【Wordpress】中身のない記事を前後ページャーから除外する方法

※本ブログの目的は個人の備忘録であり、コードは参考用として掲載しています。
実際に使用される際は、ご自身の環境で十分に動作確認を行ってください。
コードの利用によって生じたいかなる問題についても責任を負いかねますので、あらかじめご了承ください。

はじめに

WordPressで記事詳細ページに前後のリンク(ページャー)を設置する場合、多くは previous_post_link()next_post_link() を使っているかと思います。これらの関数は非常に便利で、コードもシンプルに済ませることができます。

しかし、実際のサイト運用では「本文が空の記事」、つまりあえて中身を作成しない記事というケースが存在します。

このような「中身を作成しないことを前提とした投稿」は、たとえ noindex を付けたり、アクセス時に 404 を返すようにしていても、前後リンクには通常どおり出力されてしまいます。結果として、ユーザーが意図しない「空の記事」へ遷移してしまうという問題が発生します。

そこでこの記事では、そうした「中身のない記事」を自動的に除外し、本文のある記事だけを対象とした前後ページャーを表示するためのカスタム関数をご紹介します。

WP_Query + date_query で前後の記事を検索する関数

まずは完成形のコードを紹介します。WP_Querydate_query を使って本文ありの投稿を取得します。

以下は、post_content が空でない記事のみを対象に、現在の投稿よりも前または後の記事を取得する関数です。

function get_adjacent_post_with_content($direction = 'previous') {
  global $post;
  $current_post_time = $post->post_date;

  $args = array(
    'post_type'      => $post->post_type,
    'post_status'    => 'publish',
    'orderby'        => 'date',
    'order'          => $direction === 'previous' ? 'DESC' : 'ASC',
    'posts_per_page' => -1,
    'date_query'     => array(
      array(
        $direction === 'previous' ? 'before' : 'after' => $current_post_time,
        'inclusive' => false,
      ),
    ),
  );

  $posts = get_posts($args);
  foreach ($posts as $p) {
    if (trim(strip_tags($p->post_content)) !== '') {
      return $p;
    }
  }
  return null;
}

この関数では、$post->post_date を使って「現在表示中の投稿の投稿日時」を取得し、それを基準として date_query に指定しています。

このようにすることで、「現在の投稿より前または後にある投稿」をフィルターし、さらに中身がある投稿のみを探す処理が実現できます。

ポイント:date_query

この関数で重要なのが date_query の使い方です。これは WP_Query のパラメータのひとつで、投稿日時に基づいてフィルタリングを行います。

'date_query' => array(
  array(
    'before' => $current_post_time,
    'inclusive' => false,
  )
)

このように書くことで、「現在の投稿の日時よりも前の投稿」を取得対象にできます。逆に after を指定すれば「次の記事」として取得可能です。

  • beforeafter の値には ISO 形式(例:2024-12-01 10:00:00)の日時が入ります。
  • inclusivefalse にすることで、同一日時の投稿を除外できます。

この date_query により、現在の投稿より過去または未来の記事の中から、本文が存在する最初の1件を取得する処理が実現できます。

関数内では、$direction === 'previous' ? 'before' : 'after' => $current_post_time のように、引数によって条件を切り替えることで、「前の記事」または「次の記事」のどちらを表示するかを制御しています。

テンプレートでの使い方

上記関数を活用して、カスタムテンプレートでの「前の記事」「次の記事」リンクを出力するには、以下のように記述します。

<div class="c-pager">
  <div class="prev">
    <?php $prev = get_adjacent_post_with_content('previous');
    if ($prev) echo '<a href="' . get_permalink($prev->ID) . '">前の記事へ</a>'; ?>
  </div>

  <a href="URL">一覧</a>

  <div class="next">
    <?php $next = get_adjacent_post_with_content('next');
    if ($next) echo '<a href="' . get_permalink($next->ID) . '">次の記事へ</a>'; ?>
  </div>
</div>

このようにすることで、本文が空の投稿を除外した「前後リンク」を実現できます。

まとめ

カスタム投稿タイプを運用する中で、投稿によっては本文(コンテンツ)を作成しない場合もあります。そうした投稿に対しては、表示時に 404 にリダイレクトしたり、metaタグで noindex を付けて検索エンジンにインデックスさせない処理を施すことがあります。

しかし、そうした対応を行っていても、実際は記事のパーマリンクは生成されてしまうため、前後のページャー(previous/next)では中身のない投稿がリンクとして表示されてしまうケースは意外と見落とされがちです。

本記事では、date_query を活用し、現在表示中の投稿日時を基準に「中身のある記事だけ」を前後リンクに表示する方法をご紹介しました。

特に、全件に中身を入れるとは限らないような投稿タイプを扱っている場合は、こうしたロジックの見直しが必要になってくることがあります。

また、return $pをどのような条件で返すかによって、様々な用途で利用できるかと思いますので、ぜひ要件にあったカスタマイズの参考にしてみてください。