WordPressサイトで記事を読んでいるとき、「同じカテゴリーの次の記事にすぐ移動したい」と思ったことはありませんか?

一般的なWordPressサイトでは「最近の投稿」や「カテゴリー一覧」がサイドバーに表示されますが、これらは現在読んでいる記事との関連性が薄く、読者の回遊率向上にはあまり効果的ではありません。

この記事では、現在の記事を含めて同一カテゴリー内の連続する記事をサイドバーに表示する
カスタマイズ方法を2パターン紹介します。

完成イメージ

実装後は以下のような表示になります:

パターン1:連続記事ナビゲーション(tocCat.php)

  • 現在読んでいる記事(ハイライト表示)
  • 同じカテゴリーの次の記事
  • 同じカテゴリーの次の次の記事
  • 同じカテゴリーの次の次の次の記事
  • 同じカテゴリーの次の次の次の次の記事

パターン2:カテゴリー記事リスト(postList.php)

  • カテゴリー内の1番目の記事
  • カテゴリー内の2番目の記事
  • カテゴリー内の3番目の記事
  • カテゴリー内の4番目の記事
  • カテゴリー内の5番目の記事(現在の記事が含まれる場合はハイライト)

これにより読者は迷うことなく、カテゴリー内の記事を効率的に読み進めることができます。

実装手順

1. 連続記事ナビゲーション(tocCat.php)の作成

現在の記事を基準にした前後の記事を表示するファイルを作成します。

/wp-content/themes/your-theme/parts/toc/tocCat.php

<?php
/**
* tocCat-desc.php(カテゴリー別の記事目次)
* 現在の記事を含めて、同じカテゴリー内の次の記事を表示
*/
?>
<script>
(function() {
const STYLE = document.createElement('style');
STYLE.textContent = `
/* CSS(省略、詳細は後述) */
`;
document.getElementsByTagName('head')[0].appendChild(STYLE);
})();
</script>
<?php
//現在の記事のカテゴリー情報を取得
if (has_category()) {
  $categories = get_the_category();
  if (!empty($categories)) {
    $category = $categories[0];
    $cat_id   = $category->cat_ID;
    $cat_name = $category->cat_name;
    $current_post_id = get_the_ID();
    
    //まずmenu_orderで並び順をチェック
    $args_menu_order = array(
      'cat' => $cat_id,
      'posts_per_page' => -1,
      'orderby' => 'menu_order',
      'order' => 'DESC',
      'post_status' => 'publish'
    );
    
    $posts_by_menu_order = get_posts($args_menu_order);
    
    //menu_orderが設定されているかチェック
    $has_menu_order = false;
    foreach ($posts_by_menu_order as $post) {
      if ($post->menu_order != 0) {
        $has_menu_order = true;
        break;
      }
    }
    
    //menu_orderがない場合は投稿日で並び替え
    if (!$has_menu_order) {
      $args_date = array(
        'cat' => $cat_id,
        'posts_per_page' => -1,
        'orderby' => 'date',
        'order' => 'DESC',
        'post_status' => 'publish'
      );
      $all_posts = get_posts($args_date);
    } else {
      $all_posts = $posts_by_menu_order;
    }
    
    if (!empty($all_posts)) {
      //現在の記事のインデックスを取得
      $current_index = -1;
      foreach ($all_posts as $index => $post) {
        if ($post->ID == $current_post_id) {
          $current_index = $index;
          break;
        }
      }
      
      if ($current_index === -1) {
        return;
      }
      
      //現在の記事から次の記事を5件抽出(現在の記事 + 次の4件)
      $display_posts = array();
      
      for ($i = 0; $i < 5; $i++) {
        $post_index = $current_index - $i;  //マイナス方向に移動
        if ($post_index >= 0 && isset($all_posts[$post_index])) {
          $display_posts[] = $all_posts[$post_index];
        }
      }
      
      if (!empty($display_posts)) {
?>

<div class="widget-saraTocCat_Side">
  <div class="tocCat-veu">
    <h2 class="widgettitle"><?php echo esc_html($cat_name); ?></h2>

    <ul class="tocCat-list">
      <?php foreach ($display_posts as $index => $post) : setup_postdata($post); ?>
      <?php 
      //現在の記事かどうかをチェック
      $is_current = ($post->ID == $current_post_id);
      $current_class = $is_current ? ' current_page_item' : '';
      
      //タイトルの文字数制限
      $title = get_the_title($post->ID);
      $title_length_limit = 45;
      $display_title = mb_strlen($title) > $title_length_limit 
        ? mb_substr($title, 0, $title_length_limit) . '...' 
        : $title;
      ?>
      <li class="tocCat-item<?php echo $current_class; ?>" id="post-<?php echo $post->ID; ?>">
        <a class="fl-left" href="<?php echo get_permalink($post->ID); ?>">
          <picture class="tocCat-thumbnail">
            <?php 
            $thumbnail = get_the_post_thumbnail($post->ID, array(96, 96));
            if ($thumbnail) {
              echo $thumbnail;
            } else {
              echo '<img src="' . get_theme_file_path() . '/img/noimage.png" alt="' . esc_attr($title) . '">';
            }
            ?>
          </picture>
        </a>
        <div class="tocCat-content">
          <h4 class="tocCat-title">
            <a href="<?php echo get_permalink($post->ID); ?>" title="<?php echo esc_attr($title); ?>"><?php echo esc_html($display_title); ?></a>
          </h4>
          <span class="tocCat-date"><?php echo get_the_date('Y.m.d', $post->ID); ?></span>
        </div>
      </li>
      <?php endforeach; ?>
      <?php wp_reset_postdata(); ?>
    </ul>
  </div>
</div>

<?php
      }
    }
  }
}
?>

2. カテゴリー記事リスト(postList.php)の作成

カテゴリー内の上位記事を表示するファイルを作成します。

/wp-content/themes/your-theme/parts/list/postList.php

<?php
/**
 * カテゴリー記事リスト
 * 現在の記事と同じカテゴリーの上位5件を表示
 */
?>
<script>
(function() {
const STYLE = document.createElement('style');
STYLE.textContent = `
/* postList用CSS(tocCatと同様の構造でクラス名を変更) */
`;
document.getElementsByTagName('head')[0].appendChild(STYLE);
})();
</script>
<?php
//現在の記事のカテゴリー情報を取得
if (has_category()) {
  $categories = get_the_category();
  if (!empty($categories)) {
    $category = $categories[0];
    $cat_id   = $category->cat_ID;
    $cat_name = $category->cat_name;
    $current_post_id = get_the_ID();
    
    //menu_orderチェックとフォールバック処理(tocCatと同様)
    //...
    
    //上位5件のみ取得
    if (!$has_menu_order) {
      $args_date = array(
        'cat' => $cat_id,
        'posts_per_page' => 5, //5件のみ取得
        'orderby' => 'date',
        'order' => 'DESC',
        'post_status' => 'publish'
      );
      $postlist_posts = get_posts($args_date);
    } else {
      //menu_orderがある場合は上位5件を取得
      $postlist_posts = array_slice($posts_by_menu_order, 0, 5);
    }
    
    if (!empty($postlist_posts)) {
?>

<div class="widget-saraPostList_Side">
  <div class="postList-veu">
    <h2 class="widgettitle"><?php echo esc_html($cat_name); ?></h2>

    <ul class="postList-list">
      <?php foreach ($postlist_posts as $index => $post) : setup_postdata($post); ?>
      <?php 
      //現在の記事かどうかをチェック
      $is_current = ($post->ID == $current_post_id);
      $current_class = $is_current ? ' current_page_item' : '';
      
      //タイトルの文字数制限(同様の処理)
      ?>
      <li class="postList-item<?php echo $current_class; ?>" id="post-<?php echo $post->ID; ?>">
        <!-- HTML構造はtocCatと同様、クラス名のみ変更 -->
      </li>
      <?php endforeach; ?>
      <?php wp_reset_postdata(); ?>
    </ul>
  </div>
</div>

<?php
    }
  }
}
?>

3. single.phpでの読み込み

投稿ページテンプレートで作成したPHPファイルを読み込みます。

<!-- サイドバー -->
<aside class="asleeve asleeve4efA">
  <!-- パターン1:連続記事ナビゲーション -->
  <?php include(get_theme_file_path() . '/parts/toc/tocCat.php'); ?>
  
  <!-- または -->
  
  <!-- パターン2:カテゴリー記事リスト -->
  <?php include(get_theme_file_path() . '/parts/list/postList.php'); ?>
</aside>

コードの解説

tocCat.phpの特徴

1. 現在記事を基準にした取得

//現在の記事から次の記事を5件抽出
for ($i = 0; $i < 5; $i++) {
  $post_index = $current_index - $i;  //マイナス方向に移動
  if ($post_index >= 0 && isset($all_posts[$post_index])) {
    $display_posts[] = $all_posts[$post_index];
  }
}

postList.phpの特徴

1. シンプルな上位記事取得

if (!$has_menu_order) {
  $args_date = array(
    'cat' => $cat_id,
    'posts_per_page' => 5, //最初から5件のみ取得
    'orderby' => 'date',
    'order' => 'DESC',
    'post_status' => 'publish'
  );
  $postlist_posts = get_posts($args_date);
} else {
  //menu_orderがある場合は配列の先頭5件を切り出し
  $postlist_posts = array_slice($posts_by_menu_order, 0, 5);
}

2. 現在記事のハイライト機能

現在の記事がリストに含まれる場合、自動的に current_page_item クラスが付与され、視覚的に区別されます。

共通の並び順制御

両方のファイルで以下の優先順位で並び順を決定します:

  1. menu_order(カスタムオーダー)- 設定されている場合
  2. 投稿日(昇順)- menu_orderが未設定の場合のフォールバック
//menu_orderが設定されているかチェック
$has_menu_order = false;
foreach ($posts_by_menu_order as $post) {
  if ($post->menu_order != 0) {
    $has_menu_order = true;
    break;
  }
}

CSSスタイリングのポイント

ホバー効果(コンテンツが動かない左ボーダー)

.widget-saraTocCat_Side .tocCat-veu .tocCat-list .tocCat-item {
  box-shadow: 5px 0 0 0 transparent inset;
  transition: box-shadow 0.3s ease-out;
}

.widget-saraTocCat_Side .tocCat-veu .tocCat-list .tocCat-item:has(:is([href], [onclick]):hover) {
  box-shadow: 5px 0 0 0 var(--c-assort-pl-500, hsl(223, 39%, 53%)) inset;
}

現在記事のハイライト

.widget-saraTocCat_Side .tocCat-veu .tocCat-list .tocCat-item.current_page_item {
  box-shadow: 5px 0 0 0 var(--c-assort-pl-400, hsl(223, 39%, 63%)) inset;
}

使い分けのガイドライン

tocCat.php(連続記事ナビゲーション)が適している場合

  • チュートリアルサイト: 連続した学習コンテンツ
  • シリーズ記事: 順序通りに読んでほしい記事群
  • ストーリー性のあるブログ: 前後の文脈が重要な記事

postList.php(カテゴリー記事リスト)が適している場合

  • 一般的なブログサイト: カテゴリー内の記事概観を提供
  • ニュースサイト: 最新記事や人気記事の表示
  • ポートフォリオサイト: カテゴリー内の代表的な作品表示

カスタマイズオプション

文字数制限の調整

$title_length_limit = 45; //45文字を任意の文字数に変更

表示件数の変更

//tocCat.php
for ($i = 0; $i < 5; $i++) { //5を任意の数字に変更

//postList.php
'posts_per_page' => 5, //5を任意の数字に変更

表示順序を変更

//表示順序を逆転(前の記事→現在の記事の順にする)
$display_posts = array_reverse($display_posts);

並び順の変更(投稿日の場合)

$args_date = array(
  'cat' => $cat_id,
  'posts_per_page' => 5,
  'orderby' => 'date',
  'order' => 'DESC', //ASC(古い順)をDESC(新しい順)に変更
  'post_status' => 'publish'
);

効果とメリット

このカスタマイズにより以下の効果が期待できます:

  1. 回遊率の向上: 読者が関連記事を見つけやすくなる
  2. ユーザビリティの向上: 現在位置が明確で、次に読むべき記事が分かりやすい
  3. SEO効果: 内部リンクの強化により、サイト全体の評価向上
  4. 離脱率の改善: 関連記事への誘導により滞在時間の延長
  5. コンテンツの価値向上: 記事間の関連性を明確にすることで、サイト全体の構造化

まとめ

WordPressの標準機能やプラグインでは実現しにくい「同一カテゴリー内の効果的な記事ナビゲーション」を2つのアプローチで実装する方法を紹介しました。

tocCat.phpは現在記事を中心とした連続性を重視し、postList.phpはカテゴリー全体の概観を提供します。サイトの性質や目的に応じて最適な方法を選択し、読者にとって価値のあるナビゲーション体験を提供してください。

両方のファイルは独立して動作するため、同時に使用することも可能です。A/Bテストを行い、どちらがより効果的かを検証することをお勧めします。


注意: テーマファイルを編集する前は、必ずバックアップを取ってから作業を行ってください。また、プラグインのアップデートによる影響を避けるため、子テーマでの実装を推奨します。