How To Use Transients To Speed Up Your WordPress Theme

How To Use Transients To Speed Up Your WordPress Theme

One out of all the WordPress APIs is often overlooked by developers – the Transients API. Sure, at the time you had started developing for WordPress, you first needed to get around in the system. But trust me, you definitely want to know how to use transients – because transients make your WordPress website faster. This is not only important to make sure that potential visitors don’t leave your site before it has even loaded, but also for SEO these days – Google & Co. put a lot of emphasis on your website’s page speed. The faster it loads, the better it possibly ranks. In any way, a faster page speed is better than a not-so-fast page speed. That’s why you need to use transients in your WordPress themes and plugins.

How do transients work?

It’s actually very easy to explain: A transient is a set of data that is (by default) stored in the WordPress database, exactly like all the options that come with themes and plugins. But there are two big differences:

  1. While options are stored permanently, transients can expire: Everytime you store a transient, you need to specify the number of seconds this transient will be saved (this is usually a very high number which corresponds to the number of seconds a whole week, month or even year has).
  2. There are some very handy caching plugins for WordPress which improve the results of using transients even more by implementing object cache. When you use such a plugin, transients are no longer saved in the database, but instead they will be stored persistently across page loads. The plugin I would recommend for this is the great W3 Total Cache plugin.

When should transients be used?

You could now think that transients should be used as much as possible. Generally, this is not the case. There are different opinions on this topic, but the what most of them have in common is the following:

It is recommended to use transients when…

  • you’re using complex functions which create a good load of HTML code (store the HTML code in a transient instead of recreating it on every page load)
  • you’re using complex database queries, for example to query recent posts, navigation menus or something similar (use a transient to store either the query results directly or the HTML code that is created using the query results; I recommend the latter)
  • you’re connecting to another server to fetch information, for example when connecting to WordPress.org to retrieve plugin information or to the Twitter API to request your latest tweets (again, use a transient to store either the results directly or the whole HTML code that embeds the results)

How do I use WordPress transients?

There are three basic functions to know when using transients of which you will most certainly use the first two the most:

set_transient( $transient, $value, $expiration ):

This function either creates a new transient with the name $transient or, if the transient $transient already exists, it updates the content of the transient. In both cases, the content that is stored in the transient is specified by the $value parameter (it can be anything, a number, a string, an array… Finally, the $expiration parameter defines how long this transient will be stored before it is regenerated (measured in seconds). You can either input an integer value directly or use one of the WordPress constants created especially for this case (they were introduced with WordPress 3.5):

  • MINUTE_IN_SECONDS (60)
  • HOUR_IN_SECONDS (3600)
  • DAY_IN_SECONDS (86400)
  • WEEK_IN_SECONDS (604800)
  • YEAR_IN_SECONDS (31536000)

Of course, you can also combine a constant with another integer value, for example 3 * DAY_IN_SECONDS would correspond to three days.

get_transient( $transient ):

This function retrieves the content that is stored in the transient named $transient. If this transient does not exist or has expired, the boolean value false will be returned instead.

delete_transient( $transient ):

This function deletes the transient named $transient manually. Deleting transients manually can be useful when you’re updating options that would change the output that is currently stored in the transient. For example, if you have stored the whole content of a widget in a transient and then you change a widget setting, you probably would like to have your transient regenerated immediately to apply the changes.

Note: Due to a limitation in the WordPress database, transient names must not be longer than 45 characters. Otherwise the full names cannot be saved which can lead to errors.

If you still have no idea how to use it, don’t worry, the examples are right below!

Hands-on Examples for using transients in your Theme or Plugin

How To Speed Up WordPress Navigation Menus

Whenever a WordPress nav menu is outputted (using the core function wp_nav_menu( $args )), a complex function using multiple queries is executed. We can definitely speed that up a lot! Take a look at the following function that you can easily integrate into your own theme: Just replace the calls to wp_nav_menu with a call to this function:

As you can see, at first the function tries to retrieve the transient with the name specified by the $theme_location parameter (prefixed by ‘nav-‘, this is just for a better overview). Immediately after it, an if-clause follows that is only executed if the transient could not be retrieved (either because it doesn’t exist or has expired). So all that is done in that function in this case is outputting the transient’s content. If the transient could not be accessed, it will be (re-)generated by executing the if-clause. This clause simply contains the actions that are normally executed when printing a navigation menu in WordPress (just make sure that the ‘echo’ key in the array is set to 0 so that the nav menu is returned instead of echoed). After creating the navigation menu and saving it in the temporary variable $menu, the new transient is set with the content of the $menu variable and an expiration timeout of one week.

I hope you see how simple it is: After executing the above function for the first time, the transient exists for one week. So everytime the function is called again within this week, it works as fast as retrieving the transient and outputting its contents.

It is perfectly fine like this – there is just one thing you should take notice of: Since the expiration timeout is set to one week, the navigation menu is only “refreshed” once in a week. So if you make changes in this navigation menu, they won’t show up immediately, but only after the transient has expired. Some theme developers may be okay with it, and of course you could adjust the $expiration parameter of the set_transient call to make the period shorter, for example to refresh every day. The higher the expiration timeout, the less often the function’s more complex part is executed – but it also refreshes less often. You need to decide yourself how you’re gonna handle it.

There is, however, an alternative way: You could also set the transient’s expiration time to a whole year (or even longer) and delete the transient manually if something changes (I also like to call this ‘invalidating the cache’). In most cases, a navigation menu for a website does not change very often, so this might be the best solution. The only thing a little more complicated is figuring out all the places in the code that contain adjustments which would affect the content that is stored in the transient. For a navigation menu, this is not too hard – including the code below in your theme will do the trick.

The function above will only be called if the WordPress Core hook ‘wp_update_nav_menu’ is fired. This hook by default passes the ID of the menu that was changed to the function (the $id parameter). The function now retrieves all the nav menu locations and checks which of them contain the menu that has been modified (a menu can possibly be found in multiple theme locations). If the modified nav menu is indeed tied to one or more of the locations, the transient(s) with the name of each location (again prefixed by ‘nav-‘, like in the other function before) is/are deleted. That means: if a nav menu without any defined location is changed, nothing happens (since we defined the transients according to the theme location and not according to the menu ID itself.

Note 1: The above code fully works, however there is one thing you should keep in mind: Unfortunately, the WordPress Core does not contain any hook that triggers when editing menu locations in the Manage Locations admin screen, so there is no way to delete the transient when modifications have been made in that screen. Please make sure to adjust all the changes in the Edit Menus screen (locations can be tweaked there too), and it will work fine. Just if you’re interested: A hook somewhere within lines 362-369 in wp-admin/nav-menus.php passing the $_POST['menu-locations'] variable would fix this issue.

Note 2: Please be aware that you surely can only delete the transient manually if you have control over whether something changes. There are cases (for example when requesting information from another host, like your Twitter feed) where you’re not able to check if something has changed (and therefore cannot delete the transient accordingly). In these cases you simply have to adjust the $expiration parameter to a period that suits you.

How To Cache A WordPress Widget

As a second example, you will see how to cache a WordPress widget using a transient. Since the code to do this has to be contained inside the widget class, it will only work for custom widgets. That’s not bad though as many of the WordPress Core plugins are cached by default. In this example we will create a simply Recent Posts widget (like the one that’s already bundled in the WordPress Core), but we will include featured images there. This example widget will not have any settings applied (except for the widget title), so we can fully concentrate on caching it perfectly. At first, see the widget code below.

Since it’s a whole widget, there’s still some code involved, but we’ll break it down into just a few parts which are important for us.

  1. First check out the widget( $args, $instance ) function. Except for the $before_widget and $after_widget variables which are created automatically everything else that’s being printed is stored in a transient. When using transients with widgets, it is important to consider that a widget of the same type can be used multiple times on the site, so it would be not very clever to simply give it any name. When someone uses multiple instances of this widget, each instance would always look the same since all would share the same transient. That’s why we need to do it differently: the ID of the widget is perfect for this. It is created automatically by the parent class WP_Widget and can be accessed anywhere within the class using $this->id. So we simply use the widget ID (which is always unique) as the transient name.
  2. In this widget, the code that creates the output goes from line 24 to line 100 (feel free to check out these lines, but they’re not what we will deal with here). Using the transient we not only “skip” these 76 lines, we also exclude some heavy database query (which is executed in line 35). As described earlier in this post, we could also be satisfied with only caching the $results of this query in a transient – but why doing that when we can also cache the whole widget content which is tied to the results anyway? The transient is (re-)created in line 99.
  3. Now about deleting the widget transient: When you scroll down to the bottom of the class, you will find a simple function called invalidate_widget_cache() which consists of only one single line that deletes the transient. All we need to do now is hook this function to all the actions that could possibly change the content of this widget. There are four cases that this can happen – when we save a post, delete a post, change the WordPress theme or update the widget settings. The last thing is done internally in our widget (in the update( $new_instance, $old_instance ) function), so we directly call the function there that deletes the transient. The first three cases can be covered using WordPress hooks, so (in the constructor of this class) we use these three corresponding hooks and add our invalidate_widget_cache() function to it.

Improve the Page Speed of your WordPress Theme (or Plugin!)

You’re ready to speed up your WordPress blog or website now – thanks to the easy-to-understand Transients API. Visitors and search engines will thank you.

I hope you found this tutorial helpful – let me know if there are any questions. Oh, and feel free to share your own ideas or concepts of using transients. There are probably lots of things in WordPress where speed could be improved using transients – just do not overuse it in places where it won’t help at all.


Posted

in

by

Tags:

Comments

  1. Trevor Robertson Avatar
    Trevor Robertson

    Thank you very much for posting your ideas for using transients, especially using them to speed up WordPress Navigation Menus, which once they get even slightly large on lower power servers horribly slow down the site. The word needs to be spread about doing this, it’s such a huge page load speed improvement!

    However I also could use some help with your function. I’m finding an issue on a recent site I just started developing locally. The transient function otherwise has worked great on all other sites I’ve retroactively added it to. The issue I am having is the “current-menu-item” class is being cashed on this site, on all menus I’ve tried to create. Any thoughts as so why that might be happening now and what I can do to avoid it?

    Thanks!!

    1. Felix Arntz Avatar

      Hi Trevor,

      thanks for your kind words!

      Concerning your problem, I recently discovered the same issue. The problem is when you cache a nav menu, it also caches all the classes including the one that stands for the “active/current” state. Unfortunately, I do not have a real solution on how to fix this – what I currently do is just disable the “active/current” markup completely for cached nav menus (by using the filter ‘nav_menu_css_class’. That means that the current menu item will not be highlighted at all, but in my opinion that is still better than highlighting a menu item which is actually not the current one.

      Here’s the link to a gist with the code that disabled the “active/current” class for me: https://gist.github.com/felixarntz/9519350

      I recommend you to try it first since it might not work with all themes (as they might use their own navigation walker class and different CSS class names), but you should be able to make it work with your theme as well, simply replace the active class with an empty string. I hope that helped you.

      Still, as I said, that’s definitely not the perfect solution – if you find a better one, I would appreciate if you share it here!

      1. Trevor Robertson Avatar
        Trevor Robertson

        Thanks for the tip Felix. Unfortunately I don’t really see an elegant workaround for this. It’s surprising as I’ve seen a number of sites suggesting the use of transients to cache your wp_nav_menu(). But as I see it the current-menu-item bug will always be an issue since it of course just caches one menu load on every page.

        The only work around I can think of for now is using the filter you posted then I guess using jQuery add add a current class on page load. Not ideal but an option I suppose.

        1. Harun Akgün Avatar
          Harun Akgün

          First of all, this is not a bug, but a feature.

          Caching a data will keep it as it is unless overwritten or expired. So, instead of caching the dynamic HTML, you should cache the data source that generates the HTML.

          1. Trevor Robertson Avatar
            Trevor Robertson

            Indeed, bug is the wrong term for sure, but storing wp_nav_menu as a transient and thus storing current-menu-item class incorrectly is also not what anyone would want.

            Not sure what you mean by caching the data source that generates the HTML. Any chance you can explain that in relation to caching wp_nav_menu?

            The idea of using transients for wp_nav_menu is definitely nice because that function is such a resource drain (and as you noted significantly slows down your site) if you have any kind of menu structure with nested menus. Nevertheless, I think overall one is better off caching your entire site through a WP caching plugin as then the issue of the current / parent menu item being stored in the transient is a non-issue.

          2. Harun Akgün Avatar
            Harun Akgün

            There could be couple of workarounds for wp_nav_menu.

            First of all, you can cache all the possible versions of the wp_nav_menu. You can give a unique key for each of your pages, for example your home page transient key will be “nav_menu_home” but contact page key will be “nav_menu_contact” thus, you will have no problem showing different css classes per page. This will have a small impact on the db as it stores the transient on options db and only deletes them if you try to call them after getting expired. (a cron job would clean them)

            Secondly, you can use transient as you use now, but with an additional method. Before echoing the menu to the page, you can crawl in it with php DomDocument, remove “current” class from all menu items, and find the real current menu item and add a “current” class. (I know this is processor heavy, but i bet it will be faster than default wp_nav_menu function without transient.)

            Finally, i have one more idea that involves the previous comment i posted and that you asked about, but i don’t want to say it on top of my mind i need to check if it works first, then i will share my ideas about it.

  2. JK Avatar
    JK

    Testing on my local dev server, I put my menu in a transient. queries from my theme on front page went down from 29 to 12 (and I’ll be knocking some of those 12 out with other transients!), and db time from the theme went from 0.02s to 0.0055, so huge savings. I’m currently dumping the whole output menu HTML into the db, and calling it out the same way, using get_transient and set_transient.

    Just wondering if I need to do any escaping or encoding/decoding of this HTML to make sure the HTML doesn’t break if my generated menu items have quotes and such in them. Any advice?

    1. Felix Arntz Avatar

      I did that a few times too, storing HTML in a transient, and I didn’t face any problems, just store it as a plain HTML string.

      However, I recommend not overusing transients for this since you should rather put only those contents into a transient which cost a lot of site speed, for example results of external requests or huge queries that don’t change regularly. Generating HTML code is a rather basic operation, so instead of storing the whole code in a transient, why not just go with an array of results (as an example)? I know I stored the HTML in the above article (and that’s not bad), it’s just another thing I figured out (I wrote the article quite a while ago). Just remember, if you store an array in there and retrieve it using get_transient, make sure to unserialize it because (different from arrays in WP options) this is not handled automatically. Another way for storing an array would be to json_encode it before. Hope this helps.

  3. […] un œil à l'article de leaves and love qui m'a inspiré cet article. Vous y trouverez quelques exemples pour utiliser les transients dans […]

  4. Collins Agbonghama Avatar

    Even though this tutorial was written years ago, it still hold true till today.

    It is worth noting that transient uses any active object cache such as memcache or redis. It only fallback to using database if no object cache implementation is found.

Leave a Reply

Your email address will not be published. Required fields are marked *