If you’re a plugin or theme developer, there may come a time when you need to execute a long running operation. It doesn’t need to be anything complicated, but something as simple as fetching a Twitter feed can take a significant amount of time. When you come across these types of situations, it’s handy to be able to store the data on your own server and then fetch a new copy of it every X hours. This is called caching, and WordPress convieniently comes packages with an excellent caching API called Transients .
The Transients API is surprisingly simple to use. In fact, it’s very much like using set_option and get_option except with an expiration time. If you aren’t familiar with caching at all, here’s the general workflow:
- If the data exists in the cache and isn’t expired, get it.
- If the data doesn’t exist in the cache or is expired, perform the necessary actions to get the data.
- Store the data in the cache if it doesn’t already exist or is expired.
- Continue from here using data.
When attempting to use the Transients API for caching, there are three functions that you need to be aware of: set_transient, get_transient, and delete_transient.
- set_transient($identifier, $data, $expiration_in_minutes): This function stores your data into the database. The identifier is a string that uniquely identifies your data. Your data can be any sort of complex object, so long as it is serializable. The expiration is how long your want your data to be valid (ex: 12 hours would be 60*60*12).
- get_transient($identifier): This retrieves your data. If the data doesn’t exist or the expiration time has passed, false is returned. Otherwise, the same data you stored will be returned.
- delete_transient($identifier): This will delete your data before it’s expiration time. This is handy if you are storing post-dependent data because you can hook it into the save action so that every time you save a post, your cached data is cleared.
Now that we’ve covered the basics, how about a quick example?
if (false === ( $my_data = get_transient('super_expensive_operation_data') ) ) { $my_data = do_stuff(); set_transient('super_expensive_operation_data', $my_data, 60*60*12); } echo $my_data; function do_stuff() { $x = 0; for($i = 0; $i != 999999999; $i++) { $x = $x * $i; } return $x; } |
The example is pretty straight forward. We first check to see if there is a cached copy of the data, if not, we fetch the data from the “do_stuff” function, and store it in the database. Simple, right?
One of the benefits of using the Transients API (aside from speeding your site up) is that plugins like WP Super Cache or WP Total Cache will auto-magically cache your data into memcached if you have it set up. For you, this means an even faster site! If you have any questions about caching techniques or the Transients API, leave a comment and I’d be happy to help.
7 replies on “Caching WordPress Data with the Transients API”
On high concurrency sites, you need to set a lock on the process (using another transient) so that you don’t have multiple threads hitting the expensive operation before the first one is able to finish.
It’s also a good idea to do expensive operations on shutdown, or on a pseudo cron that runs before the transient expires, so a poor user doesn’t get stuck waiting for this operation to finish dynamically.
doesn’t the pseudo cron require a user to hit the site? so whatever user trigger the job, gets the performance hit?
Good points Mark. Care to elaborate on using a psuedo cron to trigger the operation without the user having to wait? In the context of “normal” cron, this makes sense, but I’m not entirely sure what you mean by “psuedo cron”.
By pseudo cron, I mean WP Cron, WordPress’ built-in pseudo cron implementation. When populating the transient for X minutes, you’d schedule a “force rebuild” of the transient to happen at X-5 minutes (assuming it’s something cached for long enough to allow this much room).
Coincidence I found this on reddit and I happen to have the same questions regarding Mark Jaquith’s comment, I was going to ask this a few days ago on wordpress.stackexchange because even though using the transients is simple there is a real lack of documentation on how it works, especially with regards to locking, garbage collecting, and running it off a cron.
Nice post!!
The Cron issue can make really good for easing your server load, but the use transients, even without a cron for the expensive operation, is a must do. With transients one user has to wait for the operation to finish, without then every user have to wait.
Concurrency problems may happen in high load sites, but for the 99% of blogs i would not worry about them.
Couldn’t agree more. I wish I had to worry about concurrency problems. I envy the folks who get to work on those types of problems.