Advertisement
Plugins

Getting Started with the WordPress Transient API, Part 2

by

In the first post in this series, we took defined what the API is, how it differs form the settings API, and some of the general calls that we can make to the API. In this post, we'll be taking a look at a practical implementation of the API and how to handle some idiosyncrasies that come with dealing with expired data.

The WordPress Transients API is a powerful (but really-easy-to-use) aspect of the WordPress API. Generally speaking, it makes it really easy to store data with an expiration time, and makes it really easy to take advantage of various caching plugins to ultimately increase the speed of your site.


Setup The Plugin

For the purposes of this plugin, we're going to create a simple widget that will list a blogs top commenters of all time. The goal of the plugin is to keep it lean so that we can highlight the transients functionality of the plugin.

Note that all of the plugin's files can be retrieved from GitHub at any time. In the mean time, go ahead and create a directory called 'top-commenters-cached' and make sure that it has the following directory structure:

If you're not interested in localizing the plugin, feel free to leave the 'lang' directory out of the plugin. At this point, we're ready to begin writing the widget.


Basic Functionality

The plugin is simple. It should…

  • Allow the user to give the widget a custom
  • Retrieve the top 10 most popular commenters of the life of the blog

Easy enough. Here's the code for the basic plugin. Note that it's commented throughout so spend sometime reading through it to understand what we're doing. If you're unfamiliar with the widget API, don't forget to check out our WordPress Widget Boilerplate post.

class Top_Commenters_Cached extends WP_Widget {

	const name = 'Top Commenters (Cached!)';
	const locale = 'top-commenters-cached-locale';
	const slug = 'top-commenters-cached';
	

	/*--------------------------------------------------*/
	/* Constructor
	/*--------------------------------------------------*/
	
	/**
	 * The widget constructor. Specifies the classname and description, instantiates
	 * the widget, loads localization files, and includes necessary scripts and
	 * styles.
	 */
	function Top_Commenters_Cached() {

		$widget_opts = array (
			'classname' => self::name, 
			'description' => __('A plugin used to demonstrate the WordPress Transients API for an Envato blog series.', self::locale)
		);	
		$this->WP_Widget(self::slug, __(self::name, self::locale), $widget_opts);
		
		load_plugin_textdomain(self::locale, false, dirname(plugin_basename( __FILE__ ) ) . '/lang/' );
		
	} // end constructor

	/*--------------------------------------------------*/
	/* API Functions
	/*--------------------------------------------------*/
	
	/**
	 * Outputs the content of the widget.
	 *
	 * @args			The array of form elements
	 * @instance
	 */
	function widget($args, $instance) {
	
		extract($args, EXTR_SKIP);
		
		echo $before_widget;
		
		$widget_title = empty($instance['widget_title']) ? '' : apply_filters('widget_title', $instance['widget_title']);
		$commenters = $this->query_for_commenters();
    
		// Display the widget
		include(WP_PLUGIN_DIR . '/' . self::slug . '/views/widget.php');
		
		echo $after_widget;
		
	} // end widget
	
	/**
	 * Processes the widget's options to be saved.
	 *
	 * @new_instance	The previous instance of values before the update.
	 * @old_instance	The new instance of values to be generated via the update.
	 */
	function update($new_instance, $old_instance) {
		
		$instance = $old_instance;
		
		$instance['widget_title'] = $this->strip($new_instance, 'widget_title');
    
		return $instance;
		
	} // end widget
	
	/**
	 * Generates the administration form for the widget.
	 *
	 * @instance	The array of keys and values for the widget.
	 */
	function form($instance) {
	
		$instance = wp_parse_args(
			(array)$instance,
			array(
				'widget_title' => ''
			)
		);
	
		$widget_title = $this->strip($instance, 'widget_title');
		
		// Display the admin form
    	include(WP_PLUGIN_DIR . '/' . self::slug . '/views/admin.php');
		
	} // end form

	/*--------------------------------------------------*/
	/* Private Functions
	/*--------------------------------------------------*/
	
	/**
	 * Retrieves the weekly top commenters for the past week and stores the values in the cache.
	 * If the cache is empty, then the function will request information from the database and 
	 * store it in the cache.
	 */
	private function query_for_commenters() {
	
		$commenters = null;
		
		// query the database for the top commenters
		global $wpdb;
		$commenters = $wpdb->get_results("
			select count(comment_author) as comments_count, comment_author, comment_type
			from $wpdb->comments
			where comment_type != 'pingback'
			and comment_author != ''
			and comment_approved = '1'
			group by comment_author
			order by comment_author desc
			LIMIT 10
		");

		return $commenters
	
	} // end query_for_commenters
	
	/*--------------------------------------------------*/
	/* Helper Functions
	/*--------------------------------------------------*/
  
	/**
	 * Convenience method for stripping tags and slashes from the content
	 * of a form input.
	 *
	 * @obj			The instance of the argument array
	 * @title		The title of the element from which we're stripping tags and slashes.
	 */
	private function strip($obj, $title) {
		return strip_tags(stripslashes($obj[$title]));
	} // end strip
	
} // end class
add_action('widgets_init', create_function('', 'register_widget("Top_Commenters_Cached");')); 
?>

Next, let's take a look at the widget's view. This is the part of the plugin that's responsible for displaying the list of comments. It works by displaying the widget's title (if it's defined), then loops through the results creating a new list item.

 0) { ?>
	

'; foreach($commenters as $commenter) { $comment_list .= '
  • '; // actually print the commenter's name and the number of comments $comment_list .= $commenter->comment_author; $comment_list .= ' (' . $commenter->comments_count . ')'; $comment_list .= '
  • '; } // end foreach $comment_list .= ''; echo $comment_list; ?>

    Obviously, we've left out part of the code. Namely, the admin panel. It should simply allow for users to enter a title for their widget:

    Remember that you can view the full source code and download the plugin from its GitHub repository.


    Cache The Data

    At this point, we have a functional plugin; however, we're not actually caching any data yet. The most intensive part of this plugin is when we're querying the database and the results of the query are what we actually want to cache so let's do that.

    Locate the query in the code:

    	global $wpdb;
    	$commenters = $wpdb->get_results("
    		select count(comment_author) as comments_count, comment_author, comment_type
    		from $wpdb->comments
    		where comment_type != 'pingback'
    		and comment_author != ''
    		and comment_approved = '1'
    		group by comment_author
    		order by comment_author desc
    		LIMIT 10
    	");

    And let's store the results for 12 hours using the transients API:

    set_transient('top_commenters_cached', $commenters, 60 * 60 * 12);

    Pretty easy, right? Of course, we're not done yet.


    Retrieve The Data

    Once the transient is set, we need to be able to retrieve the transient. Let's set that up now:

    private function query_for_commenters() {
    	return get_transient('top_commenters_cached');
    } // end query_for_commenters

    That's all there is to it!

    But wait - if you recall from the first post in the series, transients actually expire so we're not guaranteed to retrieve the transient.


    Finding Missing Data

    Regardless of what you're doing, retrieving data that has expired generally follows the same process:

    • Check for the existence of the transient
    • If it exists, use it
    • If it doesn't exist, set it then retrieve it

    So let's do that within the context of our plugin:

    private function query_for_commenters() {
    
    	$commenters = null;
    	
    	// check to see if the transient exists. set it if it's expired or missing
    	if(!get_transient('top_commenters_cached')) {
    
    		// query the database for the top commenters
    		global $wpdb;
    		$commenters = $wpdb->get_results("
    			select count(comment_author) as comments_count, comment_author, comment_type
    			from $wpdb->comments
    			where comment_type != 'pingback'
    			and comment_author != ''
    			and comment_approved = '1'
    			group by comment_author
    			order by comment_author desc
    			LIMIT 10
    		");
    
    		// store the result 
    		set_transient('top_commenters_cached', $commenters, 60 * 60 * 12);
    		
    	} // end if 
    	
    	// transient is guaranteed to exist now, so return it
    	return get_transient('top_commenters_cached');
    
    } // end query_for_commenters

    Conclusion

    Not too bad, right?

    As you can see, working with the Transients API requires little more than knowing when to use it and what functions are available. In my opinion, it's one of the most powerful aspects of the WordPress API.

    If you find yourself retrieving large amounts of data, looking for a way to expire data for a refresh, or simply wanting to take advantage of caching plugins, remember to take advantage of the Transients API.

    Related Posts
    • Code
      Plugins
      Distributing Your Plugins in GitHub with Automatic UpdatesSensorsthumbnail
      This article will teach you that, with a little creative coding, you can host your own WordPress plugins in GitHub while still retaining the automatic update feature.Read More…
    • Code
      Creative Coding
      Using WordPress for Web Application Development: A ReviewApplication foundation 400
      Over the past few months, we've been taking a look at all of the features and aspects that make WordPress a potential foundation for application development. In fact, we've spent roughly 15 articles talking about all that WordPress offers. And though we'll be reviewing each of the points in this email, perhaps the biggest thing to take away that building web applications using WordPress is different than using many of the popular frameworks that are currently available namely because WordPress isn't a framework.Read More…
    • Code
      Creative Coding
      Using WordPress for Web Application Development: Custom Database QueriesApplication foundation 400
      Throughout this series, we've been looking at the various facilities that make it possible to treat WordPress as a foundation for web application development. Thus far, we've covered a lot of ground: We've talked about how WordPress is more of a foundation rather than a framework. We've discussed the nature of the the Event-Driven Design Pattern. There's been a discussion of Email, User Management, Saving Data, Retrieving Data ...and more. In the most recent articles, we've been talking a look at how to handle queries against the WordPress database through the use of WP_Query and WP_User_Query.Read More…
    • Code
      Creative Coding
      Using WordPress For Web Application Development: Available Features, Part 7: CachingApplication foundation 400
      When it comes to building web applications, one of the most important things that we have to constantly be mindful of is performance. As they say, performance is a feature. And regardless of if you're a designer, developer, or a user, you know this intuitively to be true: When it comes to applications, we hate waiting. We get frustrated when things don't perform fast enough, or we have to wait longer than we believe that we should.Read More…
    • Code
      Plugins
      Displaying Information of a WordPress.org Plugin on Your WebsiteWordpressdotorg plugin api border 400
      In the first part of this article, we discussed how to use built-in functions to communicate with WordPress.org and retrieve plugin details. In this tutorial we will put the theory in action to create a simple plugin which will allow us to display details of any plugin hosted on WordPress.org on our WordPress website using shortcodes.Read More…
    • Code
      Widgets
      Twitter Trends Widget for WordPressPreview
      In this tutorial we are going to create a WordPress widget that displays Twitter Trends by region. We will use Twitter's Trends API and update trends after a specific time duration using WordPress' Transients API.Read More…