Twitter followers count (and much more) in WordPress

I had created the monster. Actually I adopted small cute code from Yoast then changed its flavor from FeedBurner to Twitter… And then I let it out on WpRecipes and it run away to wander over many blogs and slowly become old, dirty, scary and unmaintained.

So when Konstantin Kovshenin and Viper007Bond recently presented their modern take on Twitter followers count in WordPress I felt slightly guilty to nitpick on their code, when my is only worthy to be kept under wraps. So I lassoed my monster, took it home to NetBeans pens and spent some time on renovating it.

Common issues with Twitter snippets for WordPress

  • poor integration – WordPress has extensive set of functions to ensure code works in many hosting environments, many snippets ignore that luxury and use generic functions;
  • no caching – Twitter API has restrictive rules and snippets that bug it on every page load will easily exhaust limit, even on moderately visited site;
  • no failover – snippets often assume best case scenario (guilty on many occasions myself) and you are left with errors and no value to show when something goes wrong;
  • narrow scope – Twitter offers wealth of information, but most snippets are hardcoded for single user and returning followers count only, while you can get much more from it.

Code

function rarst_twitter_user( $username, $field, $display = false ) {
	$interval = 3600;
	$cache = get_option('rarst_twitter_user');
	$url = 'http://api.twitter.com/1/users/show.json?screen_name='.urlencode($username);

	if ( false == $cache )
		$cache = array();

	// if first time request add placeholder and force update
	if ( !isset( $cache[$username][$field] ) ) {
		$cache[$username][$field] = NULL;
		$cache[$username]['lastcheck'] = 0;
	}

	// if outdated
	if( $cache[$username]['lastcheck'] < (time()-$interval) ) {

		// holds decoded JSON data in memory
		static $memorycache;

		if ( isset($memorycache[$username]) ) {
			$data = $memorycache[$username];
		}
		else {
			$result = wp_remote_retrieve_body(wp_remote_request($url));
			$data = json_decode( $result );
			if ( is_object($data) )
				$memorycache[$username] = $data;
		}

		if ( is_object($data) ) {
			// update all fields, known to be requested
			foreach ($cache[$username] as $key => $value)
				if( isset($data->$key) )
					$cache[$username][$key] = $data->$key;

			$cache[$username]['lastcheck'] = time();
		}
		else {
			$cache[$username]['lastcheck'] = time()+60;
		}

		update_option( 'rarst_twitter_user', $cache );
	}

	if ( false != $display )
		echo $cache[$username][$field];
	return $cache[$username][$field];
}

Updates

  • 2010-05-16 changed memory cache to single static variable (what it should have been in the first place) and to hold decoded JSON data instead of raw response.

Example usage

echo rarst_twitter_user('rarst', 'name').' has '.
rarst_twitter_user('rarst', 'followers_count').' followers after '.
rarst_twitter_user('rarst', 'statuses_count').' updates.';

Example result

Rarst has 247 followers after 3181 updates.

Features

As you see in example above this code is not limited to followers count. It can fetch any non-nested value returned by Twitter users/show API method.

It has two levels of cache:

  • queried values are stored as array in database, using WP options, for $interval seconds;
  • API responses are stored in memory so you can query any number of fields, without generating multiple API requests.

This should be safe to use for multiple values and multiple users at the same time, without worrying about exhausting API limit.

Shortcomings

I wrote this from start to finish in one evening so there may be things left to polish. Slightly worried about using variable variables for memory cache, but seems to work fine in my tests [changed to static variable].

I wanted to add error detection for cases when user name is mistyped and such. But WP HTTP API returns error and discards response data because Twitter API gives 404 on such requests. From googling around this behavior might be platform-specific (my local development stack is on Windows) and so tricky to get right.

Overall

Scary and bulky but powerful. :) And I am holding this one on a leash, feel free to point out issues and make suggestions to be implemented.

Related Posts

23 Comments

  • The advantages of transients over options are that they auto-expire (no need for your expiry check code, that’s done by WordPress on transient get) and that if you have an object cache enabled (such as memcache), then transients are stored only in the cache and not the database (unlike options which are stored in both).

    Transients are designed for exactly this kind of thing. :)

    Also, in my defense for my code only being able to do followers, I was merely trying to improve upon Konstantin Kovshenin’s code to show the best way to code such a feature rather than actually trying to come up with a comprehensive function.

    Regardless, nice code. :)

  • @Alex

    Expiration is exactly my gripe with transients – see failover in common issues. If transient expired but we failed to fetch new value then we have nothing to show. I had such issues a looot with FeedBurner when its API was unstable.

    Transients are great but not when you depend on third party source for information. You can easily end up without transient and information both.

    As I put in the start of the post your code is modern and very nice actually. :) I was generalizing about lots of Twitter snippets I keep seeing and most are much worse.

    Mine is kinda overcoded. :) Started with updated version and went on to flexible fields, then decided to scale it for multiply users… And here I am with new beast.

  • Awesome Rarst, good thinking with the ‘not only followers count’ part! It is sometimes useful to retrieve updates count, following count and maybe the user pic ;)

    Nice job!

    ~ K

  • @Konstantin

    Thanks. :) I suspect this can be slimmed down some more. I always tend to write a page code at start and then week later it is down to few lines, heh.

    I also thought about making it into class for convenience, but that by logic will require separate objects for multiply users. Will think about that some more.

  • Hi Rarst – thanks million for keeping your code updated here. I know nothing about php…

    (1) Do I place this code in my functions.php file?

    //from:
    function rarst_twitter_user(
    //up to + including:
    return $cache[$username][$field];
    }

    (2) Do I place this code in my html?

    (3) How do I re-write the above so it’s this one line, which was this in your old code:

    echo ‘Why are ‘.$tw[‘count’].’ readers following val archer on twitter today ?’;

    (4) where do I enter my username? Your old code had this line:

    $xml=file_get_contents(‘http://twitter.com/users/show.xml?screen_name=valarcher’);

    but I can’t find something similar in this new code.

    thank you for your kind help – Val

  • sorry (2) didn’t display, I’ll rewrite it with written as \ and /

    \?php
    echo rarst_twitter_user(‘rarst’, ‘name’).’ has ‘.
    rarst_twitter_user(‘rarst’, ‘followers_count’).’ followers after ‘.
    rarst_twitter_user(‘rarst’, ‘statuses_count’).’ updates.’;
    ?/

  • @Val

    1 – yes

    2 – that or whatever you make of it, it is more flexible than past snippet was

    3 and 4 are together now:

    echo 'Why are '.rarst_twitter_user('valarcher', 'followers_count').' readers following val archer on twitter today ?';

  • Hi Rarst – thank you! works great. I don’t get that “warning – failed to open stream” message any more, that I used to get as a result of twitter API “restrictive rules” (got it even after my web host white-listed my server at twitter).

    I guess no more error messages is because your new code “should be safe to use for multiply values and multiply users at the same time, without worrying about exhausting API limit.”

    P.S. you use “multiply” but in English it’s multiple, like multiple values + multiple users :) You multiply 2 x 3 to get 6, and 6 is a multiple of 2 (I think)

  • @Val

    Glad it works fine for you. :)

    Thanks for catch with multiple, confused the words. :) English is not my native language.

  • Wow Rarst this is a super sweet peace of code. thanks so much for the tutorial!

  • @WPExplorer

    You are welcome! btw you missed one “r” in via link. ;)

  • This is working great. I am trying to figure out how I would get the status -> text?

  • @Luke

    As post mentions this was written primarily for stats snippets and non-nested values (everything related to last status is nested in status field). I hadn’t used it in a while.

    For starters you can try this – pass “false” for display argument, get “status” field (it should return array), assign to variable, get value for “text” array key out of that variable.

  • […] not one for reinventing the wheel unnecessarily, so for all the Twitter stats I used @rarst‘s Twitter Snippet. The snippet allows you to grab the twitter username, followers and status count. It’s also […]

  • It works fine for me, thanks for the great functions.

  • Thanks for the script. I have a question about it though. A couple of months ago i made my own little script to get my twitter followers. it worked on localhost but testing it on my server it didn’t work anymore. my first guess was twitter not allowing a lot of requests from the same server as my website is hosted on a shared server. i never went back to find out why it really didn’t work. now i’m thinking about trying to get your script to work. do you know anything about any restrictions by twitter?

  • Hi and thanks for this.
    I wonder how I can use the function in a text widget or something.

Comments are closed.