About The Author

Hello, I’m Daniel and I make things for the web. I’m the CTO at Kinsta and I write for a number of amazing publications like Smashing Magazine and … More about Daniel

How To Create A Twitter Widget

Quick Summary

Twitter needs no introduction. It has become the way to reach audiences for some people and companies and a place to hang out for others. Placing a Twitter feed on one’s website has almost become compulsory.

Table of Contents
Membership counter

Members support Smashing

Wonderful, friendly people who keep this lil' site alive — and get smarter every day.

Are you smashing, too? →

Twitter needs no introduction. It has become the way to reach audiences for some people and companies and a place to hang out for others. Placing a Twitter feed on one’s website has almost become compulsory. Embedding a feed isn’t all that difficult if you are comfortable with Twitter’s default widget, but making your own will enable you to blend it into your website seamlessly.

photodune-4052663-twitter-on-keyboard-xs

The Result

The result of our effort will be a WordPress widget that can be placed in a widgetized sidebar. It will display the user’s details on top and the latest few items from the user’s feed. You can see it in action in our Musico theme, although the screenshot below says it all.

finished_widget

About The Twitter Terms Of Service

Because this is a custom widget, you control what and how elements are displayed. Make sure to read Twitter’s “Developer Display Requirements” to find out what you need to display. I will be breaking some of the rules for simplicity’s sake, but bolting on stuff will be a trivial matter once you’ve finished this article.

Further Reading on SmashingMag:

Note that conforming to the requirements is a must. If you do not, you run the risk of your ID being banned which means that your widget will not display any tweets.

First Step: Create A Twitter App

Before writing any code, we’ll have to get our hands on a Twitter app or, more appropriately, Twitter API credentials. The process is explained in a video that I made:

In case you prefer reading to watching a video, here are the basic steps:

  1. Log into Twitter’s developers section.
  2. Go to “My Applications,” and click “Create a new application.”
  3. Fill out the required fields, accept the rules of the road, and then click on the “Create your Twitter application” button. You will not need a callback URL for this app, so feel free to leave it blank.
  4. Once the app has been created, click the “Create my access token” button.
  5. You’re done! You will need the following data later on:
    • consumer key,
    • consumer secret,
    • access token,
    • access token secret.

Add Our App’s Details

To add some options to our theme quickly, we’ll be using the theme customizer, introduced in WordPress 3.4. Smashing Magazine has an exhaustive article on it, if you’re interested to learn more. For now, we’ll just add the bare necessities.

To enable quick access to the theme customizer, I like to use the following snippet:


add_action ('admin_menu', 'my_theme_customizer');
function my_theme_customizer() {
  add_theme_page(
    __( 'Customize Theme Options', THEMENAME ),
    __( 'Customize Theme', THEMENAME ),
    'edit_theme_options',
    'customize.php'
  );
}

Adding the code above to your theme’s functions.php file will generate a link to the customizer in the “Appearance” section of the admin area. To add some options, we’ll need to create a class. Add a file named MyCustomizer.class.php to the theme’s directory, and paste the following code in it:


<?php
class MyCustomizer {
  public static function register ( $wp_customize ) {

    /** Sections **/
    $wp_customize->add_section( 'twitter_api' , array(
      'title'    => __( 'Twitter API Details', 'mytextdomain' ),
      'priority' => 10,
    ));

    /** Settings **/
    $wp_customize->add_setting( 'twitter_consumer_key' );
    $wp_customize->add_setting( 'twitter_consumer_secret' );
    $wp_customize->add_setting( 'twitter_access_token' );
    $wp_customize->add_setting( 'twitter_access_token_secret' );

    /** Controls **/
    $wp_customize->add_control(
      'twitter_consumer_key',
       array(
        'label' => __( 'Consumer Key', 'mytextdomain' ),
        'section' => 'twitter_api',
        'priority' => 10,
       )
    );
    $wp_customize->add_control(
      'twitter_consumer_secret',
       array(
        'label' => __( 'Consumer Secret', 'mytextdomain' ),
        'section' => 'twitter_api',
        'priority' => 20,
       )
    );
    $wp_customize->add_control(
      'twitter_access_token',
       array(
        'label' => __( 'Access Token', 'mytextdomain' ),
        'section' => 'twitter_api',
        'priority' => 30,
       )
    );
    $wp_customize->add_control(
      'twitter_access_token_secret',
       array(
        'label' => __( 'Access Token Secret', 'mytextdomain' ),
        'section' => 'twitter_api',
        'priority' => 40,
       )
    );
   }
}
add_action( 'customize_register' , array( 'MyCustomizer' , 'register' ) );
?>

There are a couple of things to note about the code above. All of the details we need to add to the customizer are encapsulated in a class. The class is registered at the bottom of the code block, using a hook.

We need to do three things with the class to get our options to show up:

  • Create a new section to house these options in one logical group. We use the add_section() function to do this; all we need to add is a title.
  • We need to tell WordPress that we are adding particular settings. The function used is add_setting, which can take a default parameter as well, but we don’t really need it here.
  • Finally, we tie a control to the setting so that the user can manipulate it. A number of controls are available; here, we need a simple text box. Using the add_control() function, we specify the setting to be modified, the label of the control and the section it is in. The type of control is not specified because the default is the usual input box.

apisettings

Notice the “priority” setting for some elements. This determines the order they show up in. The reason they are multiples of 10 is that, if you realize later that you need to add something between two settings, you won’t need to rewrite all of the priorities; you would just use “15” for the new element.

Don’t forget to include this class in functions.php so that the code is executed.


include( 'MyCustomizer.class.php' );

Once all that is done, you can fill out the details. You will be able to access the values using the get_theme_mod( ‘option_name’ ) function (more on that below).

Integrate The API

We now have a way to retrieve our API details, but we are not in contact with the API just yet. Doing that is a bit difficult; luckily, others have done the grunt work for us. For this tutorial, I’ll use Codebird, a PHP class for interacting with the Twitter API.

Download the codebird.php file from Codebird, put it in your main theme folder, and set it up like so:


add_action( 'init', 'my_twitter_api' );
function my_twitter_api() {
  global $cb;
  $consumer_key = get_theme_mod( 'consumer_key' );
  $consumer_secret = get_theme_mod( 'consumer_secret' );
  $access_token = get_theme_mod( 'access_token' );
  $access_secret = get_theme_mod( 'access_secret' );

  include( 'codebird.php' )
  Codebird::setConsumerKey( $consumer_key, $consumer_secret );
  $cb = Codebird::getInstance();
  $cb->setToken( $access_token, $access_secret );
}

Now you’ll be able to use Codebird by invoking the $cb instance. Let’s set this aside for now; we’ll get back to it later!

Create A Widget

I like to separate widgets into individual files. So, before we do anything else, create a widgets directory and put a file in it named MyTwitterWidget.class.php. Include this file in functions.php just as we did above:


include( 'widgets/MyTwitterWidget.class.php' );

Add the following PHP code to the file. This is the general starting point for widgets.


<?php
class MyTwitterWidget extends WP_Widget {
  /** Widget setup **/
      function MyTwitterWidget() {
      parent::WP_Widget(
      false, __( 'My Twitter Widget', 'mytextdomain' ),
      array('description' => __( 'Displays a list of tweets from a specified user name', 'mytextdomain' )),
      array('width' => '400px')
    );
  }
  /** The back-end form **/
  function form( $instance ) {

  }
  /** Saving form data **/
  function update( $new_instance, $old_instance ) {

  }
  /** The front-end display **/
  function widget( $args, $instance ) {

  }
}
register_widget('MyTwitterWidget');
?>

There are four functions here, each with a particular role in creating the widget.

  • The first function is the constructor. The widget’s title and description may be specified here.
  • The form function takes care of the back-end form. Putting a few functions in there makes it very easy to assemble a form. WordPress takes care of the rest.
  • The update function enables you to add any special code to the saving process.
  • The widget function handles the front-end display of the widget.

As we build the widget, you’ll see that we’ll need some custom functions. But until then, let’s go function by function.

The Back-End Form

We want to give the user the option to change the title of the widget, to specify how many tweets to show, and to specify their Twitter user name. The basic pattern for creating these options is as follows:


<p>
  <label for='<?php echo $this->get_field_id( 'option_name' ); ?>'>
    <?php _e( 'Title:', 'mytextdomain' ); ?>
    <input class='widefat' id='<?php echo $this->get_field_id( 'option_name' ); ?>' name='<?php echo $this->get_field_name( 'option_name' ); ?>' type='text' value='<?php echo $values['option_name']; ?>' />
  </label>
</p>

The $values array is a list of all of this widget’s options, which are specified elsewhere. All of our options will follow the pattern below. Here are the functions to look out for:

  • get_field_id()Outputs the ID of the field for your option.
  • get_field_name()Outputs the name of the field for your option.

Using these functions is crucial because the name and ID of these fields can get pretty funky when multiple widget instances are in multiple sidebars.

The complete code for our form looks something like this:


<?php
  $defaults = array(
    'title'    => '',
    'limit'    => 5,
    'username' => 'bonsaished'
  );
  $values = wp_parse_args( $instance, $defaults );
?>
<p>
  <label for='<?php echo $this->get_field_id( 'title' ); ?>'>
    <?php _e( 'Title:', 'mytextdomain' ); ?>
    <input class='widefat' id='<?php echo $this->get_field_id( 'title' ); ?>' name='<?php echo $this->get_field_name( 'title' ); ?>' type='text' value='<?php echo $values['title']; ?>' />
  </label>
</p>

<p>
  <label for='<?php echo $this->get_field_id( 'limit' ); ?>'>
    <?php _e( 'Tweets to show:', 'mytextdomain' ); ?>
    <input class='widefat' id='<?php echo $this->get_field_id( 'limit' ); ?>' name='<?php echo $this->get_field_name( 'limit' ); ?>' type='text' value='<?php echo $values['limit']; ?>' />
  </label>
</p>

<p>
  <label for='<?php echo $this->get_field_id( 'username' ); ?>'>
    <?php _e( 'Twitter user name:', 'mytextdomain' ); ?>
    <input class='widefat' id='<?php echo $this->get_field_id( 'username' ); ?>' name='<?php echo $this->get_field_name( 'username' ); ?>' type='text' value='<?php echo $values['username']; ?>' />
  </label>
</p>

The only addition made to this code is the retrieval of the values. The function is passed the current values in the $instance parameter. I’ve added a defaults array in case no values have been set. The defaults and the instance data arrays have been merged, resulting in the final $values array.

Save The Form’s Data

I’m sure you’ll be relieved by the simplicity of this. Here’s the complete code in the update() functions.


return $new_instance;

The $new_instance parameter has all of the new data in it. All we need to do is return it. The purpose of the update function is to allow for some validation or manipulation.

Display The Tweets

Now for the hard part! Retrieving the tweets is not that difficult, but if we do it on every page load, we’ll be rate-limited by Twitter in no time. We’ll need to find a way to cache the results so that we only bother Twitter, say, every five minutes. The way I like to handle these problems is to side-step them altogether and code as if the solution were already in place. Let’s assume that we’ve already written the functions that we need for this and proceed to create the front end:

First, let’s look at the general template needed to display widgets:


echo $args['before_widget'];
echo $args['before_title'] . $instance['title'] .  $args['after_title'];
echo $args['after_widget'];

The $args parameter holds some structural information from the sidebar you created. We just output these to make sure that this widget conforms to all of your other widgets.

Now, let’s list some tweets:


$tweets = $this->get_tweets( $args['widget_id'], $instance );
if( !empty( $tweets['tweets'] ) AND empty( $tweets['tweets']->errors ) ) {

  echo $args['before_widget'];
  echo $args['before_title'] . $instance['title'] .  $args['after_title'];

  $user = current( $tweets['tweets'] );
  $user = $user->user;

  echo '
    <div class="twitter-profile">
    <img src="' . $user->profile_image_url . '">
    <h1><a class="heading-text-color" href="http://twitter.com/' . $user->screen_name . '">' . $user->screen_name . '</a></h1>
    <div class="description content">' . $user->description . '</div>
    </div>  ';

  echo '<ul>';
  foreach( $tweets['tweets'] as $tweet ) {
    if( is_object( $tweet ) ) {
      $tweet_text = htmlentities($tweet->text, ENT_QUOTES);
      $tweet_text = preg_replace( '/http://([a-z0-9_.-+&!#~/,]+)/i', 'http://$1', $tweet_text );

      echo '
        <li>
          <span class="content">' . $tweet_text . '</span>
          <div class="date">' . human_time_diff( strtotime( $tweet->created_at ) ) . ' ago </div>
        </li>';
    }
  }
  echo '</ul>';
  echo $args['after_widget'];
}

Let’s dissect this to understand what’s going on.

  • Line 1We’re assuming that we have a get_tweets() function that will return a list of tweets in some form. We haven’t written this yet, but by assuming that we have done so, we’ll know what to include in the function’s code.
  • Line 2If the tweets list is not empty and there are no errors, we can display the widget.
  • Lines 7–8All tweets are from the same user, and each tweet contains the user’s data. In line 7, we’re just grabbing the first tweet. In line 8, we’re pulling the user’s details into the $user variable.
  • Lines 10–16We use data from the $user object to build a simple display for the user’s account. It includes the image, short description and user name.
  • Lines 18–29Using data in the $tweets['tweets'] variable, we build a list of tweets. The preg_replace() in there is needed to convert links (which arrive as plain text) into clickable elements.

All that’s left is to figure out how the get_tweets() function should work. We already know that it can’t directly get the tweets from Twitter, so we’ll need to use some trickery!

To pull this off, our get_tweets() function will need to do the following:

  1. Get the list of tweets from our own database.
  2. If no list is there or the list is more than five minutes old, then it needs to grab the list from Twitter.
  3. Once we get results from Twitter, we save them to our database and add a timestamp to make sure we don’t grab it again before the five minutes is up.

To make things more modular, we’ll create three functions.

  • get_tweets()Pulls a list of tweets from our database.
  • retrieve_tweets()Pulls a list of tweets from Twitter.
  • save_tweets()Saves a list of tweets from Twitter to our database.

Retrieve Tweets From Twitter

In the MyTwitterWidget class, let’s create this function and make it retrieve some tweets:


function retrieve_tweets( $widget_id, $instance ) {
  global $cb;
  $timeline = $cb->statuses_userTimeline( 'screen_name=' . $instance['username']. '&count=' . $instance['limit'] . '&exclude_replies=true' );
  return $timeline;
}

As you can see, this is pretty easy, thanks to the Codebird class. We simply use one of its functions, statuses_userTimeline(), to retrieve our list. Our own functions receive the widget’s ID and the instance data, which we use to tell Codebird which user’s tweets we want and how many to retrieve.

Save Tweets to the Database

To save the tweets to the database, we’ll need to use the ID of the widget and the actual tweets, and we’ll need to store the time when we last updated them.


function save_tweets( $widget_id, $instance ) {
  $timeline = $this->retrieve_tweets( $widget_id, $instance );
  $tweets = array( 'tweets' => $timeline, 'update_time' => time() + ( 60 * 5 ) );
  update_option( 'my_tweets_' . $widget_id, $tweets );
  return $tweets;
}

This widget also receives the widget’s ID and the instance data. We use these to retrieve the tweets, using the retrieve_tweets() function that we created above. We’ll add that to our $tweets array, which contains the data returned from Twitter and the time of update.

The time of update is five minutes from now. When we display our tweets, we’ll use this value to determine whether to display the tweets in the database or to grab the list from Twitter again (to ensure we have the most recent ones).

We use the widget’s ID to save the list to the database, using WordPress’ options table. This ensures that we can save the proper Twitter details for each instance of our Twitter widget.

Get Tweets From the Database

We’ve finally arrived at the get_tweets() function. Let’s take a look. Explanation ensues!


function get_tweets( $widget_id, $instance ) {
  $tweets = get_option( 'my_tweets_' . $widget_id );
  if( empty( $tweets ) OR time() > $tweets['update_time'] ) {
    $tweets = $this->save_tweets( $widget_id, $instance );
  }
  return $tweets;
}

First, we retrieve the tweets from the database using the options table. If the options table is empty or the update time has past our limit, then we use the save_tweets() function. This will retrieve the tweets from Twitter and save them to the database (and also return them so that we can use them right away).

Conclusion

While this methodology does not lack complexity, it has a tight and clear logic to it, which arises from the thoughtful way that WordPress implements widgets and the new theme customizer.

Once you grasp the basic idea behind how this widget is created, you can add many of your own and customize them to your (or your client’s) delight.

Smashing Editorial (al, ea)