東京都府中市、渋谷区のWEB制作会社Maromaroのブログです

2017.09.19

hoshida

WordPressで前後記事へのリンクを親カテゴリーが共通のもので出力する

Maromaroのコーダーのhoshidaです。

WordPressの標準の関数だと、前後記事へのリンク出力を同一カテゴリーのみにすることはできますが、親カテゴリーが共通の記事だけにすることはできません。

そこで、少々力技ですが、テンプレート側で同親カテゴリーの前後の記事を出力する記述を作成しました。

//single.phpなどに記述
<?php
  //現在の投稿ID取得
  $current_id = $post->ID;
  
  //カテゴリ設定
  //カスタムタクソノミーなどの場合はタクソノミー名を入れましょう
  $tax = 'category';

  //現在の投稿のターム取得を取得
  $term = array_pop(get_the_terms($post->ID, $tax)); //現在のターム
  $term_id = $term->term_id;
  $ancestors = get_ancestors( $term_id, $tax );
  $reversed_ancestors = array_reverse($ancestors); 
  $ancestors_id = $reversed_ancestors[0]; //最上の祖先ターム
  
  $term_slug;
  if($ancestors){
    //祖先があればその最上のターム
    $term_slug = get_term($ancestors_id)->slug;
  }else{
    //祖先が無ければ現在のターム
    $term_slug = $term->slug;
  }
  
  //同タームの一覧取得
  $args = array(
    //ソートなどしたければここに追記
    'post_type' => get_post_type(),
    $tax => $term_slug,
    'numberposts' => -1
  );
  $post_list = get_posts( $args );
  
  //変数の用意
  $next_id;
  $prev_id;
  $prev_flag;

  //取得した投稿リストをループし前後のIDを取得
  if ( $post_list ) :
  foreach ( $post_list as $post ) :
    if($prev_flag == 1){
      $prev_id = $post->ID;
      $prev_flag = '';
    }
    if($current_id == $post->ID){
      $next_id = $next;
      $prev_flag = 1; 
    }
    $next = $post->ID;
  endforeach;
  endif; wp_reset_postdata();
  
  /*
   * これで
   * $next_id に次の記事の投稿IDが
   * $prev_id に前の記事の投稿IDが入ります
  */
?>

<?php if(isset($next_id) || isset($prev_id)){ //どちらかがあれば出力 ?>
  <div id="next_prev">
    <?php if(isset($next_id)){ //nextがあれば出力 ?>
      <a href="<?php echo get_the_permalink($next_id); ?>">
        <?php echo get_the_title($next_id); ?>
      </a>
    <?php } ?>
  
    <?php if(isset($prev_id)){ //prevがあれば出力 ?>
      <a href="<?php echo get_the_permalink($prev_id); ?>">
        <?php echo get_the_title($prev_id); ?>
      </a>
    <?php } ?>
  </div>
<?php } ?>

これで、現在の投稿に親カテゴリーがある場合、最上の親カテゴリーと同じカテゴリーの前後記事が出力されます。もし現在の投稿に親カテゴリーが無い場合には、現在のカテゴリーと同じカテゴリーの投稿が出力されます。

解説

冒頭では、現在の投稿についているカテゴリーの親を取得します。もし親カテゴリーがあれば最上の親を取得。なければ、つまり現在の投稿についているカテゴリーが親なら、現在のカテゴリーを取得します。

  //現在の投稿ID取得
  $current_id = $post->ID;
  
  //カテゴリ設定
  //カスタムタクソノミーなどの場合はタクソノミー名を入れましょう
  $tax = 'category';

  //現在の投稿のターム取得を取得
  $term = array_pop(get_the_terms($post->ID, $tax)); //現在のターム
  $term_id = $term->term_id;
  $ancestors = get_ancestors( $term_id, $tax );
  $reversed_ancestors = array_reverse($ancestors); 
  $ancestors_id = $reversed_ancestors[0]; //最上の祖先ターム
  
  $term_slug;
  if($ancestors){
    //祖先があればその最上のターム
    $term_slug = get_term($ancestors_id)->slug;
  }else{
    //祖先が無ければ現在のターム
    $term_slug = $term->slug;
  }

次に以下の部分で、冒頭で取得した親カテゴリーと共通の投稿データをすべて取得します。ここにソートなどの条件を追加すれば、前後記事の出力の順番なども制御することができます。

  //同タームの一覧取得
  $args = array(
    //ソートなどしたければここに追記
    'post_type' => get_post_type(),
    $tax => $term_slug,
    'numberposts' => -1
  );
  $post_list = get_posts( $args );

そして、取得した投稿データ一覧をループして、前後の記事のIDを取得します。

  //変数の用意
  $next_id;
  $prev_id;
  $prev_flag;

  //取得した投稿リストをループし前後のIDを取得
  if ( $post_list ) :
  foreach ( $post_list as $post ) :
    if($prev_flag == 1){
      $prev_id = $post->ID;
      $prev_flag = '';
    }
    if($current_id == $post->ID){
      $next_id = $next;
      $prev_flag = 1; 
    }
    $next = $post->ID;
  endforeach;
  endif; wp_reset_postdata();

最後に前後の投稿のIDを利用し、パーマリンクやタイトルを出力します。ここはデザインにあわせて適宜調整してください。IDがあるのでパーマリンクやタイトル以外にもいろいろ出力できます。

<?php if(isset($next_id) || isset($prev_id)){ //どちらかがあれば出力 ?>
  <div id="next_prev">
    <?php if(isset($next_id)){ //nextがあれば出力 ?>
      <a href="<?php echo get_the_permalink($next_id); ?>">
        <?php echo get_the_title($next_id); ?>
      </a>
    <?php } ?>
  
    <?php if(isset($prev_id)){ //prevがあれば出力 ?>
      <a href="<?php echo get_the_permalink($prev_id); ?>">
        <?php echo get_the_title($prev_id); ?>
      </a>
    <?php } ?>
  </div>
<?php } ?>

ループを回すので少し動作は重くなりますが、この方法だとカスタマイズ性が高いので、サイトが複雑になりどうしても前後記事のリンクが上手く出力できない時には活用できるでしょう。

うまくいかない場合

このコードはカテゴリーをひとつしか選択できないテーマを想定しています。なので、カテゴリーが複数ついているケースや、カテゴリーの階層が深く、その中間の親が共通しているもので出力したい場合は、期待通りに動かない可能性があります。

そのような場合にも、とにかく以下のコードの30行目、$term_slug 変数の中に入れたカテゴリーがついている記事が出力されるので、この記述の前の部分を調整してください。

  $args = array(
    //ソートなどしたければここに追記
    'post_type' => get_post_type(),
    $tax => $term_slug,
    'numberposts' => -1
  );

以上です!

なお、最上の祖先カテゴリーを取得する部分は以下の記事で書いた方法を応用しています。

今気づいたんですが記事の冒頭でふざけるとdescriptionが意味不明になりますね… 今後も気を付けません!

ではでは