Steamer Lane Studio技術備忘録ユーティリティ

WordPressでfeedから連携させる際にあると便利なコト

utility WordPressでfeedから連携させる際にあると便利なコト
作成日: 2025年5月6日

以前複数サイトのfeedをひとまとめにするってのを書いたが、WP関連(CMSならなんでもいいけど)で、CMSによる特定のタグ付与で、そのタグのついた投稿フィードを抽出し、纏めるもの。
条件としては、これを実行するための取得元feedのitem titleに判別のためのタグを含んでいること。

<?phpdate_default_timezone_set('UTC');header('Content-Type: application/rss+xml; charset=utf-8');

echo '<?xml version="1.0" encodig="UTF-8"?>' . PHP_EOL;echo '<rss version="2.0"xmlns:content="http://purl.org/rss/1.0/modules/content/"xmlns:media="http://search.yahoo.com/mrss/"xmlns:atom="http://www.w3.org/2005/Atom">' . PHP_EOL;

echo '<channel>' . PHP_EOL;echo '<title>FEED TITLE</title>' . PHP_EOL;echo '<link>サイトURL</link>' . PHP_EOL;echo '<description>説明</description>' . PHP_EOL;echo '<atom:link href="FEED URL" rel="self" type="application/rss+xml" />' . PHP_EOL;echo '<language>ja</language>' . PHP_EOL;

function fetch_feed($url) {$rss = @simplexml_load_file($url);if ($rss === false) {error_log("Failed to load feed: $url");return null;}return $rss;}

function combine_feeds($feed_urls) {$combined_entries = [];foreach ($feed_urls as $feed_url) {$feed = fetch_feed($feed_url);if ($feed === null) {continue;}foreach ($feed->channel->item as $item) {// feed2の場合、タイトルに特定文字列がないアイテムを除外if ($feed_url === '取得元FEEDURL2') {$title = (string)$item->title;if (strpos($title, '取得元FEED上のトリガーとなるタグ') === false) {continue; // タイトルに指定文字列がない場合はスキップ}}$combined_entries[] = $item;}}usort($combined_entries, function($a, $b) {$a_time = $a->pubDate ? strtotime($a->pubDate) : 0;$b_time = $b->pubDate ? strtotime($b->pubDate) : 0;return $b_time - $a_time;});return $combined_entries;}

$feed_urls = array('取得元FEED1URL','取得元FEED2URL',);

$combined_entries = combine_feeds($feed_urls);

$max_items = 999;$item_count = 0;

foreach ($combined_entries as $entry) {if ($item_count >= $max_items) {break;}

$image_url = '';if ($entry->children('media', true)->content) {$image_url = (string)$entry->children('media', true)->content->attributes()->url;} else {$contents = $entry->children('content', true)->encoded;foreach ($contents as $content) { // 複数 <content:encoded> をループif (preg_match('/<img[^>]+src=["\'](.*?)["\']/i', $content, $match)) {$image_url = $match[1];break; // 最初に見つかった画像を使用}}}if (empty($image_url)) {error_log("No image found for entry: " . $entry->title);continue;}

echo '<item>' . PHP_EOL;$title = str_replace("\n new line", " ", $entry->title);echo "<title><![CDATA[{$title}]]></title>" . PHP_EOL;$pubDate = $entry->pubDate;$timestamp = $pubDate ? strtotime($pubDate) : time(); // pubDateがない場合は現在時刻$pubDate = gmdate('D, d M Y H:i:s T', $timestamp);echo "<pubDate>{$pubDate}</pubDate>" . PHP_EOL;echo "<link>{$entry->link}</link>" . PHP_EOL;$guid = $entry->guid ? $entry->guid : $entry->link;echo "<guid isPermaLink=\"false\">{$guid}</guid>" . PHP_EOL;$description = mb_convert_encoding($entry->description ?? '', 'UTF-8', 'auto');$description = mb_substr($description, 0, 100, 'UTF-8') . '...';echo "<description><![CDATA[{$description}]]></description>" . PHP_EOL;echo "<enclosure url=\"{$image_url}\" type=\"image/jpeg\" />" . PHP_EOL;echo "<media:content url=\"{$image_url}\" medium=\"image\" />" . PHP_EOL;

// content:encodedを取得し、不要なタグを削除$content_encoded = $entry->children('content', true)->encoded;$content_encoded = preg_replace(array('/<iframe.*?<\/iframe>/is', '/<p><script.*?<\/script>/is', '/<script.*?<\/script>/is'), '', $content_encoded);

// imgタグとaタグを含むすべてのHTMLタグを削除し、プレーンテキスト化$content_encoded = strip_tags($content_encoded);

// 改行文字を削除し、文字数制限+「Learn more」を追加$content_encoded = mb_substr(str_replace(array("\r", "\n"), '', $content_encoded), 0, 800);//$content_encoded .= '... Learn more';

echo "<content:encoded><![CDATA[{$content_encoded}]]></content:encoded>" . PHP_EOL;

echo '</item>' . PHP_EOL;$item_count++;}

echo '</channel>' . PHP_EOL;echo '</rss>' . PHP_EOL;?>

複数フィードを取得してIFTTT使って連携投稿自動化ってのが趣旨で、レアケースでしか使わないが備忘。