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

    Craig Buckler
    Share

    In Part 1 of this series, we examined the Twitter API, creating a PHP TwitterStatus class, and imported the latest tweets in JSON format. Today, we’ll populate the data into HTML templates — download the full source code here.

    Template Parsing

    We have defined two HTML templates as public properties:

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

    Either template can include {named-values} from the Twitter feed, 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>';
    

    Our code must extract all {named-values}, see if a value exists in the Twitter data and replace it accordingly. Let’s create a private function to handle that:

    
    private function ParseStatus($data, $template) {
    

    ParseStatus accepts two values:

    • $data is a section of the Twitter JSON for an individual tweet.
    • $template is an HTML template (either $WidgetTemplate or $TweetTemplate will be passed).

    The first step is locate every {named-value} using a regular expression:

    
    preg_match_all('/{(.+)}/U', $template, $m);
    

    PHP’s preg_match_all() returns an array with two elements. The first is an array containing all matched “{named-value}” strings. The second is another array containing the characters found within the regular expression’s (.+) brackets, i.e., “named-value” without the curly quotes.

    We can loop through each value and determine whether it’s in the Twitter data. Note, it may reside within the ‘user’ section (a sub-associative array)…

    
    for ($i = 0, $il = count($m[0]); $i < $il; $i++) {
    
    	$name = $m[1][$i];
    
    	// Twitter value found?
    	$d = false;
    	if (isset($data[$name])) {
    		$d = $data[$name];
    	}
    	else if (isset($data['user'][$name])) {
    		$d = $data['user'][$name];
    	}
    

    At the end of this code $d is either false or a matching tweet value. We could now use it within an str_replace() but there are two special cases we need to handle first:

    • ‘text’ is the tweet string which could contain URLs, @ids or #hashtags. We need to convert those to accordingly, so we’ll intercept the data and pass it to a new function named ParseTwitterLinks().
    • ‘created_on’ is the date/time the tweet was sent. Dates must be handled differently for reasons which will become apparent in the next post. For the moment, we just want to indicate we have a date, so we’ll put the value within a {DATE:…} string.
    
    		// replace data
    		if ($d) {
    
    			switch ($name) {
    
    				// parse status links
    				case 'text':
    					if ($this->ParseLinks) {
    						$d = $this->ParseTwitterLinks($d);
    					}
    					break;
    
    				// tweet date
    				case 'created_at':
    					$d = "{DATE:$d}";
    					break;
    
    			}
    
    			$template = str_replace($m[0][$i], $d, $template);
    
    		}
    
    	}
    	// end of loop
    
    	return $template;
    
    }
    // end of ParseStatus
    

    Link Parsing

    We now require a private ParseTwitterLinks() function to translate links in tweets (‘text’ values). A single string is passed:

    
    private function ParseTwitterLinks($str) {
    

    We now need a little more regular expression magic. First, we’ll look for URLs — we don’t care if they’re well-formed, just that they start with ‘http’ and contain valid characters:

    
    $str = preg_replace('/(https{0,1}://[w-./#?&=]*)/', '<a href="$1">$1</a>', $str);
    

    Next, we’ll check for @id links and replace them with an appropriate link to Twitter:

    
    $str = preg_replace('/@(w+)/', '@<a href="http://twitter.com/$1" class="at">$1</a>', $str);
    

    Finally, we’ll replace #hashtags with a Twitter search link:

    
    $str = preg_replace('/s#(w+)/', ' <a href="http://twitter.com/#!/search?q=%23$1" class="hashtag">#$1</a>', $str);
    

    Rendering Our HTML Widget

    We now have all the code we need to translate our Twitter feed into an HTML widget. This is done in a new public method named Render(). First we fetch the feed data and check a result has been returned:

    
    $json = $this->FetchFeed();
    if ($json) {
    

    Next, we’ll define two strings for the widget itself and a collection of all status updates:

    
    	$widget = '';
    	$status = '';
    

    We can then examine every Tweet within a loop:

    
    	// examine all tweets
    	for ($t = 0, $tl = count($json); $t < $tl; $t++) {
    

    If this is the first tweet, we’ll replace values into the $WidgetTemplate. This is only required once since the outer widget code is likely to show information from the ‘user’ array which is provided with every tweet (examine the SitePoint feed):

    
    		// parse widget template
    		if ($t == 0) {
    			$widget .= $this->ParseStatus($json[$t], $this->WidgetTemplate);
    		}
    

    We can then replace values in the $TweetTemplate with those in each tweet:

    
    		// parse tweet
    		$status .= $this->ParseStatus($json[$t], $this->TweetTemplate);
    

    Finally, we end the loop and create a new $render string. This contains the outer $widget HTML but {TWEETS} is replaced with the $status HTML:

    
    	}
    
    	// parse Twitter links
    	$render = str_replace('{TWEETS}', $status, $widget);
    }
    

    Assuming we’re using the $WidgetTemplate and $TweetTemplate code above, our resulting HTML should be something like:

    
    <div>
    <img src="http://a3.twimg.com/profile_images/76953980/Picture_29_normal.png" />
    <strong>SitePoint</strong>
    <ul>
    <li>
    Tweet 9:
    Visit <a href="http://www.sitepoint.com">http://www.sitepoint.com</a>
    {DATE:Thu Dec 23 10:10:18 +0000 2010}
    </li>
    <li>
    Tweet 8:
    Hello @<a href="http://twitter.com/craigbuckler" class="at">craigbuckler</a>
    {DATE:Thu Dec 23 10:05:01 +0000 2010}
    </li>
    <li>
    Tweet 7:
    We love  <a href="http://twitter.com/#!/search?q=%23javascript" class="hashtag">#javascript</a>
    {DATE:Thu Dec 23 10:00:00 +0000 2010}
    </li>
    </ul>
    </div>
    

    It’s close to what we want, but we still need to cache the resulting HTML, convert the dates to a more friendly format, and add a sprinkling of CSS. We’ll cover that in the last post…