How to Create Your Own Twitter Widget in PHP, Part 1

    Craig Buckler
    Share

    Twitter status widgets are ten a penny, so why create your own? Because you can! Your own widget will always be more customizable than any off-the-shelf solution, and you’ll be the envy of your peers. We’ve also been asked by several readers for articles about the topic, and it’s a great introduction to PHP, REST APIs, JSON, regular expressions and Object Orientated Programming.

    Twitter widget in PHP

    The Challenge

    This is a 3-part tutorial based on source code you can download here. Our objectives are to:

      • Interrogate the Twitter API and fetch any number of status updates for an individual user.
      • Apply the data to a configurable HTML template and convert URLs, @id and #hashtags to proper links.
      • Format dates into a friendlier format, e.g. posted ten minutes ago, yesterday, two weeks ago, etc.
      • Cache the widget HTML so the fetching process is not required during every page load.
      • Make the resulting widget work in all browsers — yes, that includes IE6!

        The Twitter API

        Twitter provides a REST API. The following URL fetches the last N tweets posted by a specific user:

        http://twitter.com/statuses/user_timeline/user_id.format?count=N

        Where:

        • user_id is the Twitter user name
        • format is either json, xml, rss or atom
        • N is the number of status updates to return

        Therefore, the following URL returns Sitepoint’s last 10 updates in XML format:

        http://twitter.com/statuses/user_timeline/sitepointdotcom.xml?count=10

        JSON vs XML?

        The future of XML is a hot discussion topic, especially following Twitter’s decision to drop the format from their Streaming API in favor of JSON. I won’t get into that debate here, but my original intention had been to use the XML feed and transform it to HTML using XSLT. That became a little too convoluted–primarily because links within a tweet must be resolved using regular expressions. That would have been possible using XSLT 2.0 but, unfortunately, PHP’s libxslt only supports XSLT 1.0.

        I therefore choose JSON; it’s a less-verbose format and can be decoded by PHP’s json_decode() function.

        The TwitterStatus Class

        The widget functionality is wrapped in a single class named TwitterStatus (refer to the twitter/twitterstatus.php file in the download). Seven public and one private property is defined:

        
        class TwitterStatus
        {
        
        	public $ID;				// twitter user name
        	public $Count;			// tweets to fetch
        	public $WidgetTemplate;	// widget template
        	public $TweetTemplate;	// template for each tweet
        	public $ParseLinks;		// parse links in Twitter status
        	public $DateFormat;		// PHP or "friendly" dates
        	public $CacheFor;		// number of seconds to cache feed
        
        	private $cache;			// location of cache files
        
        note: Public and Private?

        If you’re new to Object-Orientated Programming, a public property (variable) or method (function) can be accessed from outside the class, i.e. we can set and examine the $ID value from any code no matter where it resides.

        A private property or method has local scope and only be used within the class itself. The $cache property can be set and examined within the TwitterStatus class, but it’s not visible elsewhere.

        PHP also provides protected properties and methods. We’re not using those here, but protected members are visible within the class and to inherited and parent classes.

        We now require a constructor function which runs when a new TwitterStatus object is created. Our constructor simply sets each property to a default value:

        
        // constructor
        public function __construct($id = null, $count = 0) {
        
        	// constants
        	$this->cache = __DIR__ . '/cache/';	// cache location
        	$this->CacheFor = 900;				// cache feed for 15 minutes
        
        	$this->ID = $id;
        	$this->Count = $count;
        	$this->ParseLinks = true;
        	$this->DateFormat = 'friendly';
        
        	// default widget template
        	$this->WidgetTemplate =
        		'<div class="twitterstatus">' .
        		'<h2><a href="http://twitter.com/{screen_name}"><img src="{profile_image_url}" width="24" height="24" alt="{name}" />{name}</a></h2>' .
        		'<ul>{TWEETS}</ul>' .
        		'</div>';
        
        	// default tweet template
        	$this->TweetTemplate =
        		'<li>{text} <em>{created_at}</em></li>';
        
        }
        

        The only private property is $cache–the directory where we’ll store cached versions of the widget so we’re not interrogating the Twitter API during every page load. It’s set to the directory named ‘cache’ within the directory where twitterstatus.php resides–it’ll need to have appropriate read/write permissions set.

        The $ID and $Count properties can be set when a TwitterStatus object is instantiated, e.g.,

        
        $t = new TwitterStatus('sitepointdotcom', 10);
        

        or we can change the properties separately, e.g.,

        
        $t = new TwitterStatus();
        $t->ID = 'sitepointdotcom';
        $t->Count = 10;
        

        If $ParseLinks is set to true, our code will translate links within the tweet to HTML anchor tags.

        $DateFormat can be set to a PHP date() format, e.g.

        
        $t->DateFormat = 'g:ia j F Y'; // 1:15pm 27 January 2011
        

        Alternatively, $DateFormat can be set to “friendly” (the default string) to indicate we want friendly dates (ten minutes ago, yesterday, last week, etc.)

        Finally, we set two HTML templates:

        • $WidgetTemplate is the widget’s outer HTML. The {TWEETS} code indicates where one or more $TweetTemplate blocks will appear.
        • $TweetTemplate is the HTML for an individual tweet.

        Either property can include {named-values} from the Twitter feed, e.g. {text}, {source}, {name}, {location}, {profile_image_url}, {statuses_count} etc. It’s easiest to view the XML version of the feed to locate named values.

        The developer can therefore specify their own widget HTML, e.g.,

        
        $t->WidgetTemplate =
        	'<div>' .
        	'<img src="{profile_image_url}" />' .
        	'<strong>{name}</strong>'
        	'<ul>{TWEETS}</ul>' .
        	'</div>';
        
        $t->TweetTemplate =
        	'<li>Tweet {statuses_count}: {text} {created_at}</li>';
        

        Fetching the Twitter Feed

        We can now implement a private method to fetch the Twitter status data using PHP’s Client URL (cURL) library:

        
        private function FetchFeed() {
        
        	$r = '';
        	if ($this->ID != '' && $this->Count > 0) {
        		// fetch feed
        		$c = curl_init();
        		curl_setopt_array($c, array(
        			CURLOPT_URL => 'http://twitter.com/statuses/user_timeline/' . $this->ID . '.json?count=' . $this->Count,
        			CURLOPT_HEADER => false,
        			CURLOPT_TIMEOUT => 10,
        			CURLOPT_RETURNTRANSFER => true
        		));
        		$r = curl_exec($c);
        		curl_close($c);
        	}
        
        	// return JSON as array
        	return (!!$r ? json_decode($r, true) : false);
        }
        

        A number of cURL options are set, but the most important is the timeout. We’re allowing ten seconds for a Twitter response and, if that’s exceeded, PHP will give up and the function will return false.

        If everything works as expected, the result is parsed using json_decode() which returns an array of associative arrays matching the JSON data.

        We’ve covered a lot of ground today so it’s time for a break. In the next post, we’ll examine the code which transforms Twitter data into HTML code.