Improving transient cache in WordPress

January 31, 2015

Anybody that has ever used WordPress has probably come in contact with the Transient API. While it is simple to use, I feel many times it leaves one to wish for more. Lately I’ve been using Laravel for a couple of projects, and the built in Laravel cache API is similar to the WordPress transient API — but better.

The one method that I really like in Laravel’s cache API is Cache::remember, which takes the usual key and expiration parameters, but also a callback function that let’s you set the cache if it’s been invalidated. In WordPress you have to retrieve the cache, check if it’s still valid and then either re-set it or return the cached results, do this a couple of times, and your code is hardly DRY any more.

/**
 * Example of using the WordPress transient cache.
 */
function getSomeCachedValue() {
	// Check if the value is in the cache
	$cachedValue = get_transient('myCachedValue');
	if ($cachedValue !== false) {
		// Return the cachedValue
		return $cachedValue;
	}

	// Nothing in cache, regenerate cache, set it, and return it.

	$cachedValue = // Something value

	set_transient(
		'myCachedValue',
		$cachedValue,  // cache for 12 hours.
		12*(60*60)
	);

	return $cachedValue
}

/**
 * Example of using the Laravel cache API.
 */
function generateValue() {
	// Return the value either through the cache or by regenerating and updating the cache.
	return Cache::remember(
		'myCachedValue',
		12*(60*60),   // cache for 12 hours.
		function() {
			return // Something value
		}
	);
}

So I did what any responsible developer should do, I ported the Laravel API to a simple class for WordPress. Initially I only ported the remember function, but the other methods are pretty straightforward, so I implemented them as well.

There’s some differences between the caches in WordPress and Laravel. You can never fully rely on the WordPress cache, and so it should be treated for what it is; a cache. Laravel on the other hand handles caching differently, and when you set something with an infinite expiration, it should be there until you remove it manually.

I’ve written the class with only static methods. The ones that are available are the following

/**
 * Gets an item from the cache
 *
 * @param  string $key     The unique key for the cache.
 * @param  mixed  $default (Optional) If value doesn't exist, return default
 *
 * @return mixed           The item from the cache.
 */
CacheService::get($key, $default = false);

/**
 * Deletes an item from the cache
 *
 * @param  string $key The unique key for the cache.
 *
 * @return void
 */
CacheService::delete($key);

/**
 * Deletes an item from the cache
 *
 * @param  string $key The unique key for the cache.
 *
 * @return void
 */
CacheService::forget($key);

/**
 * Retrieve an item from the cache and then delete it
 *
 * @param  string $key The unique key for the cache.
 *
 * @return mixed       The cached data.
 */
CacheService::pull($key, $default);

/**
 * Sets an item to the cache.
 *
 * @param string $key        The unique key for the cache.
 * @param mixed  $value      The data to cache.
 * @param int    $expiration Time until expiration in seconds from now, or 0 for never expires. Ex: For one day, the expiration value would be: (60 * 60 * 24).
 *
 * @return void
 */
CacheService::put($key, $value, $expiration);

/**
 * Adds an item to cache if it doesn't previously exist.
 *
 * @param string $key        The unique key for the cache.
 * @param mixed  $value      The data to cache.
 * @param int    $expiration Time until expiration in seconds from now, or 0 for never expires. Ex: For one day, the expiration value would be: (60 * 60 * 24).
 *
 * @return bool              True if added to cache
 */
CacheService::add($key, $value, $expiration);

/**
 * Adds an item to cache without expiration.
 *
 * @param string $key        The unique key for the cache.
 * @param mixed  $value      The data to cache.
 *
 * @return bool              True if added to cache
 */
CacheService::forever($key, $value);

/**
 * Checks if an item exists in the cache.
 *
 * @param  string $key The unique key for the cache.
 *
 * @return boolean     True if item exists.
 */
CacheService::has($key);

/**
 * Remembers a value.
 *
 * @param  string   $key        The unique key for the cache
 * @param  callable $cb         Callback that runs if the cache has expired.
 * @param  array    $params     (optional) Callback parameters
 *
 * @return mixed             Depending on the callback.
 */
CacheService::rememberForever($key, callable $cb, array $params = array());

/**
 * Remembers a value for a set amount of time.
 *
 * @param  string   $key        The unique key for the cache
 * @param  int      $expiration Time until expiration in seconds from now, or 0 for never expires. Ex: For one day, the expiration value would be: (60 * 60 * 24).
 * @param  callable $cb         Callback that runs if the cache has expired.
 * @param  array    $params     (optional) Callback parameters
 *
 * @return mixed             Depending on the callback.
 */
CacheService::remember($key, $expiration, callable $cb, array $params = array());

/**
 * Clears the cache completely
 *
 * @return void
 */
CacheService::emptyCache()

And here’s the implementation, as a Github repository.

Tags