WordPress Transients API – Practical examples

The WordPress Transients API is a very useful tool which allow developers to cache data such as the result of a query for future uses. In this article, I've compiled a list of useful practical example to div into the power of WordPress Transients API.


What is the transients API, and why it’s useful

Most developers who worked with WordPress in the past probably ever heard of the Options API, which allow you to save, update and delete custom values. The Transients API is pretty similar to the Options API, but with the feature of an expiration time, which simplifies the process of using the wp_options database table to store cached information.

After you read the practical example I’ve listed on this post, I suggest you to read the Transients API page on WordPress Codex.

List sites from your network

Let’s start with an interesting snippet for those who run networks of many blogs. The code below display a general menu of all sites from your networks. In this case, transients are used to store the data for a defined time (which can be set using the $expires variable on line 1) so you’ll not make huge database calls each time your menu have to be displayed.

To use this snippet, first you have to paste the function into your functions.php file.

function wp_list_sites( $expires = 7200 ) {
   if( !is_multisite() ) return false;

   // Because the get_blog_list() function is currently flagged as deprecated
   // due to the potential for high consumption of resources, we'll use
   // $wpdb to roll out our own SQL query instead. Because the query can be
   // memory-intensive, we'll store the results using the Transients API
   if ( false === ( $site_list = get_transient( 'multisite_site_list' ) ) ) {
      global $wpdb;
      $site_list = $wpdb->get_results( $wpdb->prepare('SELECT * FROM wp_blogs ORDER BY blog_id') );
      // Set the Transient cache to expire every two hours
      set_site_transient( 'multisite_site_list', $site_list, $expires );
   }

   $current_site_url = get_site_url( get_current_blog_id() );

   $html = '
<ul id="network-menu">' . "\n";

   foreach ( $site_list as $site ) {
      switch_to_blog( $site->blog_id );
      $class = ( home_url() == $current_site_url ) ? ' class="current-site-item"' : '';
      $html .= "\t" . '
<li id="site-' . $site->blog_id . '" '="" .="" $class=""><a href="' . home_url() . '">' . get_bloginfo('name') . '</a></li>

' . "\n";
      restore_current_blog();
   }

   $html .= '</ul>

<!--// end #network-menu -->' . "\n\n";

   return $html;
}

Once done, the following code will display all sites from your network. Simply paste it on any of theme files, where you want the list to be displayed.

<?php
// Multisite Network Menu
$network_menu = wp_list_sites();
if( $network_menu ):
?>
<div id="network-menu">
   <?php echo $network_menu; ?>
</div>

<!--// end #network-menu -->
<?php endif; ?>

→ Source: http://wp.smashingmagazine.com/2011/11/17/wordpress…/

Twitter followers count using WordPress transients

Many blogs, including this one, are displaying how many people are following them on Twitter. It’s quite easy to grab some json data, but it takes a significant amount of time. Using transients allow you to grab the json data from Twitter once a day, and store it in your database for future uses.

Simply paste the function below into your functions.php file:

function my_followers_count($screen_name = 'kovshenin'){
	$key = 'my_followers_count_' . $screen_name;

	// Let's see if we have a cached version
	$followers_count = get_transient($key);
	if ($followers_count !== false)
		return $followers_count;
	else
	{
		// If there's no cached version we ask Twitter
		$response = wp_remote_get("http://api.twitter.com/1/users/show.json?screen_name={$screen_name}");
		if (is_wp_error($response))
		{
			// In case Twitter is down we return the last successful count
			return get_option($key);
		}
		else
		{
			// If everything's okay, parse the body and json_decode it
			$json = json_decode(wp_remote_retrieve_body($response));
			$count = $json->followers_count;

			// Store the result in a transient, expires after 1 day
			// Also store it as the last successful using update_option
			set_transient($key, $count, 60*60*24);
			update_option($key, $count);
			return $count;
		}
	}
}

echo "I have " . my_followers_count('kovshenin') . " followers";

RSS subscribers count using WordPress transients

Using exactly the same technique as demonstrated above, we can grab RSS subscribers and store the result in WordPress database. Don’t forget to update the code with your own feedburner url on line 2. Then, paste the code where you’d like to display how many RSS feed readers you have.

function feed_subscribers(){
        $feed_url = 'http://feeds.feedburner.com/yourname';
        $count = get_transient('feed_count');
        if ($count != false) return $count;
	$count = 0;
        $data  = wp_remote_get('http://feedburner.google.com/api/awareness/1.0/GetFeedData?uri='.$feed_url.'');
   if (is_wp_error($data)) {
        return 'error';
   }else{
	$body = wp_remote_retrieve_body($data);
	$xml = new SimpleXMLElement($body);
	$status = $xml->attributes();
	if ($status == 'ok') {
		$count = $xml->feed->entry->attributes()->circulation;
	} else {
		$count = 300; // fallback number
	}
   }
	set_transient('feed_count', $count, 60*60*24); // 24 hour cache
	echo $count;
}

→ Source: https://wpsnipp.com/index.php/functions-php/get-feedburner-count-using-get_transient-and-wp_remote_get/

Cached navigation menu

Introduced in WordPress 3.0, the new menu system is definitely an improvement to WordPress. But using transients, we can even do something better, a menu with the same functionality but without the huge database requests.

<?php
/**
 * Wrapper function around wp_nav_menu() that will cache the wp_nav_menu for all tag/category
 * pages used in the nav menus
 * @see http://lookup.hitchhackerguide.com/wp_nav_menu for $args
 * @author tott
 */ 
function hh_cached_nav_menu( $args = array(), $prime_cache = false ) {
	global $wp_query;
	
	$queried_object_id = empty( $wp_query->queried_object_id ) ? 0 : (int) $wp_query->queried_object_id;
	
	// If design of navigation menus differs per queried object use the key below
	// $nav_menu_key = md5( serialize( $args ) . '-' . $queried_object_id );
	
	// Otherwise
	$nav_menu_key = md5( serialize( $args ) );
	
	$my_args = wp_parse_args( $args );
	$my_args = apply_filters( 'wp_nav_menu_args', $my_args );
	$my_args = (object) $my_args;
	
	if ( ( isset( $my_args->echo ) && true === $my_args->echo ) || !isset( $my_args->echo ) ) {
		$echo = true;
	} else {
		$echo = false;
	}
	
	$skip_cache = false;
	$use_cache = ( true === $prime_cache ) ? false : true;
	
	// If design of navigation menus differs per queried object comment out this section
	//*
	if ( is_singular() ) {
		$skip_cache = true;
	} else if ( !in_array( $queried_object_id, hh_get_nav_menu_cache_objects( $use_cache ) ) ) {
		$skip_cache = true;
	}
	//*/
	
	if ( true === $skip_cache || true === $prime_cache || false === ( $nav_menu = get_transient( $nav_menu_key ) ) ) {
		if ( false === $echo ) {
			$nav_menu = wp_nav_menu( $args );
		} else {
			ob_start();
			wp_nav_menu( $args );
			$nav_menu = ob_get_clean();
		}
		if ( false === $skip_cache )
			set_transient( $nav_menu_key, $nav_menu );
	} 
	if ( true === $echo )
		echo $nav_menu;
	else
		return $nav_menu;
}




/**
 * Invalidate navigation menu when an update occurs
 */
function hh_update_nav_menu_objects( $menu_id = null, $menu_data = null ) {
	hh_cached_nav_menu( array( 'echo' => false ), $prime_cache = true );
}
add_action( 'wp_update_nav_menu', 'hh_update_nav_menu_objects' );




/** 
 * Helper function that returns the object_ids we'd like to cache
 */
function hh_get_nav_menu_cache_objects( $use_cache = true ) {
	$object_ids = get_transient( 'hh_nav_menu_cache_object_ids' );
	if ( true === $use_cache && !empty( $object_ids ) ) {
		return $object_ids;
	}




	$object_ids = $objects = array();
	
	$menus = wp_get_nav_menus();
	foreach ( $menus as $menu_maybe ) {
		if ( $menu_items = wp_get_nav_menu_items( $menu_maybe->term_id ) ) {
			foreach( $menu_items as $menu_item ) {
				if ( preg_match( "#.*/category/([^/]+)/?$#", $menu_item->url, $match ) )
					$objects['category'][] = $match[1];
				if ( preg_match( "#.*/tag/([^/]+)/?$#", $menu_item->url, $match ) )
					$objects['post_tag'][] = $match[1];
			}
		}
	}
	if ( !empty( $objects ) ) {
		foreach( $objects as $taxonomy => $term_names ) {
			foreach( $term_names as $term_name ) {
				$term = get_term_by( 'slug', $term_name, $taxonomy );
				if ( $term )
					$object_ids[] = $term->term_id;
			}
		}
	}
	
	$object_ids[] = 0; // that's for the homepage
	
	set_transient( 'hh_nav_menu_cache_object_ids', $object_ids );
	return $object_ids;
}

→ Source: http://hitchhackerguide.com/2011/10/07/caching-wordpress-navigation-menus-wp_nav_menu-wrapper/

Cached Tag cloud

Thanks to WordPress transients API, caching almost anything is definitely. The following example shows how to cache the good old tag cloud. Simply paste this code wherever you want you tag cloud to be displayed.

$tag_cloud = get_transient( 'tag_cloud' );
if ( false === $tag_cloud || '' === $tag_cloud ){
	$args = array('echo' => false);
	$tag_cloud = wp_tag_cloud( $args );
	set_transient( 'tag_cloud', $tag_cloud, 60*60*12 );
}
echo $tag_cloud;

→ Source: http://wpengineer.com/2148/simple-cache-with-the-wordpress-transient-api/

Caching any custom query using transients

Is your theme using custom queries? If yes, you should definitely use the transients API to cache the queries. The following code shows how to cache a custom query. As you can see, there’s nothing complicated at all.

<?php
// Get any existing copy of our transient data
if ( false === ( $special_query_results = get_transient( 'special_query_results' ) ) ) {
    // It wasn't there, so regenerate the data and save the transient
     $special_query_results = new WP_Query( 'cat=5&order=random&tag=tech&post_meta_key=thumbnail' );
     set_transient( 'special_query_results', $special_query_results );
}

// Use the data like you would have normally...
?>

→ Source: http://codex.wordpress.org/Transients_API