Skip to content

Instantly share code, notes, and snippets.

@rask
Created July 9, 2015 13:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rask/c20b195ce0cc71778894 to your computer and use it in GitHub Desktop.
Save rask/c20b195ce0cc71778894 to your computer and use it in GitHub Desktop.
WordPress transients
<?php
/**==================================================================================
* WordPress transients example.
*
* This file shows the normal usage for WordPress transients with beefy comments.
*
* @author Otto J. Rask
*/
/**==================================================================================
* INTRODUCTION
*
* WordPress transients are a way to cache temporary data, such as database queries,
* API request results, post likes, and even whole HTML templates.
*
* Transients are saved to a cache system, such as memcache or Redis. By default
* WordPress uses its own database, so transients work everywhere where WordPress
* does.
*
* Transients are not hard to use, but there are some good and bad use cases. Also a
* few gotchas that might make your site work strangely or break in a bad case.
*/
/**==================================================================================
* STEP 1
* Define the transient key to which to save and from which to load the transient
* cacheable value.
*
* Transient keys should be unique per value. Example for generating transient keys:
*
* - Grab a WP_Query and serialize its query variables, then pipe it through
* `md5()` to generate a simple alphanumeric string for the key. Then prefix it
* with a custom key, such as ` myquery_`, which results in
* `myquery_123456abcdef` or similar.
*
* The key (no pun intended) is to make the key unique regarding to what is being
* saved to the transient cache.
*
* Remember: as of now/as far as I know, the WP options table (where transients are
* stored by default) limits the key length. To be safe, limit the transient key
* length (including prefixes) to 45 characters. If you have a key, you can use
* `substr($key, 0, 45);` to trim excess characters.
*/
// Custom hand-written key (remember 45 char limit!):
$custom_key = 'mykey_myuniqueidentifierhere'
// Or perhaps a generated key? Following are WP_Query arguments for some kind of
// posts that have a `post_thumbnail` set:
$query_args = array(
'post_type' => 'post',
'post_status' => 'publish',
'meta_key' => '_thumbnail_id',
'meta_value' => 0,
'meta_compare' => '>',
'posts_per_page' => 3
);
// Serialize the arguments and generate a unique key for transients to use.
$query_key = 'myvalue_' . md5(serialize($query_args));
// Following trims it down to 45 characters.
$query_key = substr($query_key, 0, 45);
/**==================================================================================
* STEP 2
* Get the transient value from cache.
*
* The cache can be the WP database, memcache, Redis, or any other object cache that
* is handled through `wp-content/object-cache.php`. Some object caches need plugins
* or customizations to your web server (e.g. memcache needs the memcached service to
* run in order to function properly).
*
* You could even write your own implementation that saves the transient data to a
* CSV file (not recommended, as transients work best with fast systems, IO is not
* fast generally).
*
* WordPress defaults to using a database. It uses the `wp_options` table to save
* transients.
*/
// Get transient cached data for the key we generated above.
$transient_value = get_transient($query_key);
// Oh wow was it that easy?
/**==================================================================================
* STEP 3
* Validate if the value has been cached to the transient.
*
* If the value has been cached to the transient (using the unique key),
* `$transient_value` now contains the exact value that has been saved to it.
*
* If no value has been saved, `get_transient` will return `false`. Remember to
* validate the `false` value strictly (using `===` or `!==`), because a
* transient could contain a "falsy" value such as `0` or `''` (empty string),
* which evaluate to `false` when using loose checking (`==` or `!==`).
*/
// Strict check for false (empty) transient.
if ($transient_value === false) {
// Oh no, transient value does not exist...
// ... fetch and save the transient here ...
}
// Strict check for existing transient value.
elseif ($transient_value !== false) {
// Transient value exists!
// ... do what you want with the value here ...
}
/**==================================================================================
* STEP 4
* Save a transient in case it does not exist (`get_transient` returned `false`).
*
* Saving a transient looks a bit similar to loading a transient with
* `get_transient`. The difference is we're using `set_transient` and we need to have
* a value to save.
*
* Additionally `set_transient` accepts a third parameter, a timeout value. The
* timeout value determines how many **seconds** a transient is considered to be
* valid before destroying the value (in which case `get_transient` would return
* `false` again).
*
* If no timeout is set, the transient value is assumed to be valid **forever**.
* Don't do this, as then it would be the same to just use the Options API. Always
* define a time out, even if it is a whole year (`60*60*24*365` seconds).
*/
// Transient returns false.
if ($transient_value === false) {
// We defined some query arguments earlier, use them to make a WP_Query.
$query = new WP_Query($query_args);
// WP_Query just did an expensive database request above. Now might be good spot
// to save the query so we do not have to access the database the next time.
// Save the query as a transient using the same transient key we used to get the
// `$transient_value` earlier. Set the query to invalidate in 30 minutes.
set_transient($query_key, $query, 60*60*30);
}
/**==================================================================================
* STEP 5
* Use the transient value in case it returned something else than `false`.
*
* If `get_transient` didn't return `false`, it means that we could fetch the wanted
* transient value from the database or memcahce or Redis or something!
*
* If we follow the PHP file from top to bottom, the saved transient was saved to
* the cache in STEP 4 and now we fetched it.
*
* This means that `$transient_value` currently holds the same thing that was saved
* to the cache, so essentially we can now just do `$query = $transient_value`.
*/
// We got some value from the cached transient.
elseif ($transient_value !== false) {
// Use the cached query.
$query = $transient_value;
}
/**==================================================================================
* STEP 6
* Onwards! We have what we need, cached or not.
*
* Now the `$query` variable contains a WP_Query object regardless whether it was
* loaded from transient cache or not. Next up we can use it just like we're used to:
*/
// Start Wordpress loop. `$query` contains a good-ole WP_Query for you to use.
// If we have any posts.
if ($query->have_posts()) :
// While we have any posts.
while ($query->have_posts()) : the_post();
?>
<div class="post">
<h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
...
</div>
<?php
endwhile;
endif;
/**==================================================================================
* STEP 7
* Destroy the cache if needed.
*
* One problem with caches is that sometimes they need to be cleared sooner than a
* default timeout value says.
*
* WordPress provides `delete_transient` for deleting transients. Just pass in the
* unique transient key and WP will take care of it.
*/
// If we want to destroy the transient each time a logged in used visits the page:
if (is_user_logged_in()) {
delete_transient($transient_key);
}
// Done!
/**==================================================================================
* FINAL WORDS
*
* Be careful of what you save to transients. You should never save private data to a
* transient that could end up being shown publicly.
*
* Don't use transients to store permanent data. Transients and other caches are
* designed to store temporary data that could disappear at any time. Make sure your
* website works with and without transients (see the `if-else` checks above.).
*/
/**
* By the way, this PHP file should work as is in a WordPress theme. Copy-paste it to
* Your theme and use PHP `include` in a template file such as `index.php`.
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment