Paulund
2012-12-03 #wordpress

Twitter Stream WordPress Widget

In a previous article last year I wrote a tutorial about how to Create WordPress Widget To Display Twitter Updates, since then I have learnt a lot more about Wordpress development. For this reason I have decided to revisit this widget and make some changes. When looking back at the code I noticed it was just a mess, I wasn't inheriting the WP_Widget class, it wasn't object oriented, it wasn't nice code. I decided to delete everything on this and start a fresh with a new Twitter stream widget, this time using the WP_Widget class. In this tutorial we are going to look at how to create a Twitter stream widget in Wordpress using the WP_Widget class.

What We Are Going To Create?

This widget is going to display the latest tweets from the given Twitter account. We don't want to limit the amount of tweets to show this will completely up to the end user of the Widget. We want the Widget to pick up all links in the Twitter stream and make them clickable on the page. We want Twitter usernames to be clickable on the page, so if you mention anyone in your Tweets people can click through to their profile straight from your Website. We also want to display the Twitter follow button on the widget making it easy for your visitors to follow you.

Wordpress Widgets

Before we start coding the Widget we need to understand what a Wordpress Widget is and how we can use the Wordpress Widget API to easily create a Wordpress Widgets. A Wordpress widget is a piece of PHP Code which will run inside a Wordpress sidebar. A Wordpress sidebar is a registered area in your theme where you can add Wordpress Widgets. Wordpress Widgets can easily be added to sidebars by going to the Widget page in the Dashboard and navigate to Appearance -> Widgets. From this Widget page you are able to drag and drop widgets into a sidebar of your choice. The widget should have some sort of Admin form so you can edit the data shown by the widget.

Wordpress WP_Widget

To create a Wordpress widget all you need to do is inherit from the standard WP_Widget class and use some of it's functions. There are 3 main functions that need to be used for the widget to work these functions are form(), widget() and update(). The WP_Widget class is located in wp-includes/widgets.php.

Wordpress Starter Widget

Below is the boilerplate of a Wordpress widget, when you create a new widget just copy and paste the below code as a starting point for your Widget.

/**
 * Adds Foo_Widget widget.
 */
class Foo_Widget extends WP_Widget {

	/**
	 * Register widget with WordPress.
	 */
	public function __construct() {
		parent::__construct(
	 		'foo_widget', // Base ID
			'Foo_Widget', // Name
			array( 'description' => __( 'A Foo Widget', 'text_domain' ), ) // Args
		);
	}

	/**
	 * Front-end display of widget.
	 *
	 * @see WP_Widget::widget()
	 *
	 * @param array $args     Widget arguments.
	 * @param array $instance Saved values from database.
	 */
	public function widget( $args, $instance ) {
		extract( $args );
		$title = apply_filters( 'widget_title', $instance['title'] );

		echo $before_widget;
		if ( ! empty( $title ) )
			echo $before_title . $title . $after_title;
		?>Hello, World!<?php
		echo $after_widget;
	}

	/**
	 * Sanitize widget form values as they are saved.
	 *
	 * @see WP_Widget::update()
	 *
	 * @param array $new_instance Values just sent to be saved.
	 * @param array $old_instance Previously saved values from database.
	 *
	 * @return array Updated safe values to be saved.
	 */
	public function update( $new_instance, $old_instance ) {
		$instance = array();
		$instance['title'] = strip_tags( $new_instance['title'] );

		return $instance;
	}

	/**
	 * Back-end widget form.
	 *
	 * @see WP_Widget::form()
	 *
	 * @param array $instance Previously saved values from database.
	 */
	public function form( $instance ) {
		if ( isset( $instance[ 'title' ] ) ) {
			$title = $instance[ 'title' ];
		}
		else {
			$title = __( 'New title', 'text_domain' );
		}
		?>
		<p>
		<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:' ); ?></label> 
		<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" />
		</p>
		<?php 
	}

} // class Foo_Widget

Creating the Twitter Widget

Above we defined what we want the Twitter widget to do now we can look at how we are going to do this. We will need to create a Widget admin screen in the Widget dashboard so that the user can enter the different information for the Widget. The information we need to collect from the user is:

  • Widget Title - This text will be placed outside of the Widget
  • Twitter Username - The account tweets we are displaying
  • Number Of Tweets - Total number of Tweets to display
  • Follow Me Text - The headline text inside the Widget

This is all the information we need to collect to create the Twitter widget for Wordpress.

Defining The Plugin

To start off this widget we first need to define this code as a Wordpress plugin. To define it we need add the following comments at the top of the PHP file. This header comments lets Wordpress see this as a Wordpress plugin and adds this to the plugin screen to activate it, without this header you will not be able to activate your plugin.

/*
 * Plugin Name: Paulund Display Latest Tweets
 * Plugin URI: http://www.paulund.co.uk
 * Description: A widget that displays your latest tweets
 * Version: 1.0
 * Author: Paul Underwood
 * Author URI: http://www.paulund.co.uk
 * License: GPL2 

    Copyright 2012  Paul Underwood

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License,
    version 2, as published by the Free Software Foundation. 

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details. 
*/

Registering The Widget

When your Wordpress plugin is activated it will run the rest of the PHP code in the plugin. For this plugin we want to create a Wordpress Widget so we need to register the widget with Wordpress so it understands we want to use this as a Widget and can drag it into a sidebar. To register the WordPress widget use the following code.


/**
 * Register the Widget
 */
add_action( 'widgets_init', create_function( '', 'register_widget("pu_tweet_widget");' ) ); 

/**
 * Create the widget class and extend from the WP_Widget
 */
 class pu_tweet_widget extends WP_Widget {

}

Twitter Widget Constructor

When the Widget is ran the constructor code will get run first, this is where we can pass through values to the WP_Widget base constructor to define the widget.


/**
 * Create the widget class and extend from the WP_Widget
 */
 class pu_tweet_widget extends WP_Widget {
 	
	private $twitter_title = "My Tweets";
	private $twitter_username = "paulund_";
	private $twitter_postcode = "10";
	private $twitter_follow_text = "Follow Me On Twitter";
 	
	/**
	 * Register widget with WordPress.
	 */
	public function __construct() {
		
		parent::__construct(
			'pu_tweet_widget',		// Base ID
			'Paulund Twitter Widget',	// Name
			array(
				'classname'		=>	'pu_tweet_widget',
				'description'	=>	__('A widget that displays your latest tweets.', 'framework')
			)
		);

	} // end constructor
}


The other functions in this class will be to setup, update and display the widget. ### Widget Function

This Widget function is used to display the Widget on the page. First we start off by getting the values from the database so we know what information we need to get from Twitter. To get the values from the database we use the second parameter in the widget function.


/* Our variables from the widget settings. */
$this->twitter_title = apply_filters('widget_title', $instance['title'] );
		
$this->twitter_username = $instance['username'];
$this->twitter_postcode = $instance['postcount'];
$this->twitter_follow_text = $instance['tweettext'];

The problem with using the Twitter API is that there is a limit on the amount of requests you get do per hour. This currently stands at 150 requests per hour, so if your website gets more than 150 page views an hour you will need to cache the Twitter results to use in the widget. Wordpress comes with an easy way to store bits of code as a temporary caching, this uses the Transient API by using the get and set transient functions.

Get Transient

The get_transient function will return the cached value for the provided transient name.


<?php get_transient( $transient_name ); ?>

Set Transient

The set_transient function will set cache in Wordpress by supplying the transient name, value to be cached and how long you want it be cached.


<?php set_transient( $transient_name, $value, $expiration ); ?>

Below is the code we use to cache the tweets from your user stream. This first checks to see if there is anything stored in the cache, if it isn't then it will call the Twitter API to get the new tweets.


            $transName = 'list-tweets'; // Name of value in database.
	    $cacheTime = 10; // Time in minutes between updates.
	 
	    if(false === ($twitterData = get_transient($transName) ) ){
	        // Get the tweets from Twitter.
	        $json = wp_remote_get("http://api.twitter.com/1/statuses/user_timeline.json?screen_name=".$this->twitter_username."&count=".$this->twitter_postcode);
	 
	        // Get tweets into an array.
	        $twitterData = json_decode($json['body'], true);
	 
	        // Save our new transient.
	        set_transient($transName, $twitterData, 60 * $cacheTime);
	    }

Now we have the Twitter stream we can display these on the website. We do this by looping through each of the tweets and add them to a list item which we can echo at the end to display all the tweets. Here is the whole code to display the tweets.


/**
	 * Front-end display of widget.
	 *
	 * @see WP_Widget::widget()
	 *
	 * @param array $args     Widget arguments.
	 * @param array $instance Saved values from database.
	 */
	public function widget( $args, $instance ) {
		extract( $args );

		/* Our variables from the widget settings. */
		$this->twitter_title = apply_filters('widget_title', $instance['title'] );
		
		$this->twitter_username = $instance['username'];
		$this->twitter_postcode = $instance['postcount'];
		$this->twitter_follow_text = $instance['tweettext'];
				
		$transName = 'list-tweets'; // Name of value in database.
	    $cacheTime = 10; // Time in minutes between updates.
	 
	    if(false === ($twitterData = get_transient($transName) ) ){
	        // Get the tweets from Twitter.
	        $json = wp_remote_get("http://api.twitter.com/1/statuses/user_timeline.json?screen_name=".$this->twitter_username."&count=".$this->twitter_postcode);
	 
	        // Get tweets into an array.
	        $twitterData = json_decode($json['body'], true);
	 
	        // Save our new transient.
	        set_transient($transName, $twitterData, 60 * $cacheTime);
	 
	    }

		/* Before widget (defined by themes). */
		echo $before_widget;
		?>
		<div class="highlight twitter_box"><?php

		/* Display the widget title if one was input (before and after defined by themes). */
		if ( $this->twitter_title )
			echo $before_title . $this->twitter_title . $after_title;

		/* Display Latest Tweets */
		 ?>
			<a href="https://twitter.com/<?php echo $this->twitter_username; ?>" 
				class="twitter-follow-button" 
				data-show-count="true" 
				data-lang="en">Follow @<?php echo $this->twitter_username; ?></a>
			<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
            
            <?php
            	if(!empty($twitterData) || !isset($twitterData['error'])){
            		$i=0;
					$hyperlinks = true;
					$encode_utf8 = true;
					$twitter_users = true;
					$update = true;
					
					echo '<ul class="twitter_update_list">';
					 
		            foreach($twitterData as $item){
		 
		                    $msg = $item['text'];
		                    $permalink = 'http://twitter.com/#!/'. $this->twitter_username .'/status/'. $item['id_str'];
		                    if($encode_utf8) $msg = utf8_encode($msg);
		                    $link = $permalink;
		 
		                     echo '<li class="twitter-item">';
		 
		                      if ($hyperlinks) {    $msg = $this->hyperlinks($msg); }
		                      if ($twitter_users)  { $msg = $this->twitter_users($msg); }
		 
		                      echo $msg;
		 
		                    if($update) {
		                      $time = strtotime($item['created_at']);
		 
		                      if ( ( abs( time() - $time) ) < 86400 )
		                        $h_time = sprintf( __('%s ago'), human_time_diff( $time ) );
		                      else
		                        $h_time = date(__('Y/m/d'), $time);
		 
		                      echo sprintf( __('%s', 'twitter-for-wordpress'),' <span class="twitter-timestamp"><abbr title="' . date(__('Y/m/d H:i:s'), $time) . '">' . $h_time . '</abbr></span>' );
		                     }          
		 
		                    echo '</li>';
		 
		                    $i++;
		                    if ( $i >= $this->twitter_postcode ) break;
		            }

					echo '</ul>';
					
            	}
            ?>
       		</div>
		<?php 

		/* After widget (defined by themes). */
		echo $after_widget;
	}

/**
	 * Find links and create the hyperlinks
	 */
	private function hyperlinks($text) {
	    $text = preg_replace('/\b([a-zA-Z]+:\/\/[\w_.\-]+\.[a-zA-Z]{2,6}[\/\w\-~.?=&%#+$*!]*)\b/i',"<a href=\"$1\" class=\"twitter-link\">$1</a>", $text);
	    $text = preg_replace('/\b(?<!:\/\/)(www\.[\w_.\-]+\.[a-zA-Z]{2,6}[\/\w\-~.?=&%#+$*!]*)\b/i',"<a href=\"http://$1\" class=\"twitter-link\">$1</a>", $text);    
	 
	    // match name@address
	    $text = preg_replace("/\b([a-zA-Z][a-zA-Z0-9_\.\-]*[a-zA-Z]*\@[a-zA-Z][a-zA-Z0-9_\.\-]*[a-zA-Z]{2,6})\b/i","<a href=\"mailto://$1\" class=\"twitter-link\">$1</a>", $text);
	        //mach #trendingtopics. Props to Michael Voigt
	    $text = preg_replace('/([\.|\,|\:|\¡|\¿|\>|\{|\(]?)#{1}(\w*)([\.|\,|\:|\!|\?|\>|\}|\)]?)\s/i', "$1<a href=\"http://twitter.com/#search?q=$2\" class=\"twitter-link\">#$2</a>$3 ", $text);
	    return $text;
	}
	 
	/**
	 * Find twitter usernames and link to them
	 */
	private function twitter_users($text) {
	       $text = preg_replace('/([\.|\,|\:|\¡|\¿|\>|\{|\(]?)@{1}(\w*)([\.|\,|\:|\!|\?|\>|\}|\)]?)\s/i', "$1<a href=\"http://twitter.com/$2\" class=\"twitter-user\">@$2</a>$3 ", $text);
	       return $text;
	}

Update Function

The update function is used to add the values of the widget dashboard to the database so we can use this when displaying the Widget. For this function we are just going to loop through all the inputs from the form and strip all tags from the input boxes. Now we can just return a validated array and these are the values which are added to the database.


	/**
	 * Sanitize widget form values as they are saved.
	 *
	 * @see WP_Widget::update()
	 *
	 * @param array $new_instance Values just sent to be saved.
	 * @param array $old_instance Previously saved values from database.
	 *
	 * @return array Updated safe values to be saved.
	 */
	function update( $new_instance, $old_instance ) {
		$instance = $old_instance;

		// Strip tags to remove HTML (important for text inputs)		
		foreach($new_instance as $k => $v){
			$instance[$k] = strip_tags($v);
		}

		return $instance;
	}

Form Function

The form function is used on the widgets dashboard screen and will allow you to edit data in the plugin. From this form we want to change the title of the widget, the Twitter username, the amount of tweets to display and the follow me text.


/**
	 * Create the form for the Widget admin
	 *
	 * @see WP_Widget::form()
	 *
	 * @param array $instance Previously saved values from database.
	 */	 
	function form( $instance ) {

		/* Set up some default widget settings. */
		$defaults = array(
		'title' => $this->twitter_title,
		'username' => $this->twitter_username,
		'postcount' => $this->twitter_postcode,
		'tweettext' => $this->twitter_follow_text,
		);
		$instance = wp_parse_args( (array) $instance, $defaults ); ?>

		<!-- Widget Title: Text Input -->
		<p>
			<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e('Title:', 'framework') ?></label>
			<input type="text" class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" value="<?php echo $instance['title']; ?>" />
		</p>

		<!-- Username: Text Input -->
		<p>
			<label for="<?php echo $this->get_field_id( 'username' ); ?>"><?php _e('Twitter Username e.g. paulund_', 'framework') ?></label>
			<input type="text" class="widefat" id="<?php echo $this->get_field_id( 'username' ); ?>" name="<?php echo $this->get_field_name( 'username' ); ?>" value="<?php echo $instance['username']; ?>" />
		</p>
		
		<!-- Postcount: Text Input -->
		<p>
			<label for="<?php echo $this->get_field_id( 'postcount' ); ?>"><?php _e('Number of tweets (max 20)', 'framework') ?></label>
			<input type="text" class="widefat" id="<?php echo $this->get_field_id( 'postcount' ); ?>" name="<?php echo $this->get_field_name( 'postcount' ); ?>" value="<?php echo $instance['postcount']; ?>" />
		</p>
		
		<!-- Tweettext: Text Input -->
		<p>
			<label for="<?php echo $this->get_field_id( 'tweettext' ); ?>"><?php _e('Follow Text e.g. Follow me on Twitter', 'framework') ?></label>
			<input type="text" class="widefat" id="<?php echo $this->get_field_id( 'tweettext' ); ?>" name="<?php echo $this->get_field_name( 'tweettext' ); ?>" value="<?php echo $instance['tweettext']; ?>" />
		</p>
		
	<?php
	}

Download

By putting all of the above functions together you can also create a Wordpress widget to display your latest Twitter updates. I have also uploaded this to the Wordpress.org repo so if you want, you can download the plugin instead to use on your Wordpress blog. Download Paulund Twitter Stream Plugin