WordPress Object Cache with Redis

WordPress Object Cache with Redis

WordPress has a built in Object Cache, as described here: WP_Object_Cache. Essentially this is a key / value store so that you can cache “objects” such as database query results to avoid the computationally expensive tasks on each page load.

Redis is an in memory cache. Being in memory its super fast. In a previous post we showed installation instructions for redis, so won’t repeat those again.

W3 Total Cache is my WordPress Caching Plugin of choice. What I love about it is that on my Ubuntu servers running WebCP W3 total cache produces an nginx.conf file which I can include into the site’s nginx config file. That way cached pages are served as static html pages directly from Nginx without invoking PHP or WordPress or the database at all.

According to the WordPress documentation on the page linked above, their object cache only caches per session. That means that effectively you don’t have a cache if you wanted to cache objects across different users. In order to get persistent caching across sessions you need something else, which is where W3 Total Cache come in!

In our scenario we run a monthly competition site. On each entrant’s page there are a number of lookups being performed like what is the name of this competition. The competition name is in date format, eg September 2018. However, you can’t assume that its the current month as people may be viewing older entries from previous months.

Each entry has a unique identifier, but each unique identifier starts with a 4 character sequence which identifies the site, the month and the year. Eg, if your unique code is eb180034 then that means you’re on site example.com, in month February (as denoted by the b) and year 2018. Your unique number in that competition is 0034.

The Problem

In our use case the problem with each entrant’s code is the section highlighted in red: eb180034. The problem with this is that if we have 1000 entries in a competition, each time a user visits one of the entries pages (the slug is the entry code) then it calculates the Month and year from the code (low impact) but also does certain database look ups to determine if the competition is currently active, how many entries are in the competition (to determine current position of the entrant in question) as well as certain other bits and pieces of data.

This implies that for each of the 1000 entries we do database queries which are identical based on the current competition. Of course W3 Total Cache’s page cache works wonders to prevent the same queries being fired each time for the same entry id, but 1000 entry id’s means 1000 look ups for some common data.

Worse still, this common data persists all month (August is August for an entire month!).

WordPress’ Object Cache

This is where WordPress’ Object Cache comes in handy. Its essentially a key value store. It does not persistent storage. Instead it leaves that to a plugin like W3 Total Cache.

The WordPress Object Cache has a few fairly simple function calls. The two used most often are:

    wp_cache_set( $key, $data, $group, $expire );

    wp_cache_get( $key, $group );

 

There are a couple of other functions and some nuances (particularly around boolean values being stored) but that’s plainly explained on WordPress own page.

To set a value you use a key, give it some data and optionally a group and an expire time. The group is so that you can group (duh) items together and the key can be the same across groups, eg:

wp_cache_set (“my_key”, “my data”, “group_1”, 100);

wp_cache_set (“my_key”, “my data”, “group_2”, 100);

The cache from the above 2 functions are distinct from one another because they belong to different groups. In our use case we use the section of our site together with the action as the group name, eg, “users_register”.

Armed with just these two functions we can start to cache up our expensive function calls like this:

// Database cache
function someCrazyExpensiveDatabaseLookUp()
{
    $value = wp_cache_get("crazy", "users_relative_position);
    
    if ($value !== false) {
        return $value;
    }
    
    // Do crazy SQL here
    ...
    
    wp_cache_set("crazy", $result_from_db, "users_relative_position", 3600);
    
    return $result_from_db;
}


// Function cache
function loopCache()
{
    $value = wp_cache_get("loop", "maths_fibonacci);
    
    if ($value !== false) {
        return $value;
    }
    
    
    // do fib sequence for 1000 iterations..
    
    wp_cache_set("loop", $result_from_sequence, "maths_fibonacci", 3600);
    
    return $result_from_sequence;
}

Of course the object cache is typically used for database queries but not limited to that. In our second example above we cached the result of a “long” running sequence.

Actually that second example brings up a point. What if you want to cache objects but you don’t know the specifics before hand? For instance, what if our sequence function took and argument for the number of iterations? Or what if a database query took an id to look up against?

In our case we simply appended the parameter to the key name and that gave us caching per user (or per whatever your caching for). So, our examples above become:

// Database cache
function someCrazyExpensiveDatabaseLookUp($id)
{
    $value = wp_cache_get("crazy_".$id, "users_relative_position);
    
    if ($value !== false) {
        return $value;
    }
    
    // Do crazy SQL here
    ...
    
    wp_cache_set("crazy_".$id, $result_from_db, "users_relative_position", 3600);
    
    return $result_from_db;
}
 
 
// Function cache
function loopCache($numberOfIterations)
{
    $value = wp_cache_get("loop_".$numberOfIterations, "maths_fibonacci);
    
    if ($value !== false) {
        return $value;
    }
    
    
    // do fib sequence for 1000 iterations..
    
    wp_cache_set("loop_".$numberOfIterations, $result_from_sequence, "maths_fibonacci", 3600);
    
    return $result_from_sequence;
}

Configuring WordPress for Object Cache

Now in your W3 Total cache you need to set up your page, object and database caches to use Redis. The Redis option is only available if you’ve correctly installed and added the php redis extension to PHP.

This will cause W3 Total Cache to use Redis as its cache store, and using the WP caching functions above will cause your own functions and queries to be cached in Redis through W3 Total Cache too.

There really is not much configuration beyond that!

John McMurray is a freelance PHP developer. Experienced in PHP, Laravel and WordPress he can code anything you need.

Based in Plettenberg Bay, Western Cape I am available for PHP, Laravel or WordPress freelance jobs in Johannesburg, Pretoria, Cape Town, Port Elizabeth. I also often do remote PHP freelance work all over South Africa and the rest of the world.

Share

Leave a Reply

Your email address will not be published. Required fields are marked *