Understand Caching with WordPress Transients API

Computer performance revolves, in large part, around the idea of caching: “storing something in a more-ready and quicker-to-access state,” so that you can more quickly deliver the final result. The WordPress Transients API is a tool for caching, and an important way to improve performance in WordPress.

To take a real-life example: your kitchen cupboard is a kind of cache. You’ve got soup cans “cached” in your cupboard, ready for quick delivery to your stove—meaning that you don’t have to drive to the supermarket every time you want soup.

Why Use WordPress Transients for Caching

In a WordPress context, caching most often means “full page” caching: storing a full webpage just before it’s sent out to a visitor, so that the next visitor to ask for that page will get the stored version without your server having to rebuild it. This is the approach of many caching plugins, such as WP Super Cache. In some situations this is ideal, and can have a major impact on site speed.

You can improve performance by caching things other than full pages, such as slow results from remote servers like Facebook’s, or large database queries.

However, there’s also the idea of “partial” or “object” caching: achieving performance gains by storing things other than full pages, such as the results of long-running computations, slow results from remote servers (such as Facebook or Twitter results), or large database queries which are likely to be both slow to run and very consistent in the results they yield.

In WordPress, the way to “partially cache” pages, one data object at a time, is the Transients API.

Understanding the WordPress Transients API

The WordPress Transients API creates its own, easy-to-use interface for the various means and methods of caching data in a given server environment, so that WordPress developers don’t have to worry too much about the specifics of that environment.

With Transients, we want to be able to name and store a hunk of data, and to get it back quickly. This so-called “key-value store” is exactly what in-memory caching systems allow. Memcached (memcached.org) is one of these systems: a very fast, simple, and powerful way to store blobs of data and retrieve them later. However, Memcached and similar systems are not available everywhere—in fact, not even on most servers where WordPress runs.

The Transients API lets developers cache data as if Memcached or a similar key-value storage system is available—whether or not it actually is.

So the WordPress Transients API lets programmers cache data just like they would if Memcached or a similar key-value storage system were available—without needing to worry whether it actually is.

In-Memory Storage and In-Database Storage

As a note on how the Transients API actually works: when Memcached or other forms of caching aren’t available, WordPress stores the cached data in the options table of its regular database. This lets WordPress provide the same functionality as an in-memory cache—although, unfortunately, somewhat slower, since the objects are cached all the way in the MySQL database, and not in the server’s memory where they’re easier to get to.

Transients Should Be Transient!

These “caches” or “transients” aren’t meant to be permanent. (Permanent data should live in the Options API; see Mastering the Options API in WordPress.)

When we cache data, we want to set a defined expiration time for that data, after which it’ll simply disappear.

How to use the Transients API

The WordPress Transients API is quite simple: you first store a name-value pair, and then you retrieve it.

set_transient()

Here’s what setting a transient looks like:

$string = "Cache me for a day!";
$bool_response = set_transient( 'wpshout_cache_me', $string, 86400 );

Let’s look at set_transient()‘s three arguments:

  1. The name of the transient, in this case wpshout_cache_me.
  2. The value of the transient. In this case, that’s the value of $string: the string “Cache me for a day!”
  3. The length for which this transient will persist. This argument takes an integer number of seconds, in this case 86400.

The final result is that the wpshout_cache_me transient will persist with a value of “Cache me for a day!” for 86,400 seconds—that is, for one full day.

get_transient()

Retrieving a transient for use looks like this:

$transient_string = get_transient( 'wpshout_cache_me' );

if ( false === $transient_string ) {
	return; // In real life we'd want to set_transient() here
}

echo '<h1>' . $transient_string . '</h1>';

Here, we’re using get_transient(), with the transient’s name (wpshout_cache_me) as its only parameter, to retrieve the transient if it exists.

Be careful! get_transient() will return false if the transient doesn’t exist. So it’s really important to test for the transient’s existence before using it. That’s what our if-statement does. In real code, the lack of a transient would be our excuse to set_transient() all over again, but we’ve omitted that here.

If we have successfully retrieved the transient, you can do anything with it. In this case, we’re printing it out, wrapped in an <h1> tag.

That’s it! There are four other functions: delete_transient(), which manually clears transients out of the cache, and three alternative functions for use in WordPress Multisite. But there’s plenty here to get you, as it were, “up and running” with transients.

An Example: Fun With Transients

Let’s look at how transients work, in a full-fledged example called “WPShout Cache Hard Math.”

How the Finished Product Works

Our plugin is a demo of object caching: it tells the server to do millions of complex calculations, and then to cache the results for ten seconds. So every ten seconds, the site loads painfully slowly—but in the seconds between, it loads quickly! That’s caching at work.

(Note: since it intentionally hurts site performance for demo purposes, this isn’t a plugin you’ll want to deploy on your own sites, or on anyone’s site that you’d like to stay on good terms with.)

The result at six seconds past the minute. This page took around ten seconds to load!
The same result, at twelve seconds past the minute. This page loaded quickly.
The result at twenty seconds past the minute. This page loaded very slowly again.

The Code

We’re about to show you a whole plugin file, in chunks. Each chunk comes immediately after the previous chunk, so if you copy-paste them all you’ll have a working—but silly and not-to-be-deployed—plugin.

This first section does a huge amount of calculations, and returns an array with two elements: the input value before the calculations, and the output value after them:

<?php
/*
Plugin Name: WPShout Cache Hard Math
*/

function wpshout_do_hard_math( $int ) {
	// $start is the starting integer
	$start = $int;

	// Insanely processing-intensive calculations
	$i = 0;
	while( $i < 100000 ) {
		$int = pow( sqrt( sqrt( sqrt( sqrt( $int) ) ) ), 16.0001);
		$i++;
	}

	// Return our array: what we started with and what resulted
	return array ( $start, $int );
}

This next section attempts to get the transient that is the result of the wpshout_do_hard_math() calculations. If it finds there’s no transient, it will try to set the transient, then get it. It then returns either the transient, or false if getting the transient failed:

function wpshout_get_hard_math_transient() {
	// Get the transient
	$result = get_transient( 'hard_math' );
	
	if ( false !== $result ) {
		// Transient exists, so return it
		return $result;
	}

	// Get array from doing "hard math" (on seconds elapsed in current minute)
	$mathed = wpshout_do_hard_math( date( 's' ) );

	// Attempt to set transient with array results; timeout is 10 seconds
	$bool_response = set_transient( 'hard_math', $mathed, 10 );

	if( false === $bool_response ) {
		// Setting the transient didn't work, so return false for failure
		return false;
	}

	// Transient is now set, so get it and return it
	return get_transient( 'hard_math' );
}

This section attempts to retrieve the transient. If it succeeds, it hooks into the_content to print a string containing the transient’s calculations at the top of the post’s content:

function wpshout_filter_content_with_hard_math_transient( $content ) {
	// Get the transient 
	$result = wpshout_get_hard_math_transient();

	// If transient isn't an array, just return content unaltered
	if ( ! is_array( $result ) ) {
		return $content;
	}

	// Prepend string with transient data to content and return it
	return '<p>(<small>I did some terrifyingly inefficient math on the number ' . ltrim( $result[0], '0' ) . ', and the result was: ' . $result[1] . '</small>)</p>' . $content;
}
add_filter( 'the_content', 'wpshout_filter_content_with_hard_math_transient' );

If you understood this example right away, you’re really getting WordPress at a deep level! If not, don’t worry too much about the specifics—just try to absorb the basic uses of get_transient() and set_transient() that this example exists to show off.

A More Practical Example Use Case for Transients

In case you’re having trouble picturing how transients could benefit a site (rather than make it virtually unusable), we’ll link to a very beautiful real-world example of caching a nav menu, which includes a use of delete_transient() to invalidate the cache when the nav menu changes: https://leaves-and-love.net/blog/transients-speed-up-wordpress-theme/.

In general, in our experience, transients are a topic that comes up most often in plugin development, where the burden of making things fast is on you. So, for example, if you write a Twitter feed widget, transients are a great idea to make sure that the site isn’t fetching from Twitter every single page load. If you’re just using plugins, though, it’s usually fine to go with the original developers’ choices, and the need to create new transients doesn’t come up especially often.

What We’ve Learned about WordPress Transients

We’ve learned how and why to use transients in WordPress, and gotten deep into an example that shows them at work. We’re a lot better-equipped to cache expensive operations in WordPress—and our sites will be faster for it. Onward!

Image credit: anarchosyn


5 Responses

Comments

  • Hugh says:

    Thanks, really interesting! Looking forward to test in a project with some large queries

  • Excellent post David. Not everyone is aware Transient uses an object storage like memcache and redis when they exist.

    Armed with the above knowledge, I stopped using wp_cache_* functions.

  • Ross McKay says:

    Great article. Two things to add:

    Memcached and other persistent object caches will automatically delete old, stale transients for you. But they can also delete new, fresh transients when there’s a lot going through the cache! Be aware of this and never store anything you can’t recreate in a transient. They’re only meant for temporary storage.

    When you don’t have memcached or similar and transients are written to the options table, they can build up over time. They’ll only get deleted if they have an expiry time and get requested again. Always use an expiry time when you create a transient!

    If you do find that your options table is filling up with transients that aren’t being deleted, there’s a few plugins that will clear out the old ones. I wrote one of them: Delete Expired Transients

  • Robert says:

    Hi,
    Not everyone is aware Transient uses a mean storage taking into consideration Memcache and Redis upfront they exist.
    Thank you.

Pingbacks