• Feed RSS

Combined Facebook, Twitter & RSS Social Stats with jQuery, PHP & YQL

Combined Facebook, Twitter & RSS Social Stats with jQuery, PHP & YQL: "

As we increasingly depend on more and more social services, there rises the need to provide a simple way to let our website visitors take part of our diverse social presence.

In this tutorial we are going to create a simple widget, which combines the number of your RSS readers, twitter followers, and fans of your facebook fan page, to give a rough estimate of your social popularity.

We are using jQuery and the tipTip plugin, object-oriented PHP, and Yahoo’s YQL, while demonstrating a number of interesting web development techniques.

Step 1 – PHP

YQL is a free Yahoo web service, which enables us to communicate with numerous third-party APIs through a consistent SQL-like language (and hence the name). It is basically a gateway that sits between you and the other APIs.

This is especially important here, as we are using Yahoo’s YQL for three very different tasks:

  • Fetch your RSS subscriber count with FeedBurner’s awareness API (which comes in the form of an XML file that has to be parsed).
    Note:
    You have to enable the awareness API to use this widget with your own feed. This is done from the Publicize Tab on your feed settings page;
  • Use twitter’s API to get your number of followers;
  • Use Facebook’s new Graph API (link) to get information about the number of fans of your facebook fanpage.

If it weren’t for YQL, we’d have to research and implement three very different solutions, which would slow us down significantly.

includes/subscriber_stats.class.php

class SubscriberStats{

 public $twitter,$rss,$facebook;
 public $services = array();

 public function __construct($arr){

  $this->services = $arr;

  $yqlQueries = array();

  // Forming the Feedburner Awaraness API URL from the passed feed URL:
  $feedBurnerAwarenessAPI = 'http://feedburner.google.com/api/awareness'.
  '/1.0/GetFeedData?uri='.end(split('/',trim($arr['feedBurnerURL'],'/')));

  // Building an array with queries:

  if($arr['feedBurnerURL'])
   $yqlQueries[] = '
    SELECT * FROM xml
    WHERE url=\''.$feedBurnerAwarenessAPI.'\'
   ';

  if($arr['twitterName'])
   $yqlQueries[] = '
    SELECT * FROM twitter.user.profile
    WHERE id=\''.$arr['twitterName'].'\'
   ';

  if($arr['facebookFanPageURL'])
   $yqlQueries[] = '
   SELECT fan_count FROM facebook.graph
   WHERE id=\''.end(split('/',trim($arr['facebookFanPageURL'],'/'))).'\'
   ';

  // Combing them into a YQL multiquery:
  $multiQuery =
  'SELECT * FROM query.multi WHERE queries = "'.join(';',$yqlQueries).'"';

  // Executing the query:
  $result = json_decode(
   file_get_contents('http://query.yahooapis.com/v1/public/yql?q='.
   urlencode($multiQuery).'&format=json&diagnostics=false&'
   'amp;env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys')
  )->query->results->results;

  // The results from the queries are accessible in the $results array:

  $this->rss = $result[0]->rsp->feed->entry->circulation;
  $this->twitter = $result[1]->item->meta[5]->content;
  $this->facebook = $result[2]->json->fan_count;
 }

 public function generate(){

  $total = number_format($this->rss+$this->twitter+$this->facebook);

  echo '
   <div class="subscriberStats">
    <div class="subscriberCount"
    title="'.$total.'+ Total Social Media Followers">'.$total.'</div>

    <div class="socialIcon"
    title="'.number_format($this->rss).' RSS Subscribers">
     <a href="'.$this->services['feedBurnerURL'].'">
     <img src="img/rss.png" alt="RSS" /></a>
    </div>

    <div class="socialIcon"
    title="'.number_format($this->facebook).' Fans on Facebook">
     <a href="'.$this->services['facebookFanPageURL'].'">
     <img src="img/facebook.png" alt="Facebook" /></a>
    </div>

    <div class="socialIcon"
    title="'.number_format($this->twitter).' Twitter Followers">
    <a href="http://twitter.com/'.$this->services['twitterName'].'">
     <img src="img/twitter.png" alt="Twitter" /></a>
    </div>
   </div>
  ';
 }
}

When we create an object of this class, the construct method is called, and a YQL query is created and executed.

To request the data from YQL’s servers, we just use file_get_contents() with the query passed as a parameter of the URL address. This returns a JSON object (basically a JavaScript object) which we can decode into a native PHP array with the in-build json_decode() function.

The results of these queries are saved locally and are made available for use in the generate() method which renders all the needed markup.

And now lets see how this class is used:

subscriber_count.php

require "includes/subscriber_stats.class.php";

$cacheFileName = "cache.txt";

// IMPORTANT: after making changes to this file (or the SubscriberStats class)
// remeber to delete cache.txt from your server, otherwise you wont see your changes.

// If a cache file exists and it is less than 6*60*60 seconds (6 hours) old, use it:

if(file_exists($cacheFileName) && time() - filemtime($cacheFileName) > 6*60*60)
{
 $stats = unserialize(file_get_contents($cacheFileName));
}

if(!$stats)
{
 // If no cache was found, fetch the subscriber stats and create a new cache:

 $stats = new SubscriberStats(array(
  'facebookFanPageURL' => 'http://www.facebook.com/smashmag',
  'feedBurnerURL'   => 'http://feeds.feedburner.com/Tutorialzine',
  'twitterName'   => 'Tutorialzine'
 ));

 // Serialize turns the object into a string,
 // which can later be restored with unserialize():

 file_put_contents($cacheFileName,serialize($stats));
}

// You can access the individual stats like this:
// $stats->twitter;
// $stats->facebook;
// $stats->rss;

// Output the markup for the stats:

$stats->generate();

Sending a query to YQL’s servers and receiving a response is a relatively slow process and would be unwise to request the same information on every page load (not to mention that we could get banned from the API for abuse).

This is why we implement a simple caching system. The idea is simple: if a cache file does not exist (or is older than 6 hours), connect to YQL, create a new cache file and output the XHTML markup. Otherwise, just read the cache and output directly. This way we send a request to the API only once every six hours which is perfect for any practical purposes.

Combined Social Media Followers Count

Combined Social Media Followers Count

Step 2 – XHTML

As mentioned in the PHP section above, the generate() method renders all the XHTML markup used to display the stats. Here is what the generated code looks like:

sample code

<div class="subscriberStats">
    <div class="subscriberCount"  title="25,382+ Total Social Media Followers>25,382</div>

    <div class="socialIcon" title="5,921 RSS Subscribers">
        <a href="http://feeds.feedburner.com/Tutorialzine">
        <img alt="RSS" src="img/rss.png" /></a>
    </div>

    <div class="socialIcon" title="16,813 Fans on Facebook">
        <a href="http://www.facebook.com/smashmag">
        <img alt="Facebook" src="img/facebook.png" /></a>
    </div>

    <div class="socialIcon" title="2,648 Twitter Followers">
        <a href="http://twitter.com/Tutorialzine">
        <img alt="Twitter" src="img/twitter.png" /></a>
    </div>
</div>

This code is fetched via AJAX and displayed on the page. Notice the title attributes. They are used as the contents of the fancy tooltips which are created by jQuery and the tipTip plugin, which we will discuss in a moment.

Step 3 – CSS

The CSS code is also quite simple and straightforward. The subscriberStats is the main outer div, inside it we have a number of .socialIcon divs and the subscrberCount.

css/styles.css

.subscriberStats{
 height:35px;
 padding:5px;
 width:220px;
}

.socialIcon{
 float:left;
 height:32px;
 width:32px;
}

a img{
 border:none;
}

.subscriberCount{
 border-bottom:1px dotted #CCCCCC;
 color:#999999;
 float:left;
 font-size:28px;
 line-height:32px;
 margin-right:10px;
}

#main{
 height:100px;
 margin:140px auto 50px;
 position:relative;
 width:200px;
}

All of these are floated to the left. Also notice that we disable the borders on the icon images on line 14, which are displayed by default and ruin your design.

Step 4 – jQuery

After including the jQuery library to the page, we just need to listen to the $(document).ready event, which is executed when all the markup of the page is accessible (this happens before things like images are loaded and comes earlier than the onload event).

js/script.js

$(document).ready(function(){

 // Using the load AJAX method to fetch the subscriber markup
 // from subscriber_count.php:

 $('#main').load('subscriber_count.php',function(){

  // Once loaded, convert the title attributes to tooltips
  // with the tipTip jQuery plugin:

  $('.subscriberStats div').tipTip({defaultPosition:'top'});
 })

});

#main is the div where we want to insert the stats. This could be your sidebar or website header. The load method fetches the markup from suscriber_count.php and displays it on the page.  The callback function is called after this and all the div titles are replaced with fancy tooltips by the tipTip plugin.

With this our combined social stats widget is complete!

Conclusion

With services like YQL working with third party APIs is a charm. Not only it provides a common interface to a sea of technologies, but it also guarantees that you will be able to access to the services you want even as the underlying APIs change overtime.

What do you think? How would you improve this code?

"