utility
WordPressでfeedから連携させる際にあると便利なコト
作成日: 2025年5月6日
以前複数サイトのfeedをひとまとめにするってのを書いたが、WP関連(CMSならなんでもいいけど)で、CMSによる特定のタグ付与で、そのタグのついた投稿フィードを抽出し、纏めるもの。
条件としては、これを実行するための取得元feedのitem titleに判別のためのタグを含んでいること。
<?php
date_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使って連携投稿自動化ってのが趣旨で、レアケースでしか使わないが備忘。