How to use transients to improve shortcode performance

User-defined content from a shortcode
Not sure what transients are? Try reading the introduction to transients first.

The last way in which I want to show you how you can use transients to improve the performance of your WordPress site, is to cache dynamic shortcode data.

Storing dynamic shortcode data

The best way I can think to demonstrate this is how I did this with the same client that I had revised the custom queries for.

I had developed multiple shortcodes to perform various different and potentially complex queries to make displaying very specific data in different parts of the website very easy.

For example, when covering a live event, I created a shortcode that allows the site’s editor to pull in all the content from different custom post types that is categorised with a specific custom taxonomy, indicating that it is related to the specific event, enabling them to create a hub of content about the event with great simplicity.

This is just one of many such shortcodes that I created for this client to allow them to pull in content for various different scenarios like this. When each shortcode is used, on every page load, a complex WP_Query is run to retrieve this specific set of content. As you might have guessed by now, this is the perfect opportunity to use transients to cache these results instead of running that query on every single pageview, greatly reducing database queries and server load, and speeding up your site as a result.

The general principles I applied here are very similar to those I’ve already demonstrated in the other tutorials in this series, but the application is slightly different because we’re working with shortcodes instead of theme files.

I built all of my shortcodes in the site’s functionality plugin so that the shortcodes would continue to work if the theme ever gets revised in the future.

Here is the shortcode I mentioned in its original form, without using transients:

And now, here is the revised code, using transients to cache the shortcode results, with the line by line explanation below:

You’ll see that the shortcode accepts 6 parameters: type, showposts, feature, cat, offset and layout. All but one of these affect the WP_Query that I use to pull in the relevant content. “layout” is used to determine how the content is displayed and therefore is not important to the information that we’re going to store in the transient (because it only comes into play when determining how to display the content on the page, rather than what content to get from the database). This will be an important distinction shortly.

Everything until line 15 is the same as the original code. In line 15, we set a new variable, equal to the value of the transient which we retrieve using get_transient(). However, you’ll see that this looks more complex than the previous examples. Here’s why: in the first examples, there was no user input, so the data retrieved from the database was the same every single time. However, shortcodes can accept user-defined variables and thus can be as dynamic and unique as you want. That means that the information a shortcode retrieves from the database is different for each combination of parameters that are used.

For example, this example shortcode can be used to display content on a page about last year’s conference, and the same shortcode with a different set of variables can be used to display content about this year’s conference on a different page. So the transients need to be kept separate so that the unique data for each page are stored independently of one another.

That is why I’ve appended the value of each parameter to the transient name, separated by an underscore, with the exception of the “layout” parameter, for the reasons outlined above. So for example, on one page, I might use the following shortcode to show all of the podcasts about this year’s supercomputing conference:

[special-feature-content type="podcast" showposts="-1" feature="2014-sc-conf" cat="soundbites" offset="0" layout="bullets"]

Based on line 15, this will create a transient with the name “hpc_special_feature_query_podcast_-1_2014-sc-conf_soundbites_0“. This transient can then be used to make this particular use of the shortcode really performant.

You’ll notice that the beauty of this implementation is that the code will create as many transients as are necessary to cache the data for all the different ways the shortcode has been used, automatically.

Line 16 is the next difference, which takes a similar form to previous examples: it checks for whether there is data stored in the transient, and if there isn’t, then WP_Query is run (lines 17-29) to get fresh data from the database (note that this is the same WP_Query as in the original code). Then, line 30 saves this new information to the transient for use on future pageviews, using the set_transient() function. Note that the format of the transient name matches that used in line 15, adding the shortcode parameters to the transient name. In this instance, I have set the expiration time to just 3 minutes, because the website becomes very busy during these live events, and new content is constantly being added, so I want to forcibly check for new data at least every 3 minutes. More on that later.

The remainder of the code deals with how to take the data from the query and display it on the page, which doesn’t change between the original code and the revised code.

Expiration time

You’ll notice that the expiration time for this transient is very short, at just 3 times. However, for this implementation, that could potentially cover thousands of pageviews, so it’s still a massive improvement over running that WP_Query several times a second.

Like in previous examples, we want to forcibly delete the transients if we know they have become invalid. In this instance, that means that if a new podcast is published, we want to delete these transients so that the data is immediately refreshed with the new podcast.

However, here’s comes the caveat: because the shortcode has infinite possible combinations, you can’t list all of the possible transient names to delete them using the save_post hook, as we did with the custom queries (if anyone can think of a workaround, please let me know). This is another reason that I have kept the expiration time relatively short (it’s not the end of the world if new content doesn’t show on the site for up to 3 minutes after it’s published).

It depends on your particular shortcode: you might have just a few different parameters with very few, known values, such that you can list out all the possible combinations and delete them in the same way that I did in the custom queries example

Conclusion

So that concludes this series on how to use transients to store temporary data in the database to simplify and speed up repeated complex queries. It is by no means an exhaustion of the ways in which they can be used to improve performance, so I welcome your input on how else you could/have used transients on your own sites, or links to articles showing other implementations, for everyone to see.

2 thoughts on “How to use transients to improve shortcode performance”

  1. Jeff Rose says:

    To solve your problem with the dozens of variations, you could run a custom delete query on the database, using a carefully constructed ” where transient_name like ‘whatever_your_unique_base_is_%’ – but of course that’s potentially dangerous. You’d want to be 100% certain it’s sanitized and couldn’t just wipe out the DB!

    1. Yes, I suppose that is a way to solve it, but I’ve never interfaced with the database, not least because it scares the crap out of me! Nice approach though :)

Leave a Reply