How to Improve WordPress Load Times Using Transients

WordPress Transients Tutorial
Standard

WordPress load times can be a serious concern if you’re working with a complicated page that has a lot of queries or API calls.

I’ve worked with several enterprise publishing sites, and site speed was always a concern because of the complex features that fill the page: related news, latest posts from several categories, news tickers, social media feeds, etc.

Loading so many features is a concern because hitting the database so many times so quickly can be a burden on the server, and when you factor in the limited number of API calls many services allow, we need a solution to store data for a brief period of time.

WordPress Transients

Enter WordPress transients.

Transients save information to the database for quick access. These are also nice because they can expire after a limited time, meaning that fresh data can be fetched based on time intervals.

The best part is they’re easy to use.

They work a lot like options or post meta in WordPress. It’s a simple function that takes a name, a value, and an optional expiration time.

Here’s how they work:

First, you check to see if anything is stored in the transient.

$value = get_transient( 'jr3_transient' );

If the desired data is not there, get your data and store it in the transient.

$value = jr3_get_data();
set_transient( 'jr3_transient', $value );

The nice thing is that you can set an expiration time for the transient. This means that if you need to only store the data temporarily, even if it’s just a few seconds, you can do that by adding the third parameter to the function.

// Store for 5 minutes.
set_transient( 'jr3_transient', $value, 5 * MINUTE_IN_SECONDS );

Here’s a more fully-featured example:

<?php
/**
* Get News posts.
*
* This is from a tutorial found here:
* @link https://johnregan3.wordpress.com/how-to-improve-wordpress-load-times-using-transients
*
* @since 1.0.0
* @uses jr3_news_query
*
* @return array Array of news posts, else an empty array.
*/
function jr3_get_news() {
$output = get_transient( 'jr3_news' );
/*
* Side note:
* When an empty array is possible
* (like if a stored array of posts is empty because
* none were found), don't do the typical "! empty()" check.
*
* If the transient is not found, it will return false.
*/
if ( ( false !== $output ) && ( is_array( $output ) ) ) {
// Return the array stored in the transient.
return $output;
}
// Imaginary function to fetch data.
$results = jr3_news_query();
if ( is_array( $results ) ) {
// Set our transient to expire in one hour.
set_transient( 'jr3_news', $results, HOUR_IN_SECONDS );
return $results;
}
// At a minimum, return an empty array.
return array();
}

Advanced Transient Names

It’s possible that you want to store the transient name based on the post being viewed, as may be the case if you are storing data for posts related to the present post. You can do this by adding the post ID to the transient name:

$transient_name = 'jr3_transient_' . get_the_ID();
$value = jr3_get_data();
set_transient( $transient_name, $value );

Super-Advanced Transient Names

It’s important to note that transient names are limited to 191 characters. This can be an issue when storing a specific WP_Query call. I run into this when I’m doing taxonomy queries, which are notoriously slow. In order to save this data in a transient name, I actually use the query arguments to generate the transient name.

Let’s say this is our query:

$wp_query_args = array(
'post_type' => 'book',
'tax_query' => array(
'relation' => 'OR',
array(
'taxonomy' => 'genre',
'fields' => 'slug',
'terms' => $genre_array,
),
array(
'taxonomy' => 'publisher',
'fields' => 'slug',
'terms' => $publisher_array,
),
),
);

Since we don’t know for sure what the $genre_array and $publisher_array will hold, we can’t hard-code a static transient name.

To solve this, we’ll use the actual $wp_query_args array to generate the transient name. We do this using two methods.

First, we turn the array into a string format using maybe_serialize(), but this still leaves us with the issue of running into the 191-character limit on the transient name.

Second, to handily convert this potentially long serialized string into a shorter string, we convert it into an MD5 hash, which turns our long string into a 32-character string, allowing us room to prefix it.

$transient_name = 'jr3_' . md5( maybe_serialize( $wp_query_args ) );

This allows us to do something like this, ensuring that this specific query will be stored in the transient:

<?php
/**
* Get Books posts.
*
* This is from a tutorial found here:
* @link https://johnregan3.wordpress.com/how-to-improve-wordpress-load-times-using-transients
*
* @since 1.0.0
*
* @param array $genre_array An array of genre slugs.
* @param array $publisher_array An array of publisher slugs.
*
* @return array Array of books, else an empty array.
*/
function jr3_get_books( $genre_array, $publisher_array ) {
/*
* For the sake of this tutorial, we'll assume
* $genre_array and $publisher_array are valid arrays.
*/
$wp_query_args = array(
'post_type' => 'book',
'tax_query' => array(
'relation' => 'OR',
array(
'taxonomy' => 'genre',
'field' => 'slug',
'terms' => $genre_array,
),
array(
'taxonomy' => 'publisher',
'field' => 'slug',
'terms' => $publisher_array,
),
),
);
// Generate the transient name.
$transient_name = 'jr3_' . md5( maybe_serialize( $wp_query_args ) );
$books = get_transient( $transient_name );
if ( ( false === $books ) || ( ! is_array( $books ) ) ) {
$books = array();
// Run the Query.
$query = new WP_Query( $wp_query_args );
if ( is_array( $query->posts ) ) {
// Rename for output.
$books = $query->posts;
// Set our transient using our generated name.
set_transient( $transient_name, $books, HOUR_IN_SECONDS );
}
}
return $books;
}

Conclusion

If you are working on a site with lots of queries, you really should be using transients. They are extremely hand for temporarily storing data, whether it be an array of posts, or the results of an API call (like fetching recent tweets). They are easy-to-use, and can be set up in just a few minutes.

Further Reading

Leave a comment