Stand With Ukraine. Stop Putin. Stop War.

This article has been translated to Russian as well. Know of any other translations? Let me know!

MODX has very granular caching possibilities. Where Evo limits caching to just snippets and has other limits in terms of embedding tags in tags, MODX Revolution does not have these limits.

In MODX Revolution you can cache / uncache any tag you may use. That includes snippets, but also setting tags, placeholders, chunks and even lexicon strings. This article will talk you through some reasons when to call what cached in MODX Revolution (but it will save you most of the inner workings).

It is important to realize that, unless you're doing real advanced stuff and have overriden the core caching, the cache will be cleared when you: save a resource, element and to some extent settings. So basically, whenever your content or structure is changed - your cache will be updated to reflect that.

How do I tell MODX to (not) cache a certain tag?

Simply add in the exclamation mark (!) in front of the token. The token is a dollar sign ($) for Chunks, a plus sign (+) for placeholders, a percentage sign (%) for lexicons and an asterix (*) for resource fields and template variables. Snippets do not have a token.

Examples cached:

[[Wayfinder]]
[[$chunkname]]

Example uncached:

[[!Wayfinder]]
[[!$chunkname]]

Four Guidelines for Caching Strategies

  1. Cache everything you can.
    In general you will want to cache as much as you can - why should MODX retrieve the content from the database on every request, when it hasn't changed? While this may seem logical (and there is rarely any question on wether to use resource fields cached or not), the same applies to other tags. If the output of a snippet doesn't change on every request - why should MODX parse the snippet on every request? It shouldn't.
  2. User-specific output needs to be uncached.
    Anything that outputs user specific information will need to be uncached. Simple - any request could be made by different users, so it wouldn't do any good to load user-specific information from cache. This applies to snippets that interact with the user system (the Login package, a Wishlist component but also Quip for commenting), but also the somewhat less known [[!+modx.user.id]] placeholder.
  3. Content related to URL parameters or POST data needs be uncached.
    If you're using a form which displays information about what was posted, you don't want that to be fixed and cached. So call that uncached as well. If your output is different depending on (non-id/q) URL parameters (for example a search results page), you will want to make sure the related snippet is not cached.
  4. Use custom caching when needed.
    If data (in a snippet) changes before the cache has been cleared, for example if data is retrieved from an external XML source that changes independantly to your MODX Content, you will want to use a custom caching method such as the getCache snippet or write your own caching within the snippet code.

Exceptions

Of course there are exceptions...actually, I could only come up with one so far: (Updated October 26th, came up with another one!)

  • site_url, http_host and related system settings may be called uncached. If you have a certain setup in which one resource+template combination may server multiple urls, you will want to make sure the related system settings are called uncached. One common application for this is your <base href="[[!++site_url]]"> tag for friendly URLs: you will want to be sure your assets are served from the same domain as the user visited. Wether you should force www/no www through htaccess is a whole different discussion, but that is very much related to this and a common cause for issues.
  • Snippets that (may) redirect or forward elsewhere will usually need to be uncached as the result may be empty, but the processing of the snippet does the work to redirect the user.

Common Errors

  1. Calling the "if" snippet uncached, when the subject is a resource field. Most likely caused by the documentation having uncached examples, a lot of people mis-use the If snippet by not caching it when the subject is static for the cache lifetime.
  2. Calling the "Wayfinder" snippet uncached. Please don't! Wayfinder especially can take a good performance hit on your website with larger menus. The only valid reason I can come up with to call Wayfinder uncached is when the output is user specific (member-only area, for example).
  3. Uncaching placeholders in chunks that are used as templates in snippets. Uncached placeholders are processed at the last possible time, and calling them uncached in a template will leave them in tact and they wont get replaced by the snippet, but instead by the core parser long after the snippet is done. (This behavior has seen some changes/bugs in the 2.1.x releases, so it could be that this is different in the latest release - I haven't actually checked in much detail recently.)

What are the errors you have made that you spotted in the above lists? Or do you have other caching tactics or questions? Share below!

Based on a comment from Marc Hinse, a follow-up to this post has been written discussing how nested caching works in MODX Revolution.


Chris Todhunter

Awesome article Mark! I've always set Wayfinder to be uncached as I would have thought that changes a client makes to their site structure wouldn't necessarily show up in the Wayfinder call otherwise - am I wrong about this?

Mark Hamstra

Thanks for the comment Chris, much appreciated :)

You definitely don't want to call Wayfinder uncached.

When your client makes a change to their site structure or updates a resource, the cache will be cleared so the next time the site is visited it will be regenerated and stored to cache.

The reason that is a common mistake and probably why you think it wouldn't update is that there was a bug in an older release where a custom cache set by Wayfinder wouldn't be cleared along with the resource cache. That has been fixed for quite some time though, leaving no reason to call it uncached.

Wayfinder is a real intensive snippet (it basically loops through every resource, checking if it has children and looping through them and so on and so on) so calling that uncached should really be avoided. One way to increase Wayfinder performance is to also add the &levels property, specifying how many levels deep you want the menu to go. If you set it to 2, it wont check if resources 2 levels deep have any (third level) children to loop through, so that saves time. :)

Tomasz Proc

Thanks for tip with Wayfinder, useful

Joakim Nyman

Excellent article! I've always set the Wayfinder as uncached as well and haven't given it a second thought later on. I just set Wayfinder to be cached on my website, and oh my, what a difference! I've been unsure how the cache works in MODx, but this article cleared that right up. Now that I've made some changes my website is lightning fast, so thanks for this article! Very helpful!

Mark Hamstra

Thanks for your comment, and great to hear your site is now so much faster :)

MadeMyDay

Thanks Mark for this guide ;-)

You asked for errors or I think new challenges in building performant cache constructions. What about:



while being chunk1/chunk2 a piece of code like:

Caching Guidelines for MODX Revolution-

and chunk1-1

something like



snippet1 (you expected it) something like

return $_GET['foo']


I think you get what I mean. How is the processing order? How can I be sure to only cache what I want? The Wayfinder example gets a lot of users back on the ground, but what about complex if/then template/chunk structures? A guide with "Look deep nested uncached -> every parent will be uncached" or similar formular would be helpful ;-)

Cheers from germany!
Marc

Mark Hamstra

Thanks for the comment Marc! Great question, and I've just rounded off an entire blog post to answer it.. It's sort of a follow up on this article now, and it will be published with the launch of my completely new site (hopefully in a week or two). I'll definitely let you know and post a link back here when it's web-accessible :)

Mark Hamstra

Now that the new site has finally launched, the follow up has also been publicized; see http://www.markhamstra.com/modx-blog/2011/11/nested-caching-in-modx-revolution/

Graham Gillen

Mark, excellent article. I'm in a situation where I might need someone to audit my site for caching best practices as I am having some performance issues with MODx 2.0.7.

Do you have some guidelines on performance tuning and how to figure out quickly if the issue is 1) code, including caching settings and best practices 2) bug in MODx caching..... assuming I've already rule out bandwidth and the web server as an issue.

Mark Hamstra

First update to 2.0.8: it was released to fix performance issues that may occur on 2.0.7, as well as an edge case scenario where the homepage turns blank (occured mostly on high traffic sites).

Next I suggest going all the way and updating to 2.1.5 and 2.2 (do take the 2.1 step). Depending on the amount of custom coding you did the 2.0->2.1 step may give some issues due to a large number of deprecated functions being removed. Also make sure that before you update MODX all of your extras are updated, and repeat that before every next step.

Now once we're on either 2.1.5 or 2.2 (it wont hurt waiting for 2.2.1 due to a number of bugs in 2.2-pl2) you can start ruling stuff out and making sure everything is right.

I tend to start by just going through all the templates line by line, checking out the called chunks as well. What snippets are being called, and do they follow the caching guidelines. Notorious mistakes include calling Wayfinder or getResources uncached, and they can have a huge performance impact.

The default caching (system) settings usually work just fine.

If there's nothing weird in the templates it can't hurt to check if resources are set to be cachable. That is the default, but I've seen a site setup where the developers decided to mark every resource as uncached during development.. which is just plain wrong. If you're using static elements or are using an include snippet to get chunks/templates from the filesystem, make sure those are cached as well, or it will request the specific file every time.

Final thing to check I can think of now is the MySQL version. If you're running 5.0.51, changes are you can boost performance 2/3x just by changing that to a new version.

Graham Gillen

Thanks for the advice Mark.

1) Planning to at a minimum to to 2.0.8 then on from there after I see what the impact is

2) For whatever reason, almost all getResources calls for all the templates are uncached. Only reason I can think of is the resources are sometimes thinks like "5 latest PR posts" to put on the home page. But it seems clearing the cache once after a PR post would work here just as well and then run getRources cached. Wayfinder only called once and it's cached

3) Running MySQL 5.1.55 so I think that should be OK.

Stupid question: when a resource has "clear cached" set by default and it is edited / saved, does this clear just the cached version of the resource and not the entire cache? I assume as much but not 100% sure.

Thanks again and here's hoping 2.0.8 does the trick and makes me feel good about going to 2.2. Agree with you I can't go to 2.2 in a single hop. My web designer tried that and broke the site. So have to take it step by step.

Thanks again!

Mark Hamstra

"when a resource has "clear cached" set by default and it is edited / saved, does this clear just the cached version of the resource and not the entire cache? "

It clears the entire cache, which also answers your question on the getResources call: the entire cache is cleared so they should be called cached.

Treigh

Dude,

This is a life-saver. They should really feature your article somewhere in the forums or even make a special page for it in the documentation. I'm so glad I read this. I was going insane with high page loads. Thx again

Graham Gillen

Mark,
FYI did the 2.0.8 upgrade including some minor code optimization regarding cache etc. Web site is screaming fast now.
Thanks!

Kwstas

Awesome guide! Thanx for sharing.
Could you write one for modx Evolution as well?

Comments are closed :(

While I would prefer to keep comments open indefinitely, the amount of spam that old articles attract is becoming a strain to keep up with and I can't always answer questions about ancient blog postings. If you have valuable feedback or important questions, please feel free to get in touch.