WordPressで記事の最初の画像を取得してサムネイルサイズで表示する

最初の画像をサムネイルサイズで取得して表示する
最初の画像をサムネイルサイズで取得して表示する

WordPressのアイキャッチ設定を使わず、自動で記事最初の画像をサムネイルサイズで表示する方法を検討しました。

以前記事を書きましたがそれでは対応できない状況もあり、今回の方法はその点も克服しています。

なお記事内には2種類のコードがありますが2つ目は自分の記録用であり、ご覧頂かなくとも内容に支障はありません。

構築環境
WordPress4.7.2
PHP7.0.9
MySQL5.7.16

実現したいこと

実現したいことは以下の通りです。

  • WordPerssの記事一覧などで各記事のサムネイルを表示する
  • アイキャッチ設定は使わない
  • メディアアップローダーで追加した画像が対象
  • 記事中の最初の画像を取得
  • サムネイルサイズで出力

単に自動取得するだけではサイズが大きすぎ、画像ID順では必ずしも最初に配置した画像ではないため、最初の画像を取得してからどうにかしてサムネイルサイズを出力しようとしています。

「サムネイル」は単に「小さな見本画像」のような意味もありややこしいですが、当記事の「サムネイルサイズ」というのは、以下の意図で用いています。

  • 「管理画面 > 設定 > メディア」 の「サムネイルのサイズ」で設定されたサイズ

なお、以下が問題の残る以前の記事です。

コード1:image_downsizeを使う(class名からIDを取得)

まずは簡単と言いますか効率的かなと思われる方のコードを。前提は以下の通りです。

  • 挿入した画像のクラス名にwp-image-〇〇がある

上記の〇〇が画像IDなので、ここを利用します。
もしも今後この命名ルールが変わる場合は、後述するコード2で同じ動作が実現可能です。


function my_first_image_thumb(){
  global $post;
  $img_url = '';
  $img_id  = '';
  //デフォルト画像の設定
  $defaute_url = get_stylesheet_directory_uri(). '/images/default.png';

  //最初の画像を取得してIDを取得
  preg_match_all('/<img.+?class=".+?wp-image-(.+).*?".*?>/i', $post->post_content, $matches);
  if(isset($matches[1][0])){
    $img_id = ($matches[1][0]);
  }

  //最初の画像があれば分岐
  if(!empty($img_id)){
    //最初の画像IDからサムネイルのパスを取得してセット
    $img_url = my_wp_get_attachment_medium_url($img_id);
    //戻ってきた値がfalseならデフォルト画像を代入
    if($img_url === false){
      $img_url = $defaute_url;
    }
  } else {
    //最初の画像がない場合、デフォルト画像のパスをセット
    $img_url = $defaute_url;
  }
  return $img_url;
}

//画像IDからサムネイルサイズのパスを取得
function my_wp_get_attachment_medium_url( $id ) {
  $thumbnail_array = image_downsize( $id, 'thumbnail' );
  //idからサムネイルが取得できない場合はfalseが帰ってくるので、それで分岐
  if($thumbnail_array !== false){
    //falseでなければ値を入れて返す
    $thumbnail_path = $thumbnail_array[0];
  } else {
    //falseならfalseを返す
    $thumbnail_path = false;
  }
  return $thumbnail_path;
}

後は出力したい部分で以下のように記述すればOKです。


<img src="<?php echo my_first_image_thumb(); ?>">

image_downsize

今回は特に、image_downsize()を知れたことが大きかったです。

この関数を使えば、画像IDからサムネイルサイズのURLを得ることができます。

なお、サムネイルのサイズというのは管理画面の「メディア」で設定可能なサイズであり、投稿画面から設定するアイキャッチ画像とは関係がありません。

サムネイルサイズ自体は変更可能なので、取得に関しては柔軟な動作となっている模様です。

  • 設定したサムネイルサイズの画像が取得可能
  • image_downsize()は新たにリサイズを行わないので、以前に設定を何度も変更している場合は取れる画像のサイズが異なる

この点に関しては、以下のページに説明されていますので引用します。

Filters whether to preempt the output of image_downsize().

Passing a truthy value to the filter will effectively short-circuit down-sizing the image, returning that value as output instead.

@since 2.5.0

@param bool $downsize Whether to short-circuit the image downsize. Default false.
@param int $id Attachment ID for image.
@param array|string $size Size of image. Image size or array of width and height values (in that order).
Default ‘medium’.

デフォルトのmediumではなくthumbnailを指定した場合、wp_get_attachment_thumb_file()が使われます。

そしてwp_get_attachment_thumb_file()ではwp_get_attachment_metadata()が読み込まれており、この関数が以下の戻り値を持っています。


Array
(
  [width] => 2400
  [height] => 1559
  [file] => 2011/12/press_image.jpg
  [sizes] => Array
    (
      [thumbnail] => Array
        (
          [file] => press_image-150x150.jpg
          [width] => 150
          [height] => 150
          [mime-type] => image/jpeg
        )
      [medium] => Array
        (
          [file] => press_image-4-300x194.jpg
          [width] => 300
          [height] => 194
          [mime-type] => image/jpeg
        )

画像のsizesの部分にデータを持っているようですから、ここを目印にしてサムネイルサイズにリサイズされた各画像を取得していると思われます。

コード2:image_downsizeを使う(画像URLからIDを取得)

当初はIDをURLから取得しようとしていまして、それ用のコードが以下のものです。

まどろっこしい処理がはいっているためコード1が使えるならこちらを使う必要性はないのですが、調べる過程で知った関数もあるため記録の意味でも記載しています。


function my_first_image_thumb(){
  global $post;
  $img_url = '';
  $first_id = '';
  //デフォルト画像の設定
  $defaute_url = get_stylesheet_directory_uri(). '/images/default.png';

  //最初の画像を取得
  preg_match_all('/<img.+src=[\'"]([^\'"]+)[\'"].*>/i', $post->post_content, $matches);

  //最初の画像があれば分岐
  if(isset($matches [1][0])){
    $first_url = $matches [1][0];
    //最初の画像の画像IDを取得
    $first_id = my_get_image_id($first_url);
    //最初の画像IDからサムネイルのパスを取得してセット
    $img_url = my_wp_get_attachment_medium_url($first_id);

    //最初の画像の画像IDからサムネイルのパスが取得できず、かつ、最初の画像のファイル名にサイズを表す文字列(e.g. -300x300)があった場合
    if(empty($img_url) && preg_match_all('/(-.[0-9].+?x[0-9].+?).(png|jpg|gif)$/iu', $first_url , $matches) ) {
      //サイズを表す文字列を削除
      $first_url = str_replace($matches[1][0], '' , $first_url);
      //最初の画像の画像IDを再取得
      $first_id = my_get_image_id($first_url);
      //再取得した画像IDからサムネイルのパスを取得してセット
      $img_url = my_wp_get_attachment_medium_url($first_id);
    } else {
      //画像がうまく取得できない場合、デフォルト画像のパスをセット
      $img_url = $defaute_url;
    }
  } else {
    //最初の画像がない場合、デフォルト画像のパスをセット
    $img_url = $defaute_url;
  }
  return $img_url;
}
//記事に挿入された最初の画像のURLから画像のIDを取得する関数
function my_get_image_id($image_url) {
  global $wpdb;
  $attachment = $wpdb->get_col($wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE guid='%s';", $image_url ));
  if(isset($attachment[0])){
    return $attachment[0];
  }
}
//画像のIDから、記事に挿入された最初の画像のサムネイルのサイズのURLを取得する関数
function my_wp_get_attachment_medium_url( $id ) {
  $medium_array = image_downsize( $id, 'thumbnail' );
  $medium_path = $medium_array[0];
  return $medium_path;
}

表示する方法はコード1と同じ(関数名を同じ名称にしたため)で以下の通りです。


<img src="<?php echo my_first_image_thumb(); ?>">

肝である「画像IDから画像のURLを取得」と「画像のURLからサムネイルのサイズのURLを取得」などは以下のサイトを参考にさせていただきました。

手こずったのは、挿入した画像がフルサイズではない場合、「-600×400.jpg」のようにサイズに関連したファイル名が取得されてしまう点です。

画像のIDを手に入れるためにはこの文字列を取除かねばならならず(取除かないでも良い方法があるかもしれませんが)、以前の仕組みでもこの除去部分がうまくできませんでした。

流れ

概ね以下のようなことをしています。

  1. 記事中の最初の画像を取得
  2. 最初の画像のURLから画像IDを取得
  3. 画像IDからサムネイルサイズの画像のURLを取得

画像ID順で取得する場合

試していませんが、記事に挿入した画像のなかで画像IDの一番若いものを取得する場合は、以下のページのコードで実現できるかと思います。

なお、画像ID順と記事内の画像配置順が一致するとはかぎりませんので、意図しない画像がでてくる可能性はあると考えています。

wp_get_attachment_imageを使う

この記事を書いた後で調べ直した際に気がつきましたが、image_downsize()ではなくwp_get_attachment_image()でも同じ事ができるのだと思います。

詳細は以下をご覧いただければと思いますが、画像のIDさえ取れてしまえば使える関数は多いのかもしれません。

結び

当初は長めのコードでしたが、クラス名からIDの取得ができると気がついたので最終的には短くできました。

とはいえ恐らくもっとも効率的なの、このために作られた(と思うのですが)アイキャッチ設定を用いることではあります。

当記事のコードでもループ内でまわす数だけ以下の処理を行っており、その分表示が遅くなる可能性もありますので。

  • 記事本文を取得
  • preg_match_all()を使い正規表現で画像を取得
  • image_downsize()でIDからサムネイルサイズのパスを取得

アイキャッチ設定の画像であれば正規表現で画像を検索する必要もありませんし、処理が軽いのではと思います。

6人がこの記事を評価

役に立ったよという方は上の「記事を評価する」ボタンをクリックしてもらえると嬉しいです。

連投防止のためにCookie使用。SNSへの投稿など他サービスとの連動は一切ありません。

コメント欄