If you have a wordpress blog (or any other kind of website), you might come across this problem some day: you want to fetch multiple RSS feeds and merge their entries in chronological order into one feed. Don’t panic, I might have found the solution for you. On my WordPress blog you can see I have RSS feeds for the blog posts, the user comments and now also the shoutbox entries. Most visitors were not aware of the different RSS feeds on my page (and who could blame them?), so I decided to combine them all into one big feed. Here is what you need to do…

  • All you need is a library (MagpieRSS) for RSS parsing and a class called FeedCreator to build the new feed. I provide all of those for download here.
  • Extract the tar into a subdirectory on your website (i used http://zerga.dyndns.org/rss for that).

Then you want to create an index.php file in the same directory and paste the following code into it. This file will contain all the configuration in its top couple of lines, followed by the logic to iterate through all feeds and aggregate them into one. Let’s go a bit into the configuration now, shall we?

  • $DOMAIN_NAME has to be set to the base of your URL.
  • $FEED_URL indicates the location of the created index.php relative to $DOMAIN_NAME
  • $RSS_CACHE is the location of the cache
  • $RSS_CACHE_EXP is the time between two generations of the feed

This is cool, because depending on the amount of feeds you want to combine, this might take a few seconds and you don’t want people who are downloading your feed to wait for too long.

  • $FEED_LIST contains all locations (URLs) of the feeds you want to combine.

By default, I am fetching always the 20 latest entries of each of the feeds by setting the $num = 20. Also I provide the full content through setting $showfullfeed = true but feel free to set it to your needs. Furthermore, I had to include a little workaround for the shoutbox feed in the line if (strlen($item['content']['encoded']) == 0) because the shoutbox is not putting the message into the content, but into the description. So if the content is empty, I just fetch the description.

< ?php
$DOMAIN_NAME = 'http://zerga.dyndns.org';
$FEED_URL = $DOMAIN_NAME . 'rss/index.php';
$SITE_TITLE = 'NeoZenCortexis';
$SITE_DESCRIPTION = 'Logical Awesome';
$SITE_AUTHOR = 'Zerga aka Nils';

$RSS_CACHE = "/tmp/rsscache";
$RSS_CACHE_EXP = 60;

$FEED_LIST = array(
	'http://zerga.dyndns.org/wordpress/feed/',
	'http://zerga.dyndns.org/wordpress/wp-content/plugins/schreikasten/feed.php',
	'http://zerga.dyndns.org/wordpress/comments/feed/'
);

define('MAGPIE_CACHE_DIR', $RSS_CACHE);
define('MAGPIE_CACHE_AGE', $RSS_CACHE_EXP);
define('MAGPIE_OUTPUT_ENCODING', 'utf-8');

require_once ('magpierss-0.72/rss_fetch.inc');
include ('feedcreator.class.php');

$rss = new UniversalFeedCreator();
$rss->useCached();
$rss->title = $SITE_TITLE;
$rss->description = $SITE_DESCRIPTION;
$rss->link = $DOMAIN_NAME;
$rss->syndicationURL = $FEED_URL;
$rss->encoding = 'utf8';

function showSummary($url, $num = 20, $showfullfeed = true) {
	global $rss, $DOMAIN_NAME, $SITE_AUTHOR, $SITE_TITLE;
	$num_items = $num;
	@ $rss1 = fetch_rss($url);
	if ($rss1) {
		$items = array_slice($rss1->items, 0, $num_items);
		foreach ($items as $item) {
			$href = $item['link'];
			$title = $item['title'];
			if (!$showfullfeed) {
				$desc = $item['description'];
			} else {
				$desc = $item['content']['encoded'];
			}
			$pdate = $item['pubdate'];
			$rss_item = new FeedItem();
			$rss_item->title = $item['title'];
			$rss_item->link = $item['link'];
			if (strlen($item['content']['encoded']) == 0) {
				$rss_item->description = $item['description'];
			} else {
				$rss_item->description = $item['content']['encoded'];
			}
			$rss_item->date = $item['pubdate'];
			$rss_item->source = $DOMAIN_NAME;
			$rss_item->author = $SITE_AUTHOR;
			$rss->addItem($rss_item);
		}

	} else {
		echo "Error: Cannot fetch feed url - " . $url;
	}
}

foreach($FEED_LIST as $v) showSummary($v);
function __usort($ad, $bd) {return strtotime($bd->date) - strtotime($ad->date);}
usort($rss->items, '__usort');
$rss->saveFeed("RSS1.0", $RSS_CACHE . "/feed.xml");

The result will be: Someone calls this index.php (in my case http://zerga.dyndns.org/rss/index.php or just http://zerga.dyndns.org/rss) and it will return one RSS feed containing all merged entries sorted in chronological order. Voila!