How to Create a Recent Tweets Widget

In this tutorial we'll look at how to create a 'recent tweets' widget. There are a fair number of twitter-related plug-ins in the repository, however I hope that this tutorial will cover some of the important (and generally applicable) methods needed for creating such a plug-in, (whether Twitter based or not).


The Widget Class

The Widget class, WP_Widget, is a helper class for creating widgets. To create a widget, you simply create an extension of this class with four methods: __construct, widget, update and form.

  • __construct initialises the widget. Here you set the widget's unique ID, title, description (for the admin side) and the class(es) to give to the widget's container on the front end.
  • widget – the method responsible for printing the widget's content on the front-end.
  • form – this method should print the widget's settings in the Appearance > Widget form
  • update – this function is responsible for validating the options sent from the widget's form (via form). The array $new_instance contains the options to be validated and the array$old_instance contains the currently saved options. It expects the validated options to be returned, or false to abort updating the options.

Class Construction

We start with constructing the class. To register your widget(s) you need to hook onto the action widgets_init and call register_widget, passing the name of the Widget's class (WP_Widget_Wptuts_Twitter in this case). This snippet sits just after our widget class:

register_widget creates an instance of our widget, and so calls the __construct method. This should set some of the class constants, for instance a unique identifier (the id_base), and the widget's configuration settings, in particular:

  • description – a description of the widget (this will appear on the widget admin page).
  • classname – Class(es) to be added to the widget's class attribute.

You can also specify a 'control options' array – this allows you to specify the width of the widget's admin form (usually 250px), in case you need more space. Aesthetically, though, it's preferable not to change this, and to not overload your widgets with excessive options.

To set these configurations you can use the WP_Widget::__construct method (i.e. parent::__construct). This expects:

  • ID Base – a unique identifier for the Widget class
  • Name – The name of your widget, used in the admin screen.
  • Widget Options – sets the classname and description.
  • Control options – (optional) array of height and width of the widget form.

Then (optionally) we can set the widget's settings and their default values.

You should give your widgets a unique class, as this would help ensure that any styling you provide targets only your widget.


Retrieving Tweets

Before we go any further, we're going to create a helper method which sends a request to the Twitter API. This simple method takes the request (an URL), and uses the function wp_remote_get to retrieve the response. wp_remote_get forms part of the HTTP API that was covered in this tutorial.

The method then checks for any errors: either thrown up by WordPress (with is_wp_error) or by Twitter (by checking the response code). The switch statement in the method allows you to act differently according to that code – in the example below all error responses are converted into a WordPress error object or otherwise the successful response (an array of tweets) is returned.

By keeping both the error code and message, we can make it much easier to debug later on, should any error occur.


The Twitter API

Twitter has extensive documentation on its API – which, among other things, allows you to retrieve your recent tweets, tweets from your 'home' page, or tweets which match a search term. Some of the more advanced API features require authentication via OAuth.

In this tutorial we are after a specific user's tweets (or the user timeline). The URL to retrieve these tweets has a very simple structure:

where {screen-name} should be the user's screen name and the other arguments can be any of those listed here. Typically arguments such as include_entities would be set to true to obtain metadata about the tweets (such as any URLs, or hashtags they contain).


Caching

Twitter imposes a limit on the number of requests you can make: 150 an hour for unauthenticated requests and 350 otherwise. Not only that, but fetching the tweets takes time – increasing your site's load time. Retrieving your tweets from Twitter on every page load is unnecessarily expensive – and particularly so if it's not necessary that your tweets appear on your site immediately after publishing them.

Caching, in particular WordPress' transients, can be used to store your tweets (or any data for that matter) locally in your database. Retrieving them from the database is much quicker than fetching them remotely, and it doesn't contribute to any API limit. Of course, the data will soon become outdated – which is why, stored along with the tweets is an expiry time.

The idea is that when displaying your tweets, if the data has expired (or the tweets aren't present in the database), you fetch them from Twitter and refresh the cache. In this way you can limit the number of requests to Twitter to once every 20 minutes, hour or day depending on how long you are willing to wait for your tweets to be updated. Furthermore, when the tweets aren't being refreshed, you'll enjoy faster load times. Caching, when used properly, is great way of boosting your plug-in's or theme's performance. If you've not used it before, I'd recommend watching this video and following this tutorial.

However – suppose your tweet-cache expires and Twitter's service is down for maintenance. The tweets are deleted from the database, but you are unable to retrieve any tweets from Twitter to replace them, and so will have nothing to display. The solution to this is 'Soft Caching'.


Soft Caching

Soft caching, like caching, attempts to update your tweets once a certain period of time has elapsed. However, unlike 'hard' caching, the previous data is not deleted until a valid response is received with which to replace it. The result is, that should Twitter's API be down – your site will still show the tweets from the last successful refresh.

Soft caching isn't natively supported by WordPress, but Mark Jaquith and Aaron Campbell have produced an excellent class implementation of it. I will be using a slightly simplified method, which I hope will illustrate how soft caching can work in WordPress.

The idea is to manually handle the transient's expiration. Rather than storing the tweets as a transient with an expiration time, you store an array containing the tweets and the expiration time inside a transient that has no expiration time. We can implement this method by using the following function in lieu of set_transient.

Of course, with no expiration time the data is never (or actually, not guaranteed to be) removed and replaced with new data. We now have to take care of this ourselves.

When you retrieve this non-expiring transient, you check if the stored expiration time has passed. If it has, you then attempt to retrieve the new tweets with the above method retrieve_remote_tweets. If that is successful, you update the transient (with the new data and a new expiration time) and use that new data. If it is not, you simply use the currently stored data until you get a successful response from Twitter.

To retrieve the tweets (remotely or locally) and handle the cache, we define the method get_tweets. This takes an array of arguments, with which to generate the Twitter request. For instance:

  • screen_name – the name of the Twitter account for follow
  • count – the number of tweets to retrieve
  • include_rts – 1|0 – 1 to include retweets, 0 to exclude retweets.

The method then uses add_query_arg to build the request URL, and from that generates a key for our transient. This is important – since you want to be using the same key for a different configuration of the widget, particularly if you have multiple instances of the widget.

Hard-coded into this function is an expiration time of 1 hour.

When using WordPress' transient API, you would check if get_transient finds your data in the cache, and if not retrieve or generate the data (say from Twitter) and then update the transient. However, the get_tweets method above will handle all of this – and will return your 'old data' if it is unable to update it. It's still not guaranteed to return data though: it maybe that there are no tweets in the database (e.g. being run for the first time) and it doesn't get a successful response from Twitter. In these instances a WP_Error object is returned – and we will need to ensure your plug-in deals with this and degrades gracefully.


The Form

The job of the form method is to display the widget's options form in the Appearance > Widget page. It passes the currently saved options as an argument (an array). Of course you can then use wp_parse_args to replace any 'missing' values with defaults.

Generally, the widget form should be quite small (and often inside the narrow sidebar) – this can be enlarged with the Control options mentioned earlier, but it's preferred that you keep to the aesthetics of WordPress. For this reason, I'll be following the layout of WordPress' default widget.

I shall also be using the methods $this->get_field_id and $this->get_field_name to generate the name and ID values for the inputs for each instance of a widget, so WordPress can handle their processing for us.

In this example, I'll allow the user to provide a title for the widget, the screen name of whose tweets are to be displayed, a maximum number of tweets and whether or not to include when the tweet was published.


Options Validation

Once you've built the form you need to update the widget options when they are saved. WordPress handles most of this for us – but we still need to validate the data. Validation has been covered in some depth in this article, and if you're not sure what you need to do, or how to validate your data, I'd recommend you check it out.

Whatever is returned from this function is added to the database, so as well as validating data we should make sure it only contains data we are expecting. A good technique is to start with an empty array and only add validated data into it. If you wish to abort the save, you can return false.

The screen name is validated by removing everything except alpha-numerics and underscores.


Displaying the Widget

Finally we come to the method for displaying the widget. All the pieces are in place, all that remains is to produce the widget content itself. The widget method responsible for this passes two arguments: the first is an array of arguments corresponding to the sidebar's widget settings – the display arguments including before_title, after_title, before_widget, and after_widget. The second is the settings for this particular instance of the widget – this is an array of the settings saved from our form.

I shall use another helper function to generate the list of tweets, but the following should be the outline of all widgets:

The generate_tweet_list method simply retrieves the tweets with get_tweets – and if there were no errors, loops through the tweets and displays them in a list. For each tweet it applies the method make_clickable – this scans the tweet and makes any screen name, hashtag or link into an actual link (see below).

Depending on the settings, it also appends when the tweet was published using the WordPress function human_time_diff.

You'll notice that I've included calls to wp_enqueue_script and wp_enqueue_style. These are commented out because I haven't needed to include any styling or scripts. But since 3.3 you can use these functions while the body of the page is being generated (i.e. in widget or shortcode callbacks). If I did need to enqueue any scripts for this widget to function, doing so here ensures that they are only loaded when they are actually needed. You should make sure you are not needlessly loading scripts and styles.


Make Clickable

Here we define the method make_clickable. This takes a tweet object and returns the tweet's content, after replacing any URLs, hashtags, users or media URLs with an appropriate link. Since we set include_entities to true, the tweet object includes the tweet's 'entities'. An entity is any URL, user mention, hashtag or media included in the tweet. To do this we use the case-insensitive function str_ireplace.

The finished product (subject to your theme's styling), should look something like this:


Shortcode

In this tutorial I've tried to stick to a basic, but important principle: separation of concerns. Our class is a collection of methods, and the idea is that each method should be responsible for a specific purpose. I have a callback for displaying the outline of the widget, which calls generate_tweet_list to produce the list itself, which uses get_tweets to retrieve the tweets – itself using retrieve_remote_tweets to interact directly with the Twitter API.

There are several reasons for this:

  • Readability – breaking code into smaller chunks, makes it much easier to read, and much easier to debug
  • Reducing duplication of code – without separating out my code, if I had two methods which both try to retrieve tweets from Twitter, both would have to include all the necessary checks and cache handling. But by separating my functions as shown, they could both use the get_tweets method.
  • Easy to edit – If Twitter ever change their API, I now have only one function to edit, and I can be sure the rest of the plug-in will continue to work fine.
  • Extendibility – The layout of this code is more akin to Lego than Plasticine. Lego is by far much better. We now have a collection of 'Lego brick' functions with which we can make more things.

To illustrate the last point. We have created a widget which displays a list of recent tweets. Because of separation of concerns, with only a few extra lines (added outside the class) we can create a shortcode which does exactly the same thing:

The tweets can then be displayed with the shortcode: [wptuts_twtter screen_name="stephenharris88"]. It also accepts the attributes count, published_when and include_rts.

We also have the very useful, and generic, method retrieve_remote_tweets which can interact with Twitter in any way we like. It will return either a valid response or a WordPress error object with the failure message.


Final Comments

The WP-TLC-Transients class, mentioned earlier, is a more generic implementation of soft caching, allowing you to specify functions with which to update the cache. It also implements background updating: only refreshing the cache once the page has loaded. The class is designed to be adopted into plug-ins (after renaming to prevent conflicts), and doing so allows for efficient soft caching handling. In fact this is what Aaron Campbell's Twitter Widget Pro plugin does.

Note: If you are using shared hosting then other websites may share your IP. Twitter API requests from these sites will contribute to your rate limit. If you find you are constantly being rate limited, then this is the likely cause.

The plug-in created in this tutorial is available on my GitHub.

Tags:

Comments

Related Articles