投稿用テンプレートsingle.phpに関連記事をプラグイン無しで表示させる[WordPressテーマ作成の手順10]

前回作った投稿用テンプレート「single.php」に、さらに「関連記事リスト」を表示させたい。
プラグイン無しで WordPressのテンプレートタグだけで。
本ブログでは、投稿記事の下に「関連記事」を3コ表示させた。その工程をメモっておきます。

本日のINDEX

「関連記事」の表示にはWordPressのプラグインを使う方法もあるが、自由にレイアウトしたいのでプラグイン無しで作る方法を探した。(プラグインを使うなら「WordPress Related Posts」が便利そうだ)

結果、バッチリだったのがこちら。
プラグインなしで関連記事を表示する方法 [Wordpressカスタマイズ] | 寝ログ

寝ログ nelog.jp
IT、Web系のプログラム関連を中心に、家電・生活用品に至るまで、幅広く検証し解説しているブログ。
特にWordPress関連は、php初心者でもすぐに実現できるように考えられたソースを無償で公開してくれています。
初心者心理への洞察力が鋭い、きめ細かい心遣いのあるソース。理解も深まります。ありがとうございます!

スポンサーリンク

関連記事に表示させる1セットを作る

まずは、関連記事として表示させたい部分の1セットを、HTMLとCSSで組む。
「繰り返し表示」させたいモノを1コだけ、あらかじめキチンと作っておくってこと。

本ブログの場合はこんなHTMLソース。これを後でphpとして保存する。

<div class="relPostBox clearfix">
  <div class="col-1-4">
  <a href="#"><img src="images/img1.jpg"/></a>
  </div><!-- ^ .col-1-4 END-->
  <div class="col-3-4">
  <h1 class="relPostH1"><a href="#">投稿記事のタイトル投稿記事のタイトル</a></h1>
  <p>ほんぶん本文ほんぶん本文...80字くらいダミーで入れとく<a href="#"> [記事を読む]</a></p>
  </div><!-- ^ .col-3-4 END-->
</div><!-- ^ .relPostBox END-->

上記ソースの div.col-1-4, div.col-3-4 は、本ブログのグリッドシステムによるものです。

本ブログの場合は、前もって全てのページをHTMLで組むところから始めたので、前回のcontent.phpを作るときと同様に、1番最初に作ったHTMLファイル群の中の「single.html」(投稿ページ用レイアウト)を利用。
その「関連記事」部分だけ残し、それ以外を削除したのが上記ソース。(最初にキチンとHTMLで作っておけば、CSS指定も済んでおり、ラク)

関連記事用のパーツテンプレートを作る

できあがった「関連記事」表示用の1セットを、適当な名前のphpファイル名で保存。
本ブログでは「single_related.php」ってファイル名にした。

「single_related.php」は、寝ログさんの元ソースを参考にさせていただきながら、このように書き換えた。

<?php
$categories = get_the_category($post->ID);
$category_ID = array();
foreach($categories as $category):
  array_push( $category_ID, $category -> cat_ID);
endforeach ;
$args = array(
  'post__not_in' => array($post -> ID),
  'posts_per_page'=> 3,
  'category__in' => $category_ID,
  //'orderby' => 'rand',ランダムじゃないほうがいいのでコメントアウト。orderbyを省略するとデフォルトの'date'になり最新記事から順に表示される
);
$query = new WP_Query($args);
if( $query -> have_posts() ):
while ($query -> have_posts()) : $query -> the_post(); ?>
  <div class="relPostBox clearfix">
   <div class="col-1-4">
   <a href="<?php the_permalink(); ?>"><?php the_post_thumbnail(); ?></a>
   </div><!-- ^ .col-1-4 END-->
   <div class="col-3-4">
   <h1 class="relPostH1"><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h1>
   <p><?php echo mb_substr(strip_tags($post->post_content), 0, 80); ?><a href="<?php the_permalink(); ?>"> [記事を読む]</a></p>
   </div><!-- ^ .col-3-4 END-->
  </div><!-- ^ .relPostBox END-->
<?php
endwhile;
endif;
wp_reset_postdata(); ?>

ハイライト部分(13〜15行、25〜28行)は、WP_Queryと呼ばれるモノ。
前回のループと似たかんじだが、よりカスタマイズしたいときに使う上級者向けのオブジェクトみたい。(ということで、初級者の私にはよく理解できていないが、寝ログさんのソースであっけなく目的は達成)

最初の12行目までは、WP_Queryのための仕込み。

2〜6行までは、get_the_category($post->ID) で現在の記事のカテゴリをゲット
($post->ID がデフォルト)
3〜6行で現在の記事と同じカテゴリ内から選ぶための「変数 $category_ID」を指定している。「変数 $category_ID」は配列である必要があるので、foreachを使っている)

get_the_category についてはこちら:テンプレートタグ/get the category-WordPress Codex 日本語版

7〜12行までは、WP_Queryで使うパラメータを前もって指定してやっている。
‘post__not_in’ 投稿&固定ページ用のパラメータ。array($post -> ID) で、今見ている記事は除外する。
‘posts_per_page’ ページ送りパラメータ。これを3にすれば記事が3コ表示されるというわけ。
‘category__in’ 表示する記事のカテゴリを指定。配列(array)であること。ここでさっき作った変数 $category_IDを指定。
‘orderby’ 並び替えのパラメータ。日付順や著者順などいろいろ指定できる。‘rand’ はランダム、デフォは’date’。

WP_Query についてはこちら:関数リファレンス/WP Query-WordPress Codex 日本語版

で、WP_Queryのループの中に(16〜24行)先ほどのHTMLで組んだ1セットを入れ、「アイキャッチ・タイトル・抜粋文・パーマリンク」をWordPressのテンプレートタグで置き換えている。
このテンプレートタグへの置き換えは後ほど詳細

WP_Query() を使ったら必ずリセットする

上のソースのWP_Queryの部分だけソースを書きだしてみた。基本形はこんなかんじ。
最後に wp_reset_postdata() でリセット(12行目)しているのに注目。

<?php
$args = array( パラメータを使って指定 ); //引数を指定する
$query = new WP_Query( $args ); //新しいクエリの実行
if($query -> have_posts()):
while ($query -> have_posts()) : $query -> the_post(); //ループ開始

//ここに表示する内容のソース

endwhile; //ループ終了
//条件(if)に合わない場合のソース(elseを使って)
endif;
wp_reset_postdata(); // ここでクエリのリセット
?>

new WP_Query(2行目)で、新しいクエリを作ったら、
必ずwp_reset_postdata()でリセットしなくてはならないんだって。
理由は、new WP_Queryで作ったクエリはメインじゃない。サブだから〜。

メインのクエリは「WordPressループ」を使って出力している「現在の記事」。
もう1つクエリを加えるために「WP_Query」で「関連記事」を出力しているのがサブのクエリ

メインクエリとサブのクエリは、実行のタイミングが違う
メインは、URLのリクエストによるクエリが、テンプレート読み込み前に実行
サブは、テーマのテンプレートやプラグインのファイル内(のnew WP_Query)で実行

WP_Queryを使って新たにサブのクエリを作ると、グローバル変数$post($postは「投稿情報」)や、$postの他の付随情報を更新(上書き)してしまう。
そのままにしておくとページの表示に影響を及ぼしてしまうので、関数「wp_reset_postdata」を使って、グローバル変数$postを元に戻す($postが「現在の投稿記事」に戻す)というわけだ。

wp_reset_postdata についてはこちら:関数リファレンス/wp reset postdata-WordPress Codex 日本語版

クエリってなんや?

queryは、「疑問・質問・問合せ」という意味の名詞&動詞。
「I queried him about his background.」なんてふうに使う。

IT用語でのクエリ(query)は、
「〈問い合わせ〉の意。データベースに対する処理要求を文字列で表現したもの。
リレーショナルデータベースでは、一般にSQLが用いられる」
んだそうだ。goo辞書から

データベースに対しての、
「あれある?(探して欲しい)」
「あったら出せる?(取得したい)」
「これ更新できる?(更新しろ)」
などの「処理要求」(というか指令よね)だと私は思ってる。

SQLは書けなくても、WordPress氏が通訳してくれるもんだから、データベースに「処理要求」できる。その1つ1つの「処理要求」が「クエリ」だと思えばいいんじゃないかな。

アイキャッチ・タイトル・抜粋文の出力

先ほどのWP_Queryのループの中身部分のテンプレートタグについて。

  <div class="relPostBox clearfix">
   <div class="col-1-4">
   <a href="<?php the_permalink();?>"><?php the_post_thumbnail();?></a>
   </div><!-- ^ .col-1-4 END-->
   <div class="col-3-4">
   <h1 class="relPostH1"><a href="<?php the_permalink();?>"><?php the_title();?></a></h1>
   <p><?php echo mb_substr(strip_tags($post->post_content), 0, 80 ); ?><a href="<?php the_permalink(); ?>"> [記事を読む]</a></p>
   </div><!-- ^ .col-3-4 END-->
  </div><!-- ^ .relPostBox END-->

上記ソースの div.col-1-4, div.col-3-4 は、本ブログのグリッドシステムによるものです。

18行目は、アイキャッチ画像にパーマリンクを貼っている。
21行目は、記事のタイトルにパーマリンクを貼っている。

アイキャッチ画像についてはこちら:テンプレート分割の前に下準備いろいろ [WordPressテーマ作成の手順2]
パーマリンクについてはこちら:トップページ用テンプレートhome.phpを作る[WordPressテーマ作成の手順8]
記事のタイトルについてはこちら:トップページ用テンプレートhome.phpを作る[WordPressテーマ作成の手順8]

ちょっとややこしく見えるのが22行目。これは抜粋文を80字表示するための指定。
「mb_substr」関数を使っている。これは以下に詳細↓

抜粋文を出力する「mb_substr」関数について

上のソースの抜粋文(22行目)だけ抜き出してみた↓

   <p><?php echo mb_substr(strip_tags($post->post_content), 0, 80 ); ?><a href="<?php the_permalink(); ?>"> [記事を読む]</a></p>

「echo」はエコー(こだま)だが、phpでは文字列を出力する。

「substr」は文字列の一部を取り出す関数。
日本語(マルチバイト文字)を扱うなら「mb_substr」関数を使う。(mbはマルチバイトの略)

mb_substr の引数は4つ。「,(カンマ)」で区切って使う。
mb_substr(文字列, 最初の文字の位置, 文字数, エンコーディング) というカタチで使う。

  • 上記ソースの mb_substr() の最初の引数には strip_tags() が使われている。
    strip_tags() は、文字列から HTMLやPHPタグを取り除く指定。
    strip_tags($post->post_content) で「投稿記事の本文のHTMLやPHPタグを取り除いたテキスト」を指定している。
  • mb_substr() の2番目の引数は、最初の文字の位置。数字で指定。「0」で先頭の文字。
  • mb_substr() の3番目の引数は、文字数。これも数字で指定。
  • mb_substr() の最後の引数「エンコーディング」は省略でphpの内部エンコーディングを使用する。特に変える必要が無ければ省略でOK。

single.phpにパーツテンプレートを組み込む

関連記事を表示する「single_related.php」ができたので、single.phpに組み込む。

<?php get_header();?>
<!--------------MainContent--------------->
<article id="main-content">
<div class="grid"><!-- GRID MOTHER -->
<?php
if (have_posts()) : 
  while (have_posts()) :
    the_post();
    get_template_part('content');
  endwhile;
endif;
?>
<!--------------RelatedPostLinks--------------->
<div class="col-full">
  <div class="wrap-col">
    <div class="related_post">
    <h1>関連記事</h1>
    <?php get_template_part('single_related'); ?>
    </div><!-- ^ .related_post END-->
  </div><!-- ^ .wrap-col END-->
</div><!-- ^ .col-full END-->
<!-----------RelatedPostLinks END------------>
<!--------------CommentArea--------------->
<div class="col-full">
  <div class="wrap-col">
    <?php comments_template(); ?>
  </div><!-- ^ .wrap-col END-->
</div><!-- ^ .col-full END-->
<!--------------CommentArea END--------------->
</div><!-- ^ .grid = GRID MOTHER END-->
</article><!-- ^ main-content END-->
<?php get_sidebar();?>
<?php get_footer();?>

上記ソースの div.col-full, div.wrap-col は、本ブログのグリッドシステムによるものです。

ハイライト部分(14〜21行)が「関連記事」表示部分。
18行目の、get_template_part(‘single_related’) で、先ほど作ったパーツテンプレート「single_related.php」を組み込んでいる。


これで投稿用テンプレート single.php はほぼ完成。残るはコメントエリア(24〜28行目)だけ。
コメントエリアは、後日詳細をメモる予定です。

関連記事

WordPressの Embedカードのリンクを別ウィンドウで開く(PCのみ。スマホ・タブレットはそのまま)

WordPressの Embedカード(ブログカード)のリンクは、デフォルトでは同ウィンドウで開くようになっていますが、これを別ウィンドウ(別タブ)で開くように [記事を読む]

WordPressの Embedカードのスタイルを編集する方法2つ

前回の記事で、WordPress 4.5 の Embedカード(ブログカード)の「テンプレートの構成」や「HTML要素のクラス名」などを調べました。これを元に、 [記事を読む]

WordPress4.5で Embedカードの PHPファイルの構造がだいぶ変わったみたい

前回から WordPressの Embedカード(ブログカード)について調べたことをメモっています。 今回は Embedカードの PHPファイルの構造について [記事を読む]

Leave a Comment

入力エリアすべてが必須項目です。メールアドレスが公開されることはありません。

内容をご確認の上、送信してください。

^