Simple Activity Streaming with SimplePie

A few different people have asked me recently how I created the activity stream/life stream you see in the sidebar of Dented Reality. It’s actually really simple, and all it does is load up the feeds from a few different locations, combine them in date order and then output them on my page using an HTML “UL” (unordered list). Based on the source of each feed, it also adds a CSS class to each list element (LI) so that I can add an appropriate icon. Here’s the complete code that I use, and then I’ll explain some parts of it, and some of what makes it tick:

<h2>Me, Live (ish)!</h2>
 <ul>
 <?php

 // Create a new SimplePie object
 $feed = new SimplePie();

 // Instead of only passing in one feed url, we'll pass in whole list
 $feed->set_feed_url(array(
 'http://feeds.delicious.com/rss/beau',
 'http://dentedreality.com.au/TwitterProxy/TwitterProxy.php?strip_replies=true&create_links=true&hashtags=true&strip_name=true&link_people=true',
 'http://ws.audioscrobbler.com/1.0/user/borkazoid/recenttracks.rss',
 'http://digg.com/users/beaulebens/history/diggs.rss',
 'http://www.hulu.com/feed/history/beaulebens'
 ));

 // Initialize the feed object
 $feed->set_cache_location(WP_CONTENT_DIR . '/feeds');
 $feed->set_cache_duration(3600);
 $feed->init();

 // This will work if all of the feeds accept the same settings.
 $feed->handle_content_type();

 // Now we output the combined feed
 $out = 0;
 foreach ($feed->get_items() as $item) {
 $f = $item->get_feed();
 switch ($f->get_link()) {
 case 'http://www.last.fm/user/borkazoid':
 $class = 'music';
 $strings = explode('–', $item->get_title());
 $text = 'Listened to <a href="http://last.fm/music/' . urlencode(trim($strings[0])) . '/_/' . trim($strings[1]) . '">' . trim($strings[1]) . '</a>, <a href="http://last.fm/music/' . urlencode(trim($strings[0])) . '">' . trim($strings[0]) . '</a>';
 break;
 case 'http://twitter.com/beaulebens':
 $text = 'Tweeted: ' . $item->get_title() . ' <a href="' . $item->get_link() . '">#</a>';
 $class = 'status';
 break;
 case 'http://digg.com/users/beaulebens/history/diggs':
 $text = 'Dugg <a href="' . $item->get_link() . '">' . $item->get_title() . '</a>';
 $class = 'digg';
 break;
 case 'http://del.icio.us/beau':
 case 'http://delicious.com/beau':
 $class = 'bookmark';
 $text = 'Bookmarked <a href="' . $item->get_link() . '">' . $item->get_title() . '</a>' . (strlen($item->get_description()) ? ' - ' . $item->get_description() : '');
 break;
 case 'http://www.hulu.com/users/history':
 $class = 'hulu';
 $text = 'Watched <a href="' . $item->get_link() . '">' . $item->get_title() . '</a> on <a href="http://hulu.com/">hulu.com</a>';
 break;
 default:
 $class = 'generic';
 $test = $item->get_title();
 }
 echo '<li>' . $text . ' <small>(' . $item->get_date('j M, g:i a') .')</small></li>';
 $out++;
 if ($out >= 30) break;
 }

 ?>
 </ul>

That’s it. Apologies for the lack of indentation, apparently my tabs didn’t come through properly. OK, let’s walk through it quickly.

This code all appears in my sidebar.php file (part of my custom theme), although I suppose ideally it should be a widget (maybe one day). As I said, it uses the SimplePie library, which is bundled with WordPress and is automatically available in theme files. It makes use of SimplePie’s ability to set an array of feed URLs (instead of just one) to load a couple different URLs and combine them all together.

You’ll notice that one of the URLs in there is weird-looking (http://dentedreality.com.au/TwitterProxy/TwitterProxy.php?strip_replies=true&create_links=true&hashtags=true&strip_name=true&link_people=true). That just uses another script of mine called TwitterProxy to load my Twitter updates and reformat them a bit to include links, exclude certain ones etc. The other feed URLs are all just standard URLs available from different web services I use. I could add/remove feeds on this list to include other ones in my simple activity stream.

Then I set up some configuration options for SimplePie, including configuring a specific cache directory so that I can store local copies of both the source feeds and the combined feed, rather than go and download them every time someone loads my website (which would be bad). I cache everything for an hour each time (3600 seconds), since it doesn’t need to be anywhere near live.

The next big loop (foreach…) just goes through each of the items in the combined collection of feeds and does some processing. Based on where that item came from (which source feed it was in), I set up a string for the output, set a CSS class to add to the LI and then output the item with the datestamp for when it happened. I only output the most recent 30 items across all services, and then I finish up my list and bail out.

So there you have it. That block of code in my theme handles everything for me, providing a custom activity stream on my blog. I could have used one of the available WordPress plugins like Lifestream, RSS Stream or the very powerful DiSo Action Stream, but I decided to just roll my own. If anything, I might go back and use the DiSo option at some point, since I think that project is doing some really interesting things.

  1. Donncha said:

    Next step would be a wp-cron job that updates the feeds in the background every hour and then updates the html making up your sidebar :)

    • Beau Lebens said:

      Yup, one day ;)

      I've been trying to figure out a decent way to widgetize it without
      losing the custom functionality as well (custom strings, URL-specific
      classes etc). Don't have a definite answer just yet, but got a few
      options. That'd make it much more accessible to other folks.

  2. Hey man. This is awesome! This is what we talked about.. Using this method I can combine the comment feeds from various blogs that use Intense Debate to produce a single feed on the main page of my social network! Beau, how can I find out the url for an Intense Debate comments feed of a blog that isn't my blog and I don't know the owner? This is very important for my implementation of Buddypress with ID next year. I teach Spanish and working very hard on http://www.languageconnects.us so that it will be ready for masses of students in the fall.

    Also… I have to say that my Php experience is limited. I have manipulated a lot of code over the years but always based on models and trial and error. A widget would be awesome!

    I have also been looking at other solutions to combine custom RSS feeds. The only solution I have found so far aside from yours is Yahoo pipes. I would love to do what you did. Am going to try to make a feed like yours with my own info… Will try do my best to build my own off of your model. Thank you so much for the walk through and model!!!

  3. Beau Lebens said:

    I'd like to build something that imported all these into wp_comments using different post_type values, then I could query them out and harness the power of WP… but that'd be a lot more work ;)

  4. ConradH said:

    Thanks for this… good info.

    I'd like to be able to display a handful of Twitter feeds from different users and was hoping to use your TwitterProxy code with SimplePie to parse the links, usernames, hashtags, etc. but then realized it's written for just one pre-defined user. Is there a straightforward way to convert your code to use a variable for the twitter username, or do you know of another way to parse URLS and such in twitter statuses pulled by SimplePie for WP? I'm surprised there isn't a SimplePie add-on or something. Any help would be appreciated. Thanks!

    • Use the Lifestream widget. In wordpress Plugins just search Lifestream. It is awesome. You can mix any RSS feeds you want into one, and put it in your sidebar. Beau, I wish you would have told me this!!! I figured it out on my own.

      • Beau Lebens said:

        I've been meaning to play around with that plugin to see what it's capable of. I literally have an unzipped copy of it sitting on my desktop waiting for me to tinker with it :) Thanks for the reminder!

    • Beau Lebens said:

      @ConradH, you could just set up a few different copies of the script, configuring each one to pull from a different Twitter account. It shouldn't be *too* hard to change it so that it supports an array of account details rather than a single constant, but the quick solution would be to just duplicate the script and change the settings at the top for each account.

  5. 14 Tutorials to Get You into SimplePie

  6. Jeroen said:

    Hi man! Great tutorial you got here!! I, however do not seem to get the $text variable working with the different cases.

    It seems that my simplepie links don’t match with the links I need the code to check. In addition, when I echo the value of the variable $f I only get weird strings of text and numbers.

    I’m a newby at programming PHP so maybe it’s just basics that I’m missing but I hope you can help me out!

    Thanks in advance!

    Jeroen

    • Beau Lebens said:

      To do anything useful with $f you'll probably want to use print_r() or var_dump() rather than echo (since it's an object).

      Your $text value won't be set correctly unless you get a match based on the switch statement ( switch ($f->get_link()) )

      Try outputting the value of $f->get_link() and see what you're getting, then you should be able to work backwards from there to come up with the "case"s you're working with.

Comments are closed.