WordPress Tweets & Retweets Count

It’s not a secret that being social is one of the key factors in today’s blogging world, and you’re probably tweeting your new blog posts every day anyway. You might have your Facebook Like, Google +1 and Tweet buttons set up on your blog already, and today’s topic is about measuring the results of your Tweet button and Twitter activity around your posts. You might say that the button itself is capable of showing the tweet count and you’re right, but today we’ll be doing things a little bit differently.

Today’s tutorial is about grabbing the tweets/retweets count from Twitter in plain text using their API and WordPress’ HTTP functions. It’s about caching the values for performance reasons and for just being nice to Twitter. It’s also about displaying those tweet counts in the posts list table for a quick overview of which posts are being tweeted about and which are not without having to scroll and spot those Tweet buttons of yours through multiple pages.

Getting Started

For this tutorial you’ll need to either create a new plugin, or use your functions.php file of your theme, both will work just fine. My recommendation here is the plugin file, since the end result will not affect the appearance of your website. We’ll be using an action and a filter, so make sure you’re familiar with the WordPress actions and filters references.

We’ll be using the wp_remote_get function which is a wrapper function to the WP_Http class in WordPress. It’ll fire a GET request the Twitter API and grab the retweet count of a URL that we specify. The Twitter API will return back JSON data so we’ll be using the json_decode PHP function to parse the output.

The actual printing of the tweets and retweets counts will be in the table shown in your All Posts screen in WordPress, so take a look at our custom columns tutorial for a detailed explanation of how that works. Well and that’s pretty much it so let’s get started!

Creating the Custom Columns

As the columns tutorial mentioned above suggests, we’re going to add a new column to the posts screen and we’ll call it Tweet Count. The action for that new column is defined in the second function.

add_filter( 'manage_edit-post_columns', 'my_columns_filter' );
add_action( 'manage_posts_custom_column', 'my_custom_column' );
function my_columns_filter( $columns ) {
	$columns['tweet_count'] = 'Tweet Count';
	return $columns;
}
function my_custom_column( $column ) {
	global $post;
	if ( $column == 'tweet_count' ) {
		echo get_tweet_count( $post->ID );
	}
}

We’re using the get_tweet_count function, one that we’ll deal with later, but for now you can just define it to return 0, like this:

function get_tweet_count( $post_id ) {
	return 0;
}

So at this point you can take a look at what your posts list looks like and you should see a new column called Tweet Count filled with 0′s for each entry, obviously, since our function is fake. You can hide and show the column via the Screen Options panel on the top right just like any of the other columns on screen.

Tweet Count in WordPress Posts

Grabbing the Tweets Count

Let’s now work on the get_tweet_count function that we have faked above. Basically you’re going to fire a GET request against the Twitter API to retrieve the tweet count for a given URL. The API endpoint itself doesn’t seem to be documented by Twitter, but Otto has a good discussion with samples about where that came from.

function get_tweet_count( $post_id ) {
	$url = get_permalink( $post_id );
	$count = 0;

	$data = wp_remote_get( 'http://urls.api.twitter.com/1/urls/count.json?url=' . urlencode( $url ) );
	if ( ! is_wp_error( $data ) ) {
		$response = json_decode( $data['body'] );
		if ( $response->count ) $count = $response->count;
	}

	return $count;
}

So we’re grabbing the given post’s permalink, encoding it and firing the GET request via wp_remote_get. We then make sure an error hasn’t been returned and if everything’s okay, decode the given JSON data and set the count. If for some reason there’s no count or one could not be retrieved, the function will fall back to zero.

Once that is set, you should be able to see the counts on that posts list I mentioned earlier. You’ll probably be getting back 0′s if you’re trying this out locally, of course, who tweets posts to localhost? Here’s a screenshot from a real-world environment:

Retweet Count in Action

You might also notice that your posts page now takes quite some time to load. That’s because before rendering every count, an HTTP request is fired, that usually makes 10 HTTP requests per page which is quite intensive, hence the lagging. Let’s take care of that with some simple caching.

Caching the Values

There are loads of different techniques and approaches to values and objects caching. Our goal is to save the retweet count from Twitter for a while, say an hour or so and upon each next request serve the value from cache, instead of firing new HTTP requests.

Let’s use the post meta for each of the posts to store the count value as well as a timeout value. Each time a retweet count is requested for a post, we’ll look into the post meta, see if there’s a value, see how old that value is and whether we should refresh the cache and fire a new HTTP request to the Twitter API if needed.

Here’s how I modified the get_tweet_count function to implement some basic caching.

function get_tweet_count( $post_id ) {
	$meta = get_post_meta( $post_id, '_tweet_count', true );
	if ( isset( $meta['timeout'], $meta['count'] ) && time() < $meta['timeout'] )
		return $meta['count'];

	$url = get_permalink( $post_id );
	$count = 0;

	$data = wp_remote_get( 'http://urls.api.twitter.com/1/urls/count.json?url=' . urlencode( $url ) );
	if ( ! is_wp_error( $data ) ) {
		$response = json_decode( $data['body'] );
		if ( $response->count ) $count = $response->count;
	}

	$meta = array(
		'count' => $count,
		'timeout' => time() + 3600
	);
	update_post_meta( $post_id, '_tweet_count', $meta );

	return $count;
}

To understand the top part, you should take a closer look at what’s happening closer to the bottom. When a count is retrieved, we simply create a $meta associative array to store our count and a timeout value which is set to “one hour from now”. We use the update_post_meta function to record that array to our post meta under the _tweet_count key. The leading underscore means that it’s a hidden meta value, one that cannot be modified from the “Custom Fields” panel when editing the post.

After the array is recorded, the count is returned. Now look again at the top part of the function where the get_post_meta function is used to retrieve that value from the post meta, see if there’s a count and timeout, measure the timeout and return the count from cache if it’s still valid. When the current time is greater than the timeout value that we have set, it means that an hour has passed and we should ask the Twitter API again.

This is quite a basic caching technique, but absolutely works with these kind of things. So after implementing that, a quick check and a couple of refreshes on your posts list page will show you that the values are taken from cache, thus the table loads lightning fast, and revalidated once every hour. Congratulations!

Final Thoughts & Conclusion

One last thing worth mentioning is that Twitter doesn’t always like it when you fire too much queries against it’s API, especially an undocumented one, made for almost internal use. Caching obviously helps, but think about what happens when your cache is old and you’re displaying 200 posts per page in your posts list. That will fire 200 requests to Twitter in one go.

One good technique to solve that would be to remove the HTTP requests to Twitter from the get function and return only the values from the post meta. Then use scheduled jobs to update the the post meta values, one at a time, with a decent interval.

Well, that’s about it my friends. Let us know about how you deal with your social metrics, tweets and retweets, likes and the rest. Anybody managed to implement a similar technique to measure +1 “pluses” or Facebook Likes? Share your thoughts in the comments section below!

Thank you so much for reading and stay tuned for more.