The Transients API in WordPress is a simple method for storing cached data in the database. It allows us to take resource-intensive queries and store them in temporary caches to improve performance. Transients are temporary, meaning that after a specified amount of time, the cached data will be deleted and re-cached, or updated.
This quick demonstration will walk you through how to use transients in your WordPress development.
Working with transients is quite simple. There are just three functions that you really need to know about:
- get_transient() – Used to retrieve the cached data
- set_transient() – Used to store data in a cache
- delete_transient() – Used to delete cached data
The function below will demonstrate a very, very basic usage of transients:
function pippin_transient_demo() { // get the cached data $data = get_transient('sample_trans'); // check to see if data was successfully retrieved from the cache if( false === $data ) { // do this if no transient set $data = 'This is the data stored in the transient'; // store the data and set it to expire in 10 seconds set_transient('sample_trans', $data, 10); } // this will output "This is the data stored in the transient" regardless of whether a the data was retrieved from the cacue or not. echo $data; } add_action('admin_notices', 'pippin_transient_demo'); |
While the example I just showed you is extremely simple (and silly), the implementation in a realistic situation is the same.
If you would like a more complete example that demonstrates a realistic usage, then check out Michael Martin’s great tutorial on listing recent comments with the transients API.
Update 02-01-2012:
Piet (in the comments) pointed out a really great article that walks through quite a few great examples of how to use transients in real world examples. Check it out the article on speckyboy.
nice and simple example, thanks! I suppose it can be useful to get data from external domains too, like a twitter follower count?
one thing: the sound of your keyboard typing is really loud and distracting, sounds like your hitting a drum 😀
Yep, that’s a perfect example of what it could be used for. Michael Martin (who I linked to at the bottom) actually did a tutorial on exactly that.
Yeah, still working with my new mic and figuring out settings and such. It probably doesn’t help that my keyboard is on a hard wood desk 😛
thanks for this very clear tutorial, it makes a lot of sense at last!
I also have a question regarding all these transients feeds stored in the database. Last night I was switching a site over to another server and as the site already exists for a couple of years, it has heaps and heaps of these transients stored in the database. Mostly in the options table and many are feeds of installed plugins, wordpress news feeds, wordpress plugins news feeds, etc.
Is it safe to just delete that whole bunch in order to make the database a little smaller or does it not matter at all or can it not be deleted just like that?
You should be able to delete them no problem, though some will likely just be recreated by your active plugins / theme.
thx for the reply. yeah I am wondering why they would be recreated. A feed normally takes only the last 10 posts, correct? Or in this case it takes everything since the plugin was installed or sth?
It could be a variety of things. Since they’re created through plugins, anything could be happening.
I’ll add my thanks for the clear and understandable tutorial.
You mentioned how transients are very useful for expensive queries. I get the concept, but I’m not so clear on when queries are more or less expensive. Usually when I write queries I’m just happy to get back what I wanted. However, I can’t say I know how to optimize those queries or recognize when they are on the expensive side.
Any chance you could offer a tutorial or a series on queries?
Sure! I can definitely look into doing some tutorials on queries.
Just did some more reading on transients form an article that was published at the end of last year, might be interesting for others too, so I thought I’d share it here: http://speckyboy.com/2011/12/14/website-speed-part-3-caching-wordpress/
Oh, thanks for the link. That’s a good article with tons of good examples. I’ll update the post with it.
Awesome tutorial Pippin, your videos are really great for seeing the steps completely. Great resource, the transients API has to be one of my favorite features in WordPress as a developer these days. Comes in useful surprisingly often!
Thanks, Michael! I’ve only just recently started using Transients, but I love what they can do!
Very Good!
I will start using this. 🙂
Glad you like it, Sam.
What’s your opinion on using this on a custom post type that does 3 separate queries? For example, I’d set the transient as ‘collection_pages_’.$post->ID and since there are three per post (in the post type), there’d be 3 x the amount of posts. It seems like a lot to store in the options table — but in your mind, do the performance gains outweigh the extra DB size?
Am now storing the three queries in an array — that better you think? 🙂
What do the queries look like?
http://pastebin.com/SPS4YM94 for example
Yes, those are good to drop into a transient. I asked Otto about it and he said there was no problem with having literally thousands of these entries in the DB. On of the the sites I’ve worked on that has over 50K users, we’re using transients to cache info related to each individual user without any problems at all.
Ah great! Yeah I noticed the number of queries go down after implementing – so I’m excited to add this onto other areas. Just wondering – according to that SpeckBoy article, you need to have WP_CACHE turned on in wp-config — I didn’t see a caching plugin from your screen-cast, are you currently using one?
Also – a mental note for myself (not sure if this was covered in the video), but transients are not good for when your query is getting random posts – as they won’t be that random anymore 😉
Thanks!
Transients do not require WP_CACHE be turned on, but other caching methods in WP do.
Ah thanks for clarifying – that part didn’t make sense to me on that other article. I’m thinking of rolling in Transients to single post views — and then what I could do is on-save (in the back-end) delete the transient (so it is always kept up to date if the content is ever re-edited) but have a decently long expiration time. Does that sound plausible/a good idea? Transients are pretty cool, but I’d hate to go over-board on that if what I’m thinking isn’t necessary with caching methods (or if this is just a better “cache within a cache”). Thanks!
That’s a great idea in fact. I’ve done that a couple of times using the “save_post” hook so that the contents are always up to date.
Nice, off I go! 🙂
Any idea why this doesn’t work? https://gist.github.com/3935999
If I delete the transient stuff it displays the count just fine.
Bah! Never mind. Looking at it for so long I didn’t notice I used follower_count in one place and subscriber_count in another.
Thanks for the great intro.
That’s easy to do 🙂
I am guessing that the RSS feed reader in WordPress uses this mechanism for caching the feeds. I found info on the “wp_feed_cache_transient_lifetime” filter for globally setting the feed timeout length.
However, when I look in the DB, it appears that WordPress actually sets this value for each individual feed, even though the filter mechanism doesn’t allow you to specify individual feeds. I’ve looked through the various RSS related files in wp-includes and I can’t seem to figure out the mechanism for naming the transients of each feed.
One of the RSS feeds on a client site displays all of the articles for a given category. I’d like to flush the cache for that feed when a new article is posted. Otherwise, it takes up to an hour for the article to show up (I set the global timeout to 1 hour).
Any ideas as to where I might look?
I’ve never played with that filter so I can’t say for sure. I’d imagine if there isn’t a unique filter for each, then there is probably a way to detect which feed we’re working with from inside of the filter. Is there?
After doing a lot of research, I have discovered that fetch_feed saves the following in the wp_option table:
_transient_timeout_feed_mod_XXXX
_transient_timeout_feed_XXXX
_transient_feed_mod_XXXX
_transient_feed_XXXX
where XXXX is an md5($url), so the following will delete the cache for a given feed:
$key = md5(“your_feed.url”);
delete_option( “_transient_timeout_feed_mod_{$key}” );
delete_option( “_transient_timeout_feed_{$key}” );
delete_option( “_transient_feed_mod_{$key}” );
delete_option( “_transient_feed_{$key}” );
The URL itself is not stored in the database if you call fetch_feed() directly. So there is no way to get a list of the feeds you’re using, unless you are using them through the RSS widget which does store the names of the feeds.
Presuming you know the URL of your feed and you use md5() on it, you can find the timeout value for the feed and change that value. I’m guessing… I haven’t tested it yet.
That sounds correct and should work just fine. Let me know if it works once you test it out!
Yeah it works. I was able to change the time-out value for internal RSS feeds (feeds that come directly from my client’s web site) to 1 minute and leave the external feeds coming from outside sites at 1 hour.
What I need to do is filter calls to fetch_feed so that I can build an index of RSS feeds and store them in wp_options. Then I can create a plugin that allows admins to individually set feed time-out values. Not sure how to do it yet, but I’ll figure it out.
Great!
Thank you! This is so much easier to understand than I thought it would be. Just one query; do you know if it is possible to force the API to recache the query? For my example, I am using the API to store a list of users for my staff display, but I have multiple queries to make to get it in the right order because managers. The chances of that changing in a month are small, but if I set it to recheck every month and it checks towards the end of the month, for example, and we have a new member of staff that comes in at the beginning of the month, could I force the cache to refresh somehow? If so, then I can extend the time period for longer than four weeks and be comfortable with knowing that an update can be pushed through.
Would you like to force it to refresh through a manual action or programmattically?