WordPress で同一カテゴリの記事タイトルを記事下に表示(複数カテゴリ)

[投稿日] 2016年4月27日
[最終更新] 2016年11月17日

2016年11月17日修正:ソースコード中、閉じる必要のないphpは閉じないようにした

本記事では、WordPressにおいて、記事下に同一カテゴリの記事を表示する方法について記述します。カテゴリが複数あればすべて表示し、また投稿記事のリンクはリストに含まれないようにします。最初のコードはバグがあったので、後でしれっと修正しました。

スポンサーリンク

やりたいこと

WordPressを初めてしばらく、そろそろテンプレートをいじりたいなと思うようになりました。手始めに、個別記事ページの記事下に、投稿記事と同じカテゴリの記事のタイトルを表示しようと思いました。Livedoorブログだと何も考えずともあるやつです。それを実装します。記事のカテゴリが複数ある場合にも対応します。phpについては不勉強ですが、自分が全然わからないコードを書いてしまうと、後々何か起きた時に右往左往してしまうことになるので、まぁなんとか説明できる範囲で書きました。

コード

編集すべき個別記事ページの php ファイルは、/var/www/html/wp-content/themes/ほげほげ/single.php です。私は初心者なので、デフォルトのTwentySixteenを使っていますが、このテーマでは、single.php に get_template_part( ‘template_part( ‘template-parts/content’, ‘single’ ); という記述があります。つまり、個別記事のphpの実体は、template-parts ディレクトリ下にあるということです。template-parts ディレクトリを見ると、content-single.php というそれらしいファイルがあります。このファイルを編集します。

以下のコードを末尾に追記すると、記事下に記事と同一カテゴリのうち新規10件のタイトルが表示されるようになります。おおまかな流れとして「[WordPress] 見ている記事と同じカテゴリーの最新記事一覧を表示する方法 (参照中の記事は除外) | TechMemo」を参考にさせていただきました。

<?php
// 現在の記事のIDを保持
$post_id = get_the_ID();
// 現在の記事のカテゴリー
$categories = get_the_category();

// 現在の記事が含むカテゴリー毎にループ
foreach( $categories as $category ):
  // 表示する記事の条件を指定
  // exclude に $post_id を入れることで、現在の記事を除外
  $args = array( 'posts_per_page' => 10, 'category' => $category->cat_ID, 'exclude' => $post_id );
  $posts = get_posts( $args );

  // 記事が1つ以上存在する時のみhtmlを出力
  if ( sizeof($posts) > 0 ):
    echo '<h3>'.$category->cat_name.' と同一カテゴリの記事</h3>';
    echo '<ul>';
    foreach( $posts as $post ):
      echo '<li><a href="'.get_permalink().'">'.get_the_title().'</a></li>';
    endforeach;
    echo '</ul>';
  endif;
endforeach;
$post = get_post($post_id);
?>

echo文の.(ドット)は、結合を意味します。echoの度にいったんphpを閉じるサンプルをよく見ますが、ソースコードが非常に見づらくなるので、一度phpが始まったら、出来る限りphpで書き続けるほうが良いのではないかと思います。

解説

一行一行、見ていきます。

$post_id = get_the_ID(); で、投稿記事のIDを代入します。これは、後で当該記事を記事一覧から省くのに使います。また、$categories にテンプレートタグ get_the_category() より、投稿記事の属するカテゴリーを代入します。get_the_category() については「テンプレートタグ/get the category – WordPress Codex 日本語版」を参照。

カテゴリーは複数あるかもしれません。ので、foreach( $categories as $category ): より、1つずつ$category として処理します。

次がポイントで、 get_posts() を利用して同一カテゴリの記事の情報を取得します。get_posts() のパラメータが重要です。ここではパラメータを $args に配列でまとめています。それぞれ説明すると、posts_per_page は件数で、表示したい記事数を入れます。category は、取得したいカテゴリのカテゴリIDを入れます(この場合 $category->cat_ID)。exclude は、除外したい記事のIDを入れます。その他どんなパラメータがあるのかなど、詳細については「テンプレートタグ/get posts – WordPress Codex 日本語版」および「get_posts:WordPress私的マニュアル」を参照してください。

さて、取得した記事群 $posts のサイズが0以下であれば、つまり表示すべき記事がないということなので、ここまでです。次の if 文内の処理は行われず、すなわち最後のほうの endif; 後、つまりループの終わりまで飛びます。$posts のサイズが0より大きければ、つまり表示すべき記事がある場合は、カテゴリ名を $category->cat_name() より取得し、その後 $posts 内の各記事情報を $post として処理していきます。各記事のURLを get_permalink() で取得し、記事タイトルを get_the_title() で取得します。

以上を繰り返し、$categories 内のすべてのカテゴリーについて処理したら、ループを抜けます。

ループを抜けたら、変わってしまった$postを元に戻します。$post = get_post($post_id);です。これをしないと、$postが一番最後に表示した記事の情報になってしまうため、メタ情報の日付がおかしなことになったりします。

リストで一度登場した記事を、別カテゴリのリストで表示させない

さて、以上のやり方でも問題ないと思いますが、たとえばAの記事がカテゴリ1とカテゴリ2の両方に属している場合、カテゴリ1とカテゴリ2のリストの両方にAの記事が載ります。それはそれでよいという場合もあるでしょうし、それはちょっと格好がつかないという場合もあるでしょう。以下に、一度リストにのった記事は、他カテゴリのリストから外れるようにするやり方を書きます。

上記コードでは、get_posts()のパラメータである$argsのexcludeで、記事のIDを指定することで、現在の記事をリストから除外しています。したがって、このexcludeに、現在の記事だけでなく、一度表示した記事のIDも指定すればよい。このexcludeは、数値、文字列のほか配列を指定することができるので、’exclude’ => post_id のpost_idを除外したい記事すべてのIDを格納した配列にすればOKです。具体的には、コードを以下のように書き換えます。

// $post_id = get_the_ID();
$post_id_array = array();
$post_id_array[] = get_the_ID();
...中略...
//         $args = array( 'posts_per_page' => 10, 'category' => $category->cat_ID, 'exclude' => $post_id );
$args = array( 'posts_per_page' => 10, 'category' => $category->cat_ID, 'exclude' => $post_id_array );
...中略...
<?php
foreach( $posts as $post ):
  echo '<li><a href="'.get_permalink().'">'.get_the_title().'</a></li>';
  // ここを追記
  $post_id_array[] = get_the_ID();
endforeach;
$post = get_post($post_id_array[0]);
?>

これで、たとえばカテゴリ1とカテゴリ2に含まれる記事Aは、カテゴリ1のリスト内でしか表示されなくなりました。

スポンサーリンク

コメントを残す

メールアドレスが公開されることはありません。