09
May
2010
13
Display your latest Twitter update with jQuery, part 2
Back in July of last year, we published the article Display your latest Twitter update with jQuery to show you how simple it was to display your latest Tweets on your website using jQuery. Since that article was published, Twitter have made some changes to their core API which affects how the script in this article works. Before carrying on, if you haven’t already, I recommend that you read the original article first so that the following makes sense.
Everything was working nice and smoothly until Twitter changed the way users can retweet from the main Twitter website. Not that this was a bad thing, the new(ish) functionality was a great addition to an already great service. Before the changes, users manually typed ‘RT’ at the beginning of their tweet to signify that they have retweeted it from another user. Now days, you simply click a button which will take care of it for you.
But, as Kerem pointed out in the comments of the original article, our code does not display these new retweets. Instead, it just displays an empty space where your latest tweet should be sitting pride of place. In nearly all circumstances, I would imagine that this is not the desired effect, especially as the retweet functionality is used a lot more these thanks to the new functionality.
As a result, I have got back to the drawing board to investigate how we can get around this problem and improve the current script. If you wish, you can download the sources files before continuing on.
The Cause of the Issue
The find out why this was happening, we started looking in the Twitter API Wiki. The statuses user_timeline page revealed that the user_timeline API call does not support the new retweets when the data has been requested in the JSON or XML formats:
“Note: For backwards compatibility reasons, retweets are stripped out of the user_timeline when calling in XML or JSON (they appear with ‘RT’ in RSS and Atom).”
The obviously impacts the code we wrote in the original article as we used the JSON format for our returned data. Unfortunately, they don’t expand as to why the no longer support these formats, so we are just going to have to take their word for it.
The Solution
As it turns out, the solution to this issue is relatively simple, but implementing that solution is slightly trickier as it will require some server-side code (of which I will go into later).
As per the Twitter API, the user_timeline API call still supports the RSS and Atom formats. Therefore we can simply change the API request URL to return our data as an RSS feed. If the latest tweet is a retweet now, the text is simply prefixed with an ‘RT’. This is much more useful that a blank tweet, as I’m sure you will agree.
This method does have a few drawbacks though. In our code, we use the jQuery .getScript() method to send our API call to Twitter and return our tweet. This is fine for the JSON format (it’s JavaScript, which can be opened with .getScript), but is not valid for the XML of the RSS feed.
Therefore, we are going to use jQuery’s .get() method instead. However, it not a straight swap because for security reasons, this method will (quite sensibly) only let you request local files with this function and our request is going directly to the Twitter API (i.e, not local).
Cache the tweet locally with PHP
There is a really simply solution to this problem though, using a PHP proxy script, we can load the data locally.
This file will sit locally on you server, and instead of calling the Twitter API directly, we will call it in the query string of this proxy.php file. This means that our new request URL will look as follows:
proxy.php?url=http://twitter.com/statuses/user_timeline/' + username + '.rss?count=1
Here is the source code of the proxy.php script (the file is included in the download at the bottom of the page). Save the file to a web accessible folder on your server:
<?php
// PHP Proxy
// Loads a XML from any location. Used with Flash/Flex apps to bypass security restrictions
// Author: Paulo Fierro
// January 29, 2006
$session = curl_init($_GET['url']);
curl_setopt($session, CURLOPT_HEADER, false);
curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
$xml = curl_exec($session);
header("Content-Type: text/xml");
echo $xml
curl_close($session);
?>
Basically, this script uses the PHP cURL Extension to open the file sent to it in the query string. It then strips away any additional information, such as the file headers, to leave the raw data (the XML of the RSS feed in our case). Finally, it changes the output header to XML and the returns the raw data.
The new jQuery
As we have changed the format of our data, will we need to change the way jQuery parses that data. In the original article, we basically took Twitters own code and tweaked it slightly. This time around, it’s going to be easier and quicker just to rewrite it.
The new JavaScript file (named twitter2.js) is included in the download for this article.
Here is the twitter2.js file in full. I will run through the code in chunks to give you an understanding of what is going on.
UPDATE: Ed Knittel quite correctly points out in the comments that the date format in the RSS results differs to that of the JSON results. Therefore, I have updated the code below to reflect this format difference.
function relative_time(time_value) {
var newtime = time_value(',','');
var values = newtime.split(" ");
time_value = values[2] + " " + values[1] + ", " + values[3] + " " + values[4];
var parsed_date = Date.parse(time_value);
var relative_to = (arguments.length > 1) ? arguments[1] : new Date();
var delta = parseInt((relative_to.getTime() - parsed_date) / 1000);
delta = delta + (relative_to.getTimezoneOffset() * 60);
if (delta < 60) {
return 'less than a minute ago';
} else if(delta < 120) {
return 'about a minute ago';
} else if(delta < (60*60)) {
return (parseInt(delta / 60)).toString() + ' minutes ago';
} else if(delta < (120*60)) {
return 'about an hour ago';
} else if(delta < (24*60*60)) {
return 'about ' + (parseInt(delta / 3600)).toString() + ' hours ago';
} else if(delta < (48*60*60)) {
return '1 day ago';
} else {
return (parseInt(delta / 86400)).toString() + ' days ago';
}
}
$(function() {
var username = '<yourtwitterusername>';
$.get('<path-to-file>/proxy.php?url=http://twitter.com/statuses/user_timeline/' + username + '.rss?count=1', function(tweets) {
$(tweets).find('item').each(function() {
var tweet = $(this);
var pattern = new RegExp("^"+username+": ","g");
var status = tweet.find('description').text().replace(/((https?|s?ftp|ssh)\:\/\/[^"\s\<\>]*[^.,;'">\:\s\<\>\)\]\!])/g, function(url) {
return '<a href="'+url+'">'+url+'</a>';
}).replace(/\B@([_a-z0-9]+)/ig, function(reply) {
return reply.charAt(0)+'<a href="http://twitter.com/'+reply.substring(1)+'">'+reply.substring(1)+'</a>';
}).replace(pattern,'');
var tweetDate = relative_time(tweet.find('pubDate').text());
$('.loading').fadeOut(750, function() {
$('#latest_tweet').append($('<p>“'+status+'” <small>- <span>'+tweetDate+'</span></small></p>').hide().fadeIn(750));
});
});
});
});
First of all, we define a function that turns the time and date of the tweet into something that is more understandable to humans. This is identical to the original, so I won’t go into detail again.
$(function() {
var username = '<yourtwitterusername>';
Here we create the standard jQuery on DOM ready function and set a variable called username to store your Twitter username:
$.get('<path-to-file>/proxy.php?url=http://twitter.com/statuses/user_timeline/' + username + '.rss?count=1', function(tweets) {
Next we request the RSS data from Twitter using jQuery’s .get() method. This is where we load your latest tweet via the proxy.php file (make sure you include the correct file path to the proxy.php file if it is in a different directory to this JavaScript file). If you would like to load more than one tweet, change the final option in the URL (e.g. enter count=3 at the end of the query string if you would like to return three tweets). The data returned from the Twitter API in then stored in an object called tweets which can the be called in the callback function.
$(tweets).find('item').each(function() {
var tweet = $(this);
var pattern = new RegExp("^"+username+": ","g");
In the next block of code, we need to search through the XML to find the text and time of each tweet. We use the .find() method to search through the XML and locate each XML element called ‘item’. We then loop through each of the discovered elements. We set a variable called tweet which caches the currently selected element in the loop.
The next step is to create a new RegExp object. By default, you may have noticed that the Twitter API not only prefixes the tweet with RT if necessary, it also prefixes every tweet with your Twitter username. The regular expression here simply matches your Twitter username so we can remove it from the tweet later on.
var status = tweet.find('description').text().replace(/((https?|s?ftp|ssh)\:\/\/[^"\s\<\>]*[^.,;'">\:\s\<\>\)\]\!])/g, function(url) {
return '<a href="'+url+'">'+url+'</a>';
}).replace(/\B@([_a-z0-9]+)/ig, function(reply) {
return reply.charAt(0)+'<a href="http://twitter.com/'+reply.substring(1)+'">'+reply.substring(1)+'</a>';
}).replace(pattern,'');
Now, at first glance, this chunk of code may look a bit confusing, but don’t let that put you off. We start by extracting the actual text of the tweet from the XML data, again using jQuery’s .find() method. We then pass this text through three regular expressions. The first regular expressions searches for any URL’s in the text and replaces them with HTML <a> links. The second expressions searchs for the Twitter @ references and again turns them into actual links. The final filter uses the regular expression that we set up earlier that removes the username from the beginning of the tweet.
var tweetDate = relative_time(tweet.find('pubDate').text());
$('.loading').fadeOut(750, function() {
$('#latest_tweet').append($('<p>“'+status+'” <small>- <span>'+tweetDate+'</span></small></p>').hide().fadeIn(750));
});
This final chuck extracts date and time of the tweet and passes it through the relative_time to turn it into a nice readable format. The last bit inserts the tweet into your website in exactly the same way as the original script.
Conclusion
The code in the original article has proved quite successful and I think many of you have found it useful. Hopefully the new version will continue to be helpful in your projects. Please let us know if you have used this script, we would love to hear if you have found this useful in any way.
Thanks!
Resources
- The original article
- Twitter API Wiki
- Twitter API – statuses user_timeline
- PHP proxy script
- PHP cURL Extension

13 Responses to “Display your latest Twitter update with jQuery, part 2”
Comments
June 22nd, 2010 at 12:50 am
Hmm… I could not get this one to work. I used the original html file created editing the source files for js, added the proxy file and the new twitter2.js but got nothing in the post box?
June 27th, 2010 at 8:34 pm
I’ve recently fell victim to the exact problem you described with the Twitter API and retweets.
Thanks for sharing your solution. Only issue I encountered was that all the tweets were being displayed in reverse order. However, the solution was real simple; swap append() out with prepend() in the jQuery code.
Hopefully Twitter will address the problem in their API soon.
June 27th, 2010 at 8:35 pm
I’ve recently fell victim to the exact problem you described with the Twitter API and retweets.
Thanks for sharing your solution. Only issue I encountered was that all the tweets were being displayed in reverse order. However, the solution was real simple; swap append() out with prepend() in your jQuery code.
Hopefully Twitter will address the problem in their API soon.
July 5th, 2010 at 10:41 pm
is there a way to do this without php… asp maybe? i am trying to get this to work on a business catalyst site which does not seem to recognize php files.
are there any other solutions?
July 15th, 2010 at 12:23 pm
yes you can setup a reverse proxy on your Apache (or whatever web server you are using) and map for example /twitter/ to http://www.twitter.com
then from the JS, instead of calling proxy.php like above or http://twitter.com/statuses/user_timeline/ (which won’t work cos it’s cross-domain) you’d be utilizing your reverse proxy and calling http://www.yourdomain.com/twitter/statuses/...
this way you can trick your browser into thinking you are making local request while you’d be making remote one via the reverse proxy on the server level
August 3rd, 2010 at 8:10 pm
I noticed a problem with the time_value which then of course was messing up the delta. If you change the RSS count to more than 1 (say, 5) you might be seeing a lot many tweets which appear to be posted on or about the same time. To correct this I made my time_value = values[2] + ” ” + values[1] + “, ” + values[3] + ” ” + values[4];
Which is MMM DD, YYYY HH:MM:SS
I also realized that in your example you weren’t linking back to the original tweet which is useful if you want folks to retweet what you post. To accommodate this I grab the link node and wrap a link around the tweetDate like so:
var link = tweet.find(‘link’).text();
var tweetDate = ‘‘+relative_time(tweet.find(‘pubDate’).text())+’‘;
Thanks for posting this as it was frustrating as all hell why RTs weren’t being displayed.
August 3rd, 2010 at 8:13 pm
Hmmm your comment system screwed up my tweetDate. Let’s try:
var tweetDate = ‘‘+relative_time(tweet.find(‘pubDate’).text())+”;
August 3rd, 2010 at 8:13 pm
Nevermind
August 4th, 2010 at 7:49 pm
Hi Ed,
Thanks for pointing that out, you are quite right. The tweets returned via RSS seems to have a different date format to that of the JSON results, which was causing the dates to display incorrectly.
I will update the post with the correct format.
Many thanks,
Ian
August 30th, 2010 at 10:48 pm
Thanks for updating your code!
Just as a friendly FYI, there’s a minor problem on line 2 in your relative_time() function, posted above, where it appears you forgot to call the replace() function. Other than that it works great. Thanks again!
August 6th, 2010 at 12:50 pm
what if i need to show my own database updates in run time ?
October 31st, 2010 at 6:28 pm
Now that you are moving the actually contact to twitter to the server side of things, you may want to do the same with your string parsing. Imagine you need to run your script 1000 times/hour for a decent amount of traffic and you update your .php proxy every 30 minutes with a cron job. Your current implementation would have all the code for the twitter feed parsing running 1000 times, when you could get away with just 2 times if it were handled in the php.
March 4th, 2011 at 10:14 pm
Im used my entire evening implementing the original script to a joomla template. And was happy.
Sadly i did not see the spoiler..
It was working so fine, untill i tried to retweet. The solution provided to solve this did not work for me.
Although, im also unsure where to place proxy.pgp and weather to include it?
But also i get an error, when trying to check the url for proxy.php.. (I just copy/pasted it).
http://www.d3signated.com/templates/d3/php/proxy.php
XML Parsing Error: no element found
Location: http://www.d3signated.com/templates/d3/php/proxy.php
Line Number 1, Column 1:
I don’t know if you kan help, but i would be greatly appriciative
I just placed it in a php folder!
Trackbacks & Pingbacks