Caching in WordPress: Transients or APC?

When using WordPress, I often find myself needed to query out posts or other information that isn’t easily available courtesy of one of WordPress’ built-in functions. While it’s a normal thing to do, it can come with a cost: performance.

Every time a query is written to pull out specific data from WordPress, it adds another query to MySQL which adds time and performance. Singularly, it’s not a huge cost, but if your site has any decent level of traffic, it can add up.

Screen Shot 2013-12-09 at 10.56.01 AMCase in point: we recently relaunched our internal campus news site as a responsive site.

Every day, we post news stories for various audiences and some of these stories are for events happening today, which is information we wanted to feature for our readers.

We have a custom field in our WordPress backend that allows us to note the day of an event, so even if the story is posted a month ago, on the day of the event we can query it and display it for the user.

That query is pretty simple. It looks like this:


$args = array(
 'numberposts' => -1,
 'offset' => 0,
 'orderby' => 'post_date',
 'order' => 'DESC',
 'post_type' => 'post',
 'post_status' => 'publish',
 'year' => $current_year,
 'meta_key' => 'date',
 'meta_value' => $today,
 );

$go = get_posts($args);

With over 3,500 posts in this site, that’s an expensive query. You’ll notice we help narrow that query down a bit by only having WordPress look for posts in the current calendar year. No sense in looking at 2011’s posts for an event in 2013. Even with that reduction, there’s still several hundred posts to sort through.

There are a few ways to reduce the load that query creates. The best way is to cache the results of the query, which will allow us to serve that faster from memory/database then having to make a whole database call with all sorts of parameters.

One way is to use WordPress’ built-in Transients API. It’s a fairly straight-forward system to set, fetch and delete data inside WordPress. This is perfect for things like queries and other rendered data that you’re going to need often.

Setting up and fetching transients is easy.


$transientname = 'hewt';
$cachetime = 60;

if(false === ($go = get_transient($transientname))){
	$go = get_posts($args);
	set_transient($transName,$go,60*$cachetime);
}

That code, in a nutshell, is first checking to see if the transient variable exists and can be fetched. If it can, great, move on. If it can’t or doesn’t exist, run the WordPress query and save the results in the Transient API for an hour. We can start using the $go variable as needed after that.

The trick about WordPress transients is they are stored in the database. But Mike, didn’t you say that having to query the database every time is a performance hit? Yes, but…

Transients are inherently sped up by caching plugins, where normal Options are not. A memcached plugin, for example, would make WordPress store transient values in fast memory instead of in the database. For this reason, transients should be used to store any data that is expected to expire, or which can expire at any time. Transients should also never be assumed to be in the database, since they may not be stored there at all.

The other way to do some as-needed caching is to use a PHP caching solution, such as APC. I’ve talked about caching WordPress queries using APC in this post.

You’d write your PHP code to save to APC the same way.


$transientname = 'hewt';

if($go = apc_fetch($transientname)){}else{
    $go = get_posts($args);
    apc_add($transientname,$go,3600);
}

Same idea here. We’re checking APC to see if the variable is available. If it is, great, move on. If it’s not, run the WordPress query and save the results for the next time the page is loaded.

What’s neat about APC is that instead of writing the values to MySQL, APC stores them in memory, which means its m