Advanced WordPress Development: Working With Transients

Advanced WordPress Development: Working With Transients

Transients are a super-handy type of WordPress caching that is often sorely underutilized. But what are they exactly? Simply put, a transient is a bit of data you can store with an expiration date.

This may not seem like much, but transients allow you to create more efficient systems in WordPress that clean up after themselves.

This is the third post in our six-part series focusing on WordPress for advanced developers. This series follows on from our popular WordPress Development for Intermediate Users, which introduced you to some meaty coding topics, including theme development in detail, making themes customizer-ready, building plugins, custom post types and taxonomies, queries and loops, custom fields and metadata, and localization.

In last week’s post, we explored writing object-oriented plugins. In this post, we’ll take a break from that and start looking at some advanced bits and pieces of WordPress. I’ll be using OOP in code examples where appropriate so if you feel lost it’s best you take a look at the first two parts of this series.

Let’s get stuck in.

Note: It’s important that you have a working knowledge of PHP as this is the foundational language of WordPress for this series, which covers advanced topics aimed at developers. I’ll be referring to code snippets throughout this series.

Why Use Transients?

Let’s say you’re creating a Pinterest module for your home page that displays your latest pins. A regular implementation may fetch your pins on every single page load. This is inefficient for a number of reasons:

  • It puts unnecessary strain on your server
  • Scaled up, the issue could increase your hosting costs and/or slow down your site
  • It causes unnecessary bandwidth usage
  • It may lead to you bumping into rate limits – your pins would not be shown until the limit is reset
  • You may put unfair strain on other servers if you use APIs

Transients are one way to solve this issue. They are essentially a caching mechanism. For example, instead of fetching your Pinterest pins and displaying them, you place transients as “middle men.” Retrieved pins could be stored in a transient with an expiration of two hours. For two hours those pins would be loaded locally. Once the two hours have passed, the transient would then be deleted and the pins re-fetched.

Another great use for transients is to store the results of complex queries such as related posts or complex header menus. You could take the result of complex queries, or the HTML generated based upon them and stash them in transients.

So How Do Transients Work?

To be able to build an efficient system you’ll need to know a couple of key things about transients: where they can be found and how their expiration works.

Where Transients Are Stored

Transients are usually stored in your WordPress database, but not always. A memcached plugin would force transients into memory instead, which makes them even faster. Therefore you should always rely on the get/set/delete functions provided by WordPress.

When Do Transients Expire?

When you set a transient you give it a maximum expiration time. The transient may be removed before the expiration time but it will never be available afterwards. The impact of this is that you should always have a fallback for regenerating data.

Building a Movie List With Transients

Our project for this lesson is to create a movie list using transients. I found a neat little API called Netflix Roulette, which provides a free way into the Netflix API. With its help we’ll be listing movies from a popular director: Martin Scorsese.

First thing’s first, you’ll need to create a quick plugin. Mine is named “my-favorite-director.” By this stage, you should be able to create a plugin that does nothing, but can be activated in WordPress. If you need help, take a look at our article Getting Started with WordPress Plugin Development: The Ultimate Guide.

How the Transients API Works

It’s quite simple really. The URL will return a list of Martin Scorsese movies, The returned data is a JSON string in the body. We’ll be using json_decode() to turn it into a PHP array and looping through it to create the following widget:

Movie list plugin
Movie list plugin

Building it Without Transients

The plugin contains two files. The main file – my-favorite-director.php contains the base class that launches all our functionality:

I’ve added a hook in the constructor method which fires the method that initiates the widget. Widgets can be created using the register_widget() function which takes the name of the widget’s class as its parameter.

The class must be available so I’ve included the file that contains it _ My_Favorite_Director_Widget.php – at the top. The code that creates the widget is the following:

The constructor method takes care of the basic details like the name and description of the widget. The form() method outputs the elements needed to save the widget details. In our case this is simply the title.

The widget() method is used to create the user-facing side of the widget. Using the HTTP API we send a request to the API and parse out the data we need. Then, we loop through the data, creating the movie list.

This should work just fine but our code is burdened with all the issues described above. Netflix Roulette is a publicly and freely accessible API so we should do everything we can to minimize the queries we send!


Our best pro WP tools in one bundle

Try free for 7 days
30-day money-back

Adding Transients

The logic of adding transients is always similar:

  1. Grab the data we need from a transient
  2. Check if it is empty
  3. If is empty get the data from the regular source and update the transient with the new data
  4. Use the transient value

The first step is to separate out the code that actually retrieves the data from the API into a new method within our widget’s class. Let’s call it get_movies().

Next, let’s modify the beginning of the widget() method to use the new method along with transients.

Using the get_transient() function we retrieve the value of a transient named “my-favorite-director”. If the value is empty (because the the transient never existed or has expired) we grab the data we need from the API and use it to update the transient using the set_transient() function.

This function takes the name of the transient as the first parameter, the data to store as the second and the expiration time as the third. I’ve used a WordPress constant to indicate that it should expire in a week.

Everything else is exactly the same. Instead of querying the API on every page load we’ve reduced this to once a week. That’s a fairly safe bet, directors don’t make new movies every day!

Extending Our Plugin With Multiple Directors

Right now the director is hard-coded into the plugin. Let’s change that and start supporting user input!

To begin we should add a text field to the widget form where users can enter a director’s name. The full code for the form method is the following:

The next place we need to go is the get_movies() method. In the widget() method we will call it like this:

We can then re-write the function to support an argument. All we need to do is url encode it and append it to the base URL.

If you fill out the form with “Quentin Tarantino” you’ll notice that the information is saved but you still see Martin Scorsese movies in the list. This is because we’re using the value of the “my-favorite-director” transient, which will only update in a week.

Add delete_transient('my-favorite-director') at the top of the widget() method (or wait a week) and reload the page. You should see the new movie list show up. Delete the delete_transient() call and let’s continue to figure out why this is as buggy as hell!

It looks good following a cursory glance, but try adding a second widget with a different director. You’ll get widgets with different titles but the same list. We’re using a single transient for two different sets of data which means that both widgets will show the same list. The solution is using variable names for our transients. Let’s modify the beginning of the widget() method.

Instead of using “my-favorite-director” we’ll be using “mfd-[sanitized director name].” For example, when grabbing movies from Mr Tarantino the transient name will be “mfd-quentin-tarantino.”

Each director will have a separate transient. On the first page load this will result in two API calls but they will be cached in a transient for a week – at which point another two API calls will be made.

Separate movie lists
Separate movie lists

Deleting a Transient Using Actions

In some cases you’ll want to add something to a transient that may be updated via a user action. For example, you could store the full HTML of the top navigation menu in a transient.

The HTML of the top menu never changes on its own but users may add/remove menu items. In these cases you can set the time limit to something extremely high and rely on other hooks to delete the transient when needed.

As you can see there’s nothing stopping you from storing a whole chunk of HTML in a transient. Always take care to map all the hooks that could modify the data you are storing, otherwise it may not sync up with the intentions of the website owner.

Wrapping Up

The Transients API is an easy to use and powerful feature of WordPress. I would advise caution when using it, especially if you will be using powerful other caching mechanisms in addition to it.

Generally, it’s a good idea to use transients for bits and pieces of data – especially results of API calls – but storing large parts of your site in transients is a no-no. There are exceptions of course but as a rule of thumb only use transients when you are positive that you’ll see a performance gain.

Did you find this tutorial helpful? Why do you want to learn WordPress development? What do you want to know more about? Let us know in the comments below.

Daniel Pataki

Daniel Pataki Daniel is the CTO at Kinsta and has written for many outstanding publications like WPMU DEV and Smashing Magazine. In his spare time, you'll find him playing board games or planning the next amazing office game like the not-at-all-destructive Megaball.