Revised WordPress 3.6 menu UI

How to use transients to speed up your WordPress menus

| 8 Comments

Not sure what transients are? Try reading the introduction to transients first.

Following on the previous post in this series (using transients to improve the performance of custom queries), we’re going to look at another type of query that can be improved by using transients. We’re going to cache your navigation menus.

Caching WordPress menus

Every time you load a page on your site, chances are that you are loading at least one menu. To retrieve that menu, WordPress has to query the database to find all of the menu items associated with that menu and all of the data associated with them (menu item titles etc.). Using the same principles as improving the custom queries, we can cache this database query as well.

Take for example my original code for retrieving a WordPress menu:

Ever since the introduction of the menu functions in WordPress 3.0, nearly every theme now uses this method to display menus on your site, so you should have some similar looking code in your theme files.

Now, this is what my revised code looks like and I’ll explain it line by line, below:

In line 2, we’re setting our variable ($header_menu_query) equal to the value of the transient of the same name using get_transient(). On line 3, we check for whether that transient data exists. If it doesn’t (either because it hasn’t been created yet, or because it has expired and been deleted), we go ahead and run the query to retrieve the WordPress menu. In line 5, we set our variable equal to the result of the wp_nav_menu query.

Whereas in the example of the custom queries we didn’t change the query itself, we do need to make a slight tweak to the wp_nav_menu function. By default, wp_nav_menu echoes the result of the query (which is normally the desired behaviour, so that it appears on screen), but we want to return the data to PHP to be stored as a transient, so we need to add the argument ‘echo’ => 0 to the function, as shown in line 12. Aside from that, the remainder of the query stays the same.

In line 15, we take the result of the query and set our transient with that data using set_transient(), so that it can be reused on the next page load. Again, you’ll note that I’ve set a maximum expiration time (of 24 hours), but more on that later.

On line 17, we have to make a slight addition: since previously wp_nav_menu was automatically echoing the menu to screen and we modified the query to return it to PHP, we need to echo the result in order to actually see it, so we add in this line to achieve that.

Updating the transient

As with the custom queries example, we have set an absolute maximum expiration time for the data, after which we want to forcibly replace it. WordPress menus don’t change often, so this could be quite a long time, but 1 day allows you to do it often enough to check daily without impacting performance (one database query per day wouldn’t even be noticed).

However, we want to proactively delete the data when we know the data has changed. To do this, I wrote another function which I dropped into my functionality plugin, though this could just as easily go into functions.php. This is what it looks like:

I hooked into the wp_update_nav_menu action, which fires every time a WordPress menu is updated. Since this is so rare, I didn’t bother checking which menu had been edited, to decide which menu transients to delete, though you could certainly do that.

The function simply uses the delete_transient() function to delete all of my menu transients every time a menu is updated (I had two additional menus [footer_menu1 and footer_menu2] where I applied the same technique).

Now, the transients are refreshed at least every 24 hours, and immediately after a nav menu has been edited or saved. You’re now saving yourself several database queries on every page load, which can amount to a nice little savings, depending on busy your site is and how many menus you have.

Want to speed up other aspects of your site in a similar way? Try improving the performance of custom queries or improving the performance of your shortcodes.

Categories: Code & Snippets, Speed | Permalink

What next?

Hire me

If you couldn't quite manage this yourself, find it too intimidating, or just don't have the time to do it, you can always hire Dave to do it. Please get in touch so that we can discuss your needs.

Leave a comment

If you have a question, update, or comment about the tutorial, please leave a comment. I try and respond to every comment, though it may take a few days, so please check back soon.

Let a WordPress Expert help you

Do you want to try this, but feel like you need a helping hand, in case something goes wrong? My service, The WP Butler, gives you access to WordPress expertise whenever you need it. Better yet, I'll keep your site backed up, updated and secure, so that you don't have to worry about it. It's all part of the service. Use coupon DIWW and save 15% on all plans.

Visit The WP Butler

Author:

Dave has been tinkering with WordPress for many years, and he now shares his WordPress knowledge here on Do It WIth WordPress to help others realise its impressive power. He can also be hired to help with your WordPress needs. Dave, who is British, is married to his best friend, Marti, with whom he has a beautiful daughter, Ellie. When he's not dabbling with WordPress, he's probably eating Triscuits or hummus, watching an indie film or British TV show, spending time with friends or family, or exploring the world.

8 Comments

  1. Great articles! I have never used transients before, but will definitely start now.
    One question, though. How does this functionality work when using a cache plugin? Or does the transient implementation more or less become nullified if the the plugin caches the page and database queries?

    • To be perfectly honest, I’m not sure how this would work in conjunction with a caching plugin. It shouldn’t make anything worse, but I’m just not sure whether you’d realise the same savings as you would without a caching plugin. I’m not familiar enough with how caching plugins usually handle the database cache, so maybe someone with a bit more knowledge in that area can chime in.

  2. No code is showing up. When I look in the source there are HTML comments saying Missing Gist ID. You may need to look into that..

  3. If I’m not mistaken, you might not see a big benefit here.

    I ran through the wp_nav_menu code quickly and it appears that WordPress is already using a cache for this data.

    Not that this wouldn’t make an improvement, just probably not as big as the one in your first post about WP_Query.

    Of course, I only did a VERY quick check, so it’s possibe that I’m wrong.

  4. It’s a good idea and i tried once to use it a year ago or so.

    Your article reminded about this and made me to write an article (it’s in romanian, but the code is universal i guess) on my blog with a helper function.

    Also, one of my readers reminded me why i didn’t used this method more often: it makes impossible to highlight active menu item. I looked briefly on WP source and i found out that is not quite possible to use this without rewriting the whole wp_nav_menu function.

    • Interesting point. I hadn’t considered that it would break the “active” menu items, but you’re absolutely right. So, this isn’t a good idea for someone whose theme relies on it.

Leave a Reply