WordPress標準のRSSブロックは、アイキャッチ画像を含むリストを表示させることができません。
これは、フィードを出力する側(情報元のサイト)で、WordPress標準のRSSフィード出力ではアイキャッチ画像の情報を出力しないようになっていることから、別のWordPressから情報を取得して表示させるという前提とした時に取得できないものを出力する必要はないだろうというところから来ているのだと想像します。
これも想像ですが、もしもRSSブロックで画像を取得して出力できるようにしていた場合に、情報元のサイトのフィードに画像がなかったら当然ながら表示されないわけで、これを不具合ととらえる人がいるからという理由もあるのでしょう。
そこで今回は、以下のようなことをする方法をコード実装例として自身のカスタマイズ備忘録を兼ねて紹介します。
本ページの作成にあたり、以下のページなどを参考にさせていただきました。
- ブログ新着記事を外部サイトにサムネイル付きで一覧表示する方法【WordPress】
- rssフィードでサムネイル付きの新着情報を表示させる方法
- wordpressでRSSを使って複数のブログをまとめて時系列に一覧表示する方法
そして、参考ページの手法を基に、コードについては極力コメントなどを入れて分かりやすくなるようにし、汎用性を持たせるよう以下のような仕様にしています。
- アイキャッチ画像を含めてフィード出力するようにする【情報元サイト側】
- 1のサイトのフィードをアイキャッチ画像を含めてカード表示する【一覧表示サイト側】
- ショートコードでどこにでも設置できるようにする
- パラメーターで表示数を指定できるようにする
- パラメーターで複数のURLを指定し、それらをまとめて時系列で表示させるようにする
- 「アイキャッチ画像」「ページタイトル」「抜粋文」「公開日」「カテゴリー」を表示する
- アイキャッチ画像がない場合(設定されていないorフィードに出力されていない)場合には、代替画像を表示させる
- 公開日はサイトのタイムゾーンに合わせて表示させるようにする
- ショートコードでどこにでも設置できるようにする
特に赤字にしている項目は、需要が多いものの、同様のカスタマイズ情報が掲載されているページでは実装されていないことが多いのではないでしょうか?
また、コード紹介記事では省略されがちなセキュリティ関連の記述も極力追加し、コピペでも安全性を保てるようにしています(確実に安全という保障はできません)。
本ページで紹介するコードは、WordPressで運営している他のサイトのRSSフィード情報を取得してカード表示させるというものです。他のツールで出力されたRSSフィード情報を利用する際にはうまく動作しない可能性がありますのでご注意ください
なお、ここまで読んで恐らく勘違いされる方はいないと思いますが、そもそもアイキャッチ画像を取得表示する必要がない場合は、標準のRSSブロックを使えばよいので、この方法を用いる必要はありません。
表示サンプル
以下が本ページのコードを使用した場合の表示サンプルです(他にフィードを取得するサンプルがないため、このサイトのRSSフィードを取得し、2件表示させています)
本ページ掲載のコードを使用するときは
本ページで掲載しているコードは、以下に了承した上で使用ください
- コードは商用・非商用問わず自由に使っていただいて構いませんが、コード追加による不具合やトラブルが発生しても当方では一切責任を負いません
- コードは有効化しているテーマのfunctions.php、style.cssなどへ追加することで機能します。それらのファイルへの変更を行うことに不安のある方は使用しないでください
- コードは本ページの公開日時点で私の環境において動作したものです。WordPressバージョン他環境の違いによって動作しないことがあります
- コードは、セキュリティ、コードの正確さなどにおいて完全なものではありません。中には紹介するコードを簡略化するために省略している部分があるものもありますので、ご自身でコードを十分に検証し、必要な部分の編集を行った上で使用するようにしてください
- 掲載しているのは参考コードです。自身の環境に合わせるための編集はご自身で対応いただく必要があります(コメント欄等から質問いただいても基本回答は致しません)
- 掲載しているコードの転載を禁じます(SNSで紹介いただいたり、本ページへのリンクを張っていただくことは大歓迎です)
【前準備】フィードを出力する側(情報元サイト)の処理
冒頭でも書いたように、WordPress標準のRSSフィード出力では、アイキャッチ画像を出力していないので、以下のコードを有効化しているテーマのfunctions.phpへ追加して、抜粋や本文の冒頭へアイキャッチ画像のタグを出力する必要があります。
/* フィードの抜粋や本文の冒頭にアイキャッチ画像の情報を追加 */
function pwcn_rss_post_thumbnail($content) {
//出力するメディアのサイズ指定
//thumbnail,medium,large,fullなどから指定
$size = 'thumbnail';
global $post;
if(has_post_thumbnail($post->ID)) {
//よくあるサンプルコードではpタグで囲んでいるけど、囲まずに出力
//$content = '<p>' . get_the_post_thumbnail($post->ID,'thumbnail') . '</p>' . $content;
$content = get_the_post_thumbnail($post->ID, $size ) . $content;
}
return $content;
}
add_filter('the_excerpt_rss', 'pwcn_rss_post_thumbnail');
add_filter('the_content_feed', 'pwcn_rss_post_thumbnail');
WordPressの表示設定の「フィードの各投稿に含める内容」で、「全文を表示」を選択した際に本文冒頭に画像を出力するために「the_content_feed」フックを、「抜粋のみ」を選択した際の抜粋文冒頭に画像を出力するために「the_excerpt_rss」フックを使います
コード中の「$size = ‘thumbnail’;」の「thumbnail」を変更すると、サムネイルサイズの画像以外のサイズの画像タグを出力できますが、大きな画像を使う必要はないと思いますので、そのままにするか、「medium」あたりを選択するといいでしょう
詳しく調べていくと、コンテンツの冒頭に出力する他にも出力する方法があるようですが、今回は取得する側のコードとの兼ね合いや汎用性から上記コードを追加しています。
フィード情報を取得して表示する側のサイトに表示できる件数は、フィードを出力する側のサイトで設定した件数が条件となりますので、運営状況に応じて調整してください
フィードを取得してアイキャッチ画像付きリストを表示させる方法
アイキャッチ画像がない場合の代替画像を用意する
このページに掲載しているコードでは、フィードを取得した際にアイキャッチ画像のないコンテンツに対して、代替画像を表示するようにしています。
代替画像のサイズは150x150pxにすると最適化されるようにコードを書いていますので、そのサイズの画像を「noimage.jpg」というファイル名で用意し、テーマフォルダ内へアップロードしておきます。
紹介するコードでは、代替画像を用意しない場合で、フィードコンテンツに画像がない場合には、タイトルがカード幅いっぱいに表示されるようにしています
サニタイズ関数の用意
カード本文として取得・出力させる内容のサニタイズ(無害化)を行うため、紹介するコードでは、以下のサニタイズ関数を使用しています。有効化しているテーマのfunctions.phpへ以下を追加してください。
/*** サニタイズ関数 ***/
/* HTMLタグ */
if ( !function_exists( 'pwcn_sanitize_html_tags' ) ){
function pwcn_sanitize_html_tags( $input ){
$allowed_tags = array(
'a' => array(
'class' => array(),
'href' => array(),
'rel' => array(),
'title' => array(),
),
'aside' => array(
'class' => array(),
'style' => array(),
),
'b' => array(),
'blockquote' => array(
'cite' => array(),
),
'br' => array(),
'button' => array(
'id' => array(),
'class' => array(),
'style' => array(),
),
'cite' => array(
'title' => array(),
),
'code' => array(),
'del' => array(
'datetime' => array(),
'title' => array(),
),
'dd' => array(),
'div' => array(
'id' => array(),
'class' => array(),
'title' => array(),
'style' => array(),
),
'dl' => array(),
'dt' => array(),
'em' => array(),
'h1' => array(
'class' => array(),
'style' => array(),
),
'h2' => array(
'class' => array(),
'style' => array(),
),
'h3' => array(
'class' => array(),
'style' => array(),
),
'h4' => array(
'class' => array(),
'style' => array(),
),
'h5' => array(
'class' => array(),
'style' => array(),
),
'h6' => array(
'class' => array(),
'style' => array(),
),
'i' => array(),
'img' => array(
'alt' => array(),
'class' => array(),
'height' => array(),
'src' => array(),
'width' => array(),
),
'li' => array(
'class' => array(),
'style' => array(),
),
'nav' => array(
'id' => array(),
'class' => array(),
'style' => array(),
),
'ol' => array(
'class' => array(),
'style' => array(),
),
'p' => array(
'class' => array(),
'style' => array(),
),
'q' => array(
'cite' => array(),
'title' => array(),
),
'section' => array(
'id' => array(),
'class' => array(),
'style' => array(),
),
'span' => array(
'class' => array(),
'title' => array(),
'style' => array(),
),
'strong' => array(),
'ul' => array(
'class' => array(),
'style' => array(),
),
);
return wp_kses($input, $allowed_tags);
}
}
このサニタイズ関数は、取得する文字列の中にある特定のhtmlタグを許可し、それ以外のタグ(例えばスクリプトタグなど)は単純な文字列へ変換して動作しないようにするためのものです。
本ページのコード以外でカスタマイズコードを追加した場合に、以下のように記述することで同様のサニタイズができますので、必要な時に利用するといいでしょう。
$text = '特定のHTMLタグのみを通すサニタイズ処理が必要な文字列';
pwcn_sanitize_html_tags($text);
このサニタイズ処理が不要な場合には、次項のプログラムコード中にある「pwcn_sanitize_html_tags(〇〇);」の赤文字部分を削除してください。削除せずに次項のプログラムコードをコピペして保存するとエラーになりますのでご注意ください
プログラムコード(PHP)
以下がプログラムコードです。有効化しているテーマのfunctions.phpへ追加します。
function pwcn_feed_list_with_thumb_multi($atts) {
/* ショートコードパラメーターの設定 */
$atts = shortcode_atts(
array(
'url' => '',
'num' => '',
), $atts);
/* xmlファイルからコンテンツを抽出 */
//コンテキストの生成とSSL証明書のチェック
$context = stream_context_create(array(
'http' => array(
'method' => 'POST',
'header' => 'Content-Type: application/json'
),
//SSL証明書の確認
'ssl' => array(
'verify_peer' => true,
'verify_peer_name' => true,
'allow_self_signed' => false,
'capture_peer_cert' => true,
'capture_peer_cert_chain' => true,
'verify_depth' => 5,
'CN_match' => 'example.com',
'disable_compression' => true,
'SNI_enabled' => true,
'ciphers' => 'HIGH'
),
//SSL証明書のチェックに失敗しても処理を続行
'http' => array(
'ignore_errors' => true
)
));
//パラメーターからURLを取得
$urls = $atts['url'];
//$feedsを初期化
$feeds = array();
//コンマ区切りのURLを配列として変換
if (!empty($urls)) {
$feeds = explode(',', $urls);
} else {
$feeds = array();
}
// urlパラメーターが存在しない場合は空文字列を返して処理を終了します(エラー回避)
if (empty($feeds)) {
return '';
}
//$marged_feedを初期化
$merged_feed = array();
//URL分だけ情報を取得
foreach ($feeds as $feed_url) {
$content = file_get_contents($feed_url, false, $context);
$x = new SimpleXmlElement($content);
foreach ($x->channel->item as $entry) {
$merged_feed[] = array(
'title' => (string) $entry->title,
'link' => (string) $entry->link,
'date' => (string) $entry->pubDate,
'desc' => (string) $entry->description,
'cat' => (string) $entry->category
);
}
}
//取得したすべての情報を日付でソート
usort($merged_feed, function ($a, $b) {
return strtotime($b['date']) - strtotime($a['date']);
});
/* カードの出力 */
// 表示数の設定
$number = $atts['num'];
if(!empty($number)){
$num = absint($number);
}else{
$num = absint('5');
}
//出力のバッファリング開始(コンテンツ内へ出力)
ob_start();
//開始タグの出力
echo '<article class="pwcn-feed-list"><ul>';
// 表示件数を初期化
$count = 0;
//内容を整理してリスト出力
foreach ($merged_feed as $item) {
// カウンターが指定した件数以上の場合はループを終了
if ($count >= $num) { // カウンターが指定した件数以上の場合はループを終了
break;
}
//出力内容の整理、サニタイズ
//画像
$description = $item['desc'];
$imgurl = preg_match('/<img[^>]+src=[\'"]([^\'"]+)[\'"][^>]+\>/i', $description, $imgurls);
//出力側のサイトでアイキャッチ画像が出力されていない場合に「noimage.jpg」を出力
$noimage_url = get_theme_file_uri('/noimage.jpg');
$noimage_tag = '<img src="'.$noimage_url.'" width="150" height="150" alt="no-image">';
if(preg_match('/<img[^>]+src=[\'"]([^\'"]+)[\'"][^>]+\>/i', $description)){
$eyecatch = ha_sanitize_html_tags($imgurls[0]);
}else{
$eyecatch = ha_sanitize_html_tags($noimage_tag);
}
//リンクURL
$link = esc_url($item['link']);
//タイトル
$title = esc_attr($item['title']);
//カテゴリー
$category = esc_attr($item['cat']);
//日付
$date = $item['date'];
$dateTimeFormat = get_option( 'date_format' );
$date = esc_attr(date_i18n($dateTimeFormat, strtotime($date)));
//抜粋
$img_pattern = '/<img[^>]+src=[\'"]([^\'"]+)[\'"][^>]+\>/i';
$des_content = pwcn_sanitize_html_tags(preg_replace($img_pattern,'',$description));
//内容の出力
echo '<li>';
echo '<a href="' . $link . '" target="_blank">';
echo $eyecatch;
echo '<p class="pwcn-feed-list-title">'.$title.'</p>';
echo '<p class="pwcn-feed-list-category">' . $category . ' / ' . $date .'</p>';
echo '<p class="pwcn-feed-list-des">' . $des_content . '</p>';
echo '</a></li>';
//件数カウントを追加
$count++;
//1件分のリスト処理終了
}
echo '</ul></article>';
//出力のバッファリング終了
$output = ob_get_clean();
return $output;
}
add_shortcode('pwcn-feed-list-multi', 'pwcn_feed_list_with_thumb_multi');
諸所にコメントを入れていますので、どのようなことをしているのかはご覧いただければ分かると思いますので詳細な説明は省きます。
スタイルコード(CSS)
以下が前項のプログラムに応じたスタイルコードです。有効化しているテーマのstyle.cssへ追加します。
.pwcn-feed-list a {
text-decoration: none;
}
.pwcn-feed-list li {
border: 1px solid #ccc;
border-radius:4px;
padding: 12px;
margin: 1rem 0;
}
.pwcn-feed-list ul {
list-style: none;
padding-left: 0;
}
.pwcn-feed-list img {
float: left;
width: 100px;
height: 100px;
margin-right: 12px;
border:1px solid #eee;
border-radius:4px;
}
.pwcn-feed-list img:after {
clear: both;
}
p.pwcn-feed-list-title {
font-size: var(--wp--preset--font-size--large);
margin-top: 0;
}
p.pwcn-feed-list-category {
font-size: var(--wp--preset--font-size--small);
text-align: right;
}
ショートコードの挿入
ここまで問題なくコードの追加ができたら、以下のショートコードをフィードリストを表示させたい場所へ挿入します。
[pwcn-feed-list-multi url="" num=""]
「url=””」の「””」の間にフィードURLを入力します。
例)https://example.com/feed/
複数のフィードURLを含める場合には、URLの間をカンマ(,)で区切ります。
「num=””」の””の間に半角数字を入力すると、リスト出力される件数を指定できます(指定しない場合には5件表示されます)
表示件数は、取得するサイトのフィードの総数が上限となります。例えばAというサイトの「表示設定」で指定している「RSS/Atom フィードで表示する最新の投稿数」が5件、Bというサイトのそれが5件で、2つのサイトのRSSフィードを取得した場合、合計は10件となり、numパラメーターに10以上の数字を入れても10件のみの表示となります
【番外編】画像がいらない時は
ここまでは、文章で表すと、複数のサイトのRSSフィードを取得して時系列で並び替え、元サイトのフィードの抜粋に出力したアイキャッチ画像のタグを分解(抽出)して、カード形式にして表示するということをしてきました。
前述したコードをご覧いただいて分かる通り、結構複雑なことをしています。
この機能から一歩下がって?、WordPressの標準RSSブロックでは複数のRSSフィードをまとめて時系列に並び替えることができないから、その部分だけを実現して、日付とタイトルだけがリスト化されればいいというユースケースもあるのではないかと思い、最後に番外編として参考コードを載せておきます。
コード例では、2列表示させた時に1列目では1~5件を、2列目では6~10件をといった形で表示させることができるよう、オフセット値が指定できるようにしています
コードを見比べて、どの部分が不要となるのかを検証してみるのも面白いかも知れません。
ちなみにこのコードで本サイトのフィードを2件オフセットさせて表示したのがこちら。
前述したコードとの衝突や重複などを避けるため、ユーザー定義関数やCSSクラスを変更していますので、前述のコードとの併用が可能となるようにしています。
function pwcn_simple_feed_list_multi($atts) {
/* ショートコードパラメーターの設定 */
$atts = shortcode_atts(
array(
'url' => '',
'num' => '',
'offset' => '',
), $atts);
/* xmlファイルからコンテンツを抽出 */
//コンテキストの生成とSSL証明書のチェック
$context = stream_context_create(array(
'http' => array(
'method' => 'POST',
'header' => 'Content-Type: application/json'
),
//SSL証明書の確認
'ssl' => array(
'verify_peer' => true,
'verify_peer_name' => true,
'allow_self_signed' => false,
'capture_peer_cert' => true,
'capture_peer_cert_chain' => true,
'verify_depth' => 5,
'CN_match' => 'example.com',
'disable_compression' => true,
'SNI_enabled' => true,
'ciphers' => 'HIGH'
),
//SSL証明書のチェックに失敗しても処理を続行
'http' => array(
'ignore_errors' => true
)
));
//パラメーターからURLを取得
$urls = $atts['url'];
//$feedsを初期化
$feeds = array();
//コンマ区切りのURLを配列として変換
if (!empty($urls)) {
$feeds = explode(',', $urls);
} else {
$feeds = array();
}
// urlパラメーターが存在しない場合は空文字列を返して処理を終了します(エラー回避)
if (empty($feeds)) {
return '';
}
//$marged_feedを初期化
$merged_feed = array();
//URL分だけ情報を取得
foreach ($feeds as $feed_url) {
$content = file_get_contents($feed_url, false, $context);
$x = new SimpleXmlElement($content);
foreach ($x->channel->item as $entry) {
$merged_feed[] = array(
'title' => (string) $entry->title,
'link' => (string) $entry->link,
'date' => (string) $entry->pubDate
);
}
}
//取得したすべての情報を日付でソート
usort($merged_feed, function ($a, $b) {
return strtotime($b['date']) - strtotime($a['date']);
});
/* リストの出力 */
// 表示数の設定
$number = $atts['num'];
if(!empty($number)){
$num = absint($number);
}else{
$num = absint('5');
}
// オフセットの設定
$offset = $atts['offset'];
if(!empty($offset)){
$offset = absint($offset);
}else{
$offset = absint('0');
}
//出力のバッファリング開始(コンテンツ内へ出力)
ob_start();
//開始タグの出力
echo '<article class="pwcn-simple-feed-list"><ul>';
// 表示件数を初期化
$count = 0;
//内容を整理してリスト出力
foreach ($merged_feed as $item) {
// カウンターが指定した件数以上の場合はループを終了
if ($count >= $num) { // カウンターが指定した件数以上の場合はループを終了
break;
}
//オフセットより前の項目はスキップする
if ($count < $offset) {
$count++;
continue;
}
//リンクURL
$link = esc_url($item['link']);
//タイトル
$title = esc_attr($item['title']);
//日付
$date = $item['date'];
$dateTimeFormat = get_option( 'date_format' );
$date = esc_attr(date_i18n($dateTimeFormat, strtotime($date)));
//内容の出力
echo '<li>';
echo '<a href="' . $link . '" target="_blank">';
echo '<p class="pwcn-simple-feed-list-title">'.$title.'-' . $date .'</p>';
echo '</a></li>';
//件数カウントを追加
$count++;
//1件分のリスト処理終了
}
echo '</ul></article>';
//出力のバッファリング終了
$output = ob_get_clean();
return $output;
}
add_shortcode('pwcn-simple-feed-list-multi', 'pwcn_simple_feed_list_multi');
ショートコードは以下を使用してください。
[pwcn-simple-feed-list-multi url=”” num=”” offset=””]
コメントを残す