twitter and wordpress, non-widget edition
Folks reading my blog via an RSS reader probably haven’t noticed, but I’ve recently refreshed the look of chizang’s web 6.0. If you haven’t seen it yet, come on over and check it out. It’s a lot shinier!
While the base theme (Fontella) was a nice start, one thing it lacked was WordPress widget support, which was annoying because I wanted to embed Twitter here, and by far the easiest way to do that is with existing widgets that folks have already written. So the alternative solution was to ride the internet platypus around for a bit and look for others’ solutions.
After a little searching, it was clear to me that using the official Twitter API was overkill for what I wanted, and the simplest thing to do would be to just write (or borrow) a little php snippet that reads the RSS feed of your Twitter profile. I found something that was a good starting point and modified it a little bit so it ended up like the following:
<?php
$feedURL = "http://twitter.com/statuses/user_timeline/65818688.rss";
$doc = new DOMDocument();
if (@$doc->load($feedURL, LIBXML_DTDLOAD) == false)
exit();
foreach ($doc->getElementsByTagName('item') as $node) {
$str = $node->getElementsByTagName('title')->item(0)->nodeValue;
$str = str_replace('_achiang: ', '', $str);
if (preg_match('/^@/', $str)) {
continue;
}
$str = ereg_replace("[[:alpha:]]+://[^<>[:space:]]+[[:alnum:]/]", "<a href=\"\\0\">\\0</a>", $str);
echo $str;
break;
}
?>
It’s pretty self-explanatory, but in words, it grabs my Twitter RSS feed, and reads out the ‘title’ elements, which are the tweets. Since all my tweets are preceded with my username (_achiang), it strips that part out. It then looks to see if the tweet is an @reply to someone else, in which case it skips to the next one, which is a small design decision based on the idea that I’m looking to display my generalized tweets on my blog, not my out-of-context replies to someone else.
The next bit turns any links in my tweet into an actual clickable link.
Finally, echo out the completed string, and stop processing. You could put that into a counted loop of sorts if you wanted to do that for say, your most recent 5 tweets or whatever, but I really only wanted one.
Ok, so you have all that, and you think you can just embed that code into your blog somewhere, but you don’t really want to do that because each page refresh will cause your blog to hit Twitter. And if you have a popular blog, you will quickly get rate-limited and then Twitter will start returning 401 error codes that look really ugly.
What we need to do is decouple the “poll twitter” bit from the “display on blog” bit.
For the “poll twitter” bit, we run the code as a cronjob, maybe every 5 minutes or so. Here’s what I ended up with:
5 * * * * php /path/to/twitter-rss.php > /path/to/output.txt
“Run every 5 minutes.” “Directly call php on your snippet” “Redirect output to a file.”
Running the snippet every 5 minutes won’t run afoul of Twitter’s rate-limiting policy.
And now, finally, you can stick this into your theme somewhere:
<?php
echo file_get_contents("/path/to/output.txt");
?>
The above just reads the output of your little snippet whenever your blog loads, but obviously doesn’t hit Twitter. And it’s much more flexible than a WordPress widget, since those typically have to go into the sidebar, which doesn’t work all that great for a single-column layout like I have here.
Enjoy.
Update: (9 July 2010) – fix the php snippet to use the @ sign and squelch all warning output, and exit if the DOMDocument->load fails (aka twitter is experiencing fail whales). also, simplify the cron job, as links -dump (the old way) created parsed html, and we really just want the raw.
- Posted by alex at 03:42 pm
- Permalink for this entry
- Filed under: geek
- RSS comments feed of this entry
- TrackBack URI
Hi Alex,
Thanks for the quality blog! I just wanted to give you a heads up that I’ve been seeing this message where your tweets should be on the blog:
Warning: DOMDocument::load(http://twitter.com/statuses/user_timeline/65818688.rss) [domdocument.load]: failed to open stream: HTTP request failed! HTTP/1.1 400 Bad Request in /home/achiang/chizang.net/alex/twitter-rss.php on line 4 Warning: DOMDocument::load() [domdocument.load]: I/O warning : failed to load external entity “http://twitter.com/statuses/user_timeline/65818688.rss” in /home/achiang/chizang.net/alex/twitter-rss.php on line 4
I’ve not reloaded the page to see the error rate, but I’m pretty sure I’ve seen this about twice in three visits.
-Nathan
Thanks Nathan!
Yeah, I’m aware that it’s still a little busticated. :(
I’m not a php hacker, but what I really need to do is add error checking in the call to the document loading step, and if we get a 401 error, to just bail out early.
Clues and patches gratefully accepted. ;)