ジェネリックBeansへの道(徒労編)

前のテーマ「Beans」の投稿一覧ページでは、「続きを読む」より前の本文をそのまま表示していた。また、本文に続きがない場合は「Read More」ボタンが表示されなかった。

今回はカスタマイズしたテーマをよりBeansに近づけるために、アイキャッチが設定されていない投稿にもサムネイル画像を表示させる方法についてまとめてみる。

この記事は、見てのとおり徒労に終わりました。

詳細は次の記事へ。

投稿一覧ページについて、アイキャッチ画像を設定した記事は今の状態で申し分ない。でもアイキャッチ画像を設定しなかったときも記事の最初の画像をサムネイルとして表示させたい。

ということで紆余曲折を経て見つけた記事がこちら。

WordPressで記事内の最初の画像をアイキャッチ代わりに使う方法

ここに辿り着くまでめちゃ大変だったんだけど、「chatch_that_image()」で検索すると似たような記事がたくさん出てきた。これはどうも、昔(2010年頃)誰かが作ったユーザー関数らしい。

これをカスタマイズして使いたいので、調べたことを色々書きながらコードを解読していく。

アレコレする前に、まずはプログラミング用語の復習から。

戻り値と引数

WordPressのWikiを見ているとよく出てくるプログラミング用語、「戻り値」と「引数」について思い出す。ああ、そんなのあったよね。あれでしょ。あれ。

戻り値
プログラム中で呼び出された関数が処理を終了するとき、呼び出し元に対して返す値。

引数
呼び出し元から関数に対して渡すパラメータのこと。

そうそう「足し算する」という関数に「7と13」という引数を渡すと「20」という戻り値を返す、的なあれ。

STEP1:現在のテーマが行っている処理を解読してみる

入門編として、最初は現在のテーマが行っている処理を解読してみる。

現状では /loop-templates/content.phpget_the_post_thumbnail 関数を使ってアイキャッチ画像のHTMLのimg要素(<img src=”~~~” ~~~>)を出力している。これはUnderstrapテーマに入っているデフォルト状態のまま。

<?php echo get_the_post_thumbnail( $post->ID, 'large' ); ?>

get_the_post_thumbnail 関数の用法は次のとおり。

<php echo get_the_post_thumbnail( $post_id, $size, $attr ); ?>

$post_id
対象の投稿のID(整数)。初期値は「現在の投稿のID」(null)。

$size
画像のサイズ。特定の文字列(’thumbnail’, ‘medium’, ‘large’, ‘full’など)かピクセルで指定する。

$attr
アイキャッチ画像を表示するHTMLタグに含める属性 / 値を配列で記述。
付けても付けなくてもいい。今回は付けていない。

これで、 対象とした投稿のアイキャッチ画像のimg要素(<img src=”~~~” ~~~>) がHTMLの中に出力される。

次に、function.php で続きへのリンクを挿入している。これはこちらの記事からコピペした内容。
今回の目的とはあまり関係ないけど、今後のために解読していく。

//投稿一覧ページのアイキャッチ画像に投稿をリンク
function myautolink_featured_image( $html, $post_id, $post_image_id ) {
    if (! is_singular()) {
        $html = '<a href="' . get_permalink( $post_id ) . '"
                  title="' . esc_attr( get_the_title( $post_id ) ) . '"
                  >' . $html . '</a>';
        return $html;
    }
    else {
        return $html;
    }
}
add_filter( 'post_thumbnail_html', 'myautolink_featured_image', 10, 3 );

これを2つに分割して解読していこう。まずは前半部。

function myautolink_featured_image( $html, $post_id, $post_image_id ) {
    if (! is_singular()) {
        $html = '<a href="' . get_permalink( $post_id ) . '"
              title="' . esc_attr( get_the_title( $post_id ) ) . '"
              >' . $html . '</a>';
        return $html;
    }
    else {
        return $html;
    }
}

ユーザー定義関数を宣言するPHPの構文「function」で、「myautolink_featured_image」(実はこの名前はなんでもいい)という関数を定義する。

関数 「myautolink_featured_image」 とは以下のようなものである。

この関数は「$html」、「$post_id」、「$post_image_id」の3つの引数を使う。
個別の投稿ページではないとき( !is_singular() )、変数「$html」にHTMLの a要素「<a href=”~~~.html” title=”(リンク先の補足的な情報)”>」を代入する。個別の投稿ページの場合は、何もしない。

次に後半部。

add_filter( 'post_thumbnail_html', 'myautolink_featured_image', 10, 3 );

こうして定義された関数 「myautolink_featured_image」 を実行する。この関数の優先度は10であり、wordpressが定義しているフック「post_thumbnail_html」に渡す引数は3つである。

優先度は、小さいものから実行される(直感と合わねえなあ)ので注意。

ここで作ったユーザー定義関数は「フックをセットする関数のための関数」、ということになるみたい。

フックをセットする関数( add_filter() )というのはWordpressが定義した関数で、「ユーザーが”何かしらの処理”をしたいとき、関数と引数を適当に渡したらいい感じに実行してくれるおっさん」みたいなイメージ。多分。
じゃあフックというのは………おっさんの手のひらみたいなものじゃないかと思う。多分。

参考:フックって?WordPressのカスタマイズ方法を説明します!

pose_thumbnail_html 」フックについて:post_thumbnail_htmlフックを使って、画像周りを一括管理する方法

STEP1 が長くて脱線したけど、本来の「やりたいこと」の話に戻る。

STEP2:アイキャッチ画像の有無に応じた処理を実行する

<?php if (has_post_thumbnail()) :
       echo get_the_post_thumbnail( $post->ID, 'large' ); ?>
<!-- アイキャッチ画像があればそれを表示する関数で処理 -->

<?php else : ?>
<!-- そうでない場合は... -->

<img src="<?php echo catch_that_image(); ?>" class="wp-post-image">
<!-- catch_that_img 関数で取得した文字列を画像のURLとして出力する -->

<?php endif ; ?>
<!-- おわり。 -->

最初に has_post_thumbnail 関数でアイキャッチ画像の有無を調べ、結果に応じた関数でそれぞれ処理を行う。

has_post_thumbnail 関数の用法は以下のとおり。

<? php has_post_thumbnail( $post_id ); ?>

引数:
$post_id
対象の投稿のID(整数)。初期値は「現在の投稿のID」(null)。

戻り値
アイキャッチ画像が付いていれば true を、付いていなければ false を返す。

アイキャッチ画像がある場合は、STEP1 と同様に get_the_post_thumbnail 関数でアイキャッチ画像を表示させる。

STEP3:アイキャッチの代わりの画像を表示させる関数を解読する

次に、STEP2で調べた結果アイキャッチ画像がなかった場合に使うユーザー定義関数「catch_that_image」を考える。

//アイキャッチ画像がない場合に代替の画像(記事内の画像 or デフォルト画像)を表示する
function catch_that_image() {
    global $post, $posts;
    $first_img = '';
    ob_start();
    ob_end_clean();
    $output =
        preg_match_all('/<img.+src=[\'"]([^\'"]+)[\'"].*>/i',
        $post->post_content, $matches);
    $first_img = $matches [1] [0];
    if(empty($first_img)){
        // 記事内で画像がなかったときのためのデフォルト画像を指定
        $first_img = "https://nobodys-rhapsody.sakura.ne.jp/banner/intro.png";
    }
    return $first_img;
}

最初に変数「 $first_img」 を宣言する。ここには後で投稿最初の画像のURLが入るが、今は空っぽ。

次に、PHPの関数 preg_match_all() を使って投稿内の<img>タグを検索し、一番最初に引っかかった「src=”~~”」の中身(=最初の画像のURL)を $first_img に代入する。

投稿内に画像が見つからなかったら( empty($first_img) )、$first_img の中身を指定したデフォルト画像のURLにして、$first_img の値とする。

……ということらしい。よく分からんおまじないが多いけど。(おまじないなくても動いた。)

というわけで無事、アイキャッチ画像の代わりの画像URLの取得が終わったので、content.php に戻って代替画像のURLを出力し、仕上げに見た目を整えるためのクラス(wordpressが自動でアイキャッチ画像につけるもの)をひっつけて、欲しかった<img>タグが完成する。

<img src="<? php echo catch_that_image(); ?>" class="wp-post-image">

しかし、投稿内に画像がないときは何もしたくないんだけど……ここからさらにカスタマイズできるかな?