Don't Be a Nester

Speed up your site by reducing the nesting levels of MODX tags, and avoiding conditional output modifiers.

By Bob Ray  |  September 20, 2022  |  7 min read
Don't Be a Nester

When I troubleshoot people’s sites, one thing I often notice is a tendency toward unnecessary nesting of MODX tags. On one site I looked at a while back, there was a Chunk tag in the Template, inside the Chunk tag was another Chunk tag (and nothing else), and in that Chunk, was a single Snippet tag. I couldn’t see any reason at all not to put the Snippet tag itself in the Template, especially since it was the only Template on the site.

Technically, tags processed inside of other tags are called “nested tags”.

If, for example, you’re going to use a common header in multiple Templates, it makes sense to put the code of that header in a Chunk (though you should still ask yourself if you really need multiple Templates). On the other hand, breaking down the header section further may not make any real sense. I’ve seen layouts like this, for example. In the Template, there’s a Chunk tag for a Chunk called “Header”. In the Header Chunk, you find something like this:

[[$Logo]]
[[$Banner]]
[[$Separator]]
[[$TopMenu]]
[[$SecondSeparator]]

In one case I looked at, the first two Chunks each contained just an image tag. The separator Chunks were very simple HTML, and the TopMenu Chunk contained nothing but a single Wayfinder tag.

Think about the process that occurs for the header on every page. MODX has to load the Template, then find and load the Header Chunk, then find, load, and parse all the individual Chunks, then find and run the Wayfinder Snippet. This is mitigated somewhat by having things cached, but every time you make a change to any of the parts, or the site cache is cleared the next visitor is going to have to wait.

The six tags above (including the Header Chunk tag), could be replaced by a few lines of HTML code, eliminating the need for MODX to retrieve and parse six separate Chunks.

Worse yet, when it’s a year later, and you need to make some changes, you have to load the Template to find out the name of the Header Chunk, then load the Header Chunk to find out the names of the Chunks it contains, then figure out which one holds the part you want to change (assuming that it has a sensible name), then load and edit that Chunk perhaps only to discover that what you thought was in the Banner is really part of the Logo, or should be moved there. How much simpler to have all that code in the Header Chunk instead of spread all over the map.

The example above may seem like an exaggeration, but I’ve actually seen sites where chunks referenced in the Header chunk contained several chunks of their own.

Even if you could somehow justify the creation of all these separate Chunks, you’d still be dealing with the fact that it takes six times as long to load six Chunks as it does to load one.

Here’s an example of that nested code moved to the Template:

<img class="site_logo" src="assets/images/logo.png" alt = 'Logo'>
<img class="site_banner" src="assets/images/banner.png" alt='Banner'>
<div class="separator_1"></div>
<div class="top_menu"></div>
<div class="separator_2"></div>
<div class="top_menu">
  [[Wayfinder ... ]]
</div>

Now MODX has no Chunks to retrieve and parse, and you’ve moved control of much of the display to the CSS file where it belongs.

The moral is, don’t move things to a lower nesting level unless you have a very good reason for doing so. For a page footer or copyright notice used on multiple pages, a separate Chunk makes perfect sense, but don’t move things down a level just because you can.

Time Is of the Essence

Take a look at this NY Times article on bounce rates and page-load times.

If your page loads are too slow, users won’t stick around long enough to find out what a great site you have. And when I say too slow, the effects start at around 250 milliseconds. That’s a quarter of a second. It’s not unreasonable to suppose that loading five or six unnecessary Chunks (let alone ten or twenty) would take longer than that on some servers.

Conditional Output Modifiers

Don’t get me started on nested conditional output modifiers. These were created for people who were not comfortable using PHP code. The output modifiers let users perform transformations for tags on the page, such as changing case, stripping HTML tags, or converting text into HTML entities.

The conditional output modifiers mimic the logic of PHP code with concepts like if, then and else. They are often combined with tests for things like equality or inequality, and the PHP operators, <, >, >=, <=, +, -, /, and *.

Conditional output modifiers are notoriously slow, however. The MODX parser is very fast and efficient, but if you look at a complex conditional output modifier, it takes you a while to figure out what it’s doing. MODX has the same problem.

Consider this conditional output modifier:

Date: [[*id:is=`115`:or:is=`225`:then=`[[*editedon:strtotime:strftime=`%d %B %Y`]]`:else=`[[*editedon:strtotime:strftime[`%Y-%m-%d`]]`]]

MODX has to not only parse this string starting at the inside and working out, in the process, it has to call the filter() method of the modOutputFilter class nine times! It also has to test several conditions to see which part of the modifier should be executed. It also has to call strtotime(), and strftime() twice each, because it won’t know which of the two values it will display until later in the parsing process.

The worst part of it is that during the parsing process, MODX will calculate the value of every tag, whether that value us ultimately going to be used or not.

Here’s a Snippet that will do the same job:

The tag:

[[!ShowEditedOnDate]]

The Snippet:

/* ShowEditedOnDate snippet */
$date = $modx->resource->get('editedon');
$id = $modx->resource->get('id');
if ($id == 115 || $id == 225) {
    $dateFormat = "$d %B %Y"
} else {
    $dateFormat = "%Y-%m-%d";
}
return strftime($dateFormat, strtotime($date));

The if statement take a few milliseconds to execute. The two calls to get the id and editedon value occur in both the Snippet and the output modifier, but strtoTime() and strftime() are each called once instead of twice. The nine calls to the output filter’s filter() method are gone, and there’s no time at all spent parsing the output modifier or calculating values that will never be used.

Unless your server is blindingly fast, you should either learn to write simple Snippets to replace your conditional output modifiers or hire someone to replace them for you. Generally, an experienced PHP coder can replace conditional output modifiers very quickly. The code above took me a couple of minutes to write. You only have to have them replaced once and your site will be considerably snappier from then on.

If you must use conditional output modifiers, check out this epic "mosquitoes" blog post from Jason Coward. Here’s slightly modified example from Jason’s blog, showing the problems of conditional output modifiers: ``` {{*content:default=`{{$defaultContent}}`}} ``` The material in the defaultContent Chunk will be shown if the `content` field of the current Resource is empty (which will almost never happen). Imagine that the defaultContent Chunk contains some other Chunk tags and a Snippet tag or two. All of those will be processed on every page load, even though they will almost never be used because the parser processes that inner tag before it evaluates the condition on the left. Check out Jason’s post to see how to avoid that and still use a conditional output modifier. Coincidentally, this blog post of mine was written just a few days ahead of the ten-year anniversary of Jason’s now-legendary post in September 2012.

Parsing Problems

There’s one more reason for avoiding nested MODX tags. Tags can be called cached ([[tagname]]) or uncached [[!tagname]]. When some tags in your nested sequence are called cached and others are not, problems can crop up.

An uncached tag may not be processed at the time another tag its inside of needs its value. The MODX parser is extremely capable, but at a certain nesting depth, MODX can get confused about the order of processing for the tags. The result can be empty, or contain a value from a previous visit to the page.

For example, the processing of an uncached tag (with the exclamation point) is often delayed until later in the process parsing process. If the tag’s value is used by a surrounding tag, that tag may end up trying to process the inner tag itself instead of its value (which hasn’t been calculated yet). This will usually cause maddening errors that are very difficult to diagnose.

It’s also tedious and frustrating to try all the permutations of cached and uncached tags in a nested sequence while trying to get the output you want.

I long ago lost count of the number of times an issue in the MODX Forums was solved by either reducing the depth of the nesting or replacing all, or part, of the HTML code with a call to a custom Snippet.

Whenever you start nesting MODX tags, think hard about whether the nesting is actually necessary.


Bob Ray is the author of the MODX: The Official Guide and dozens of MODX Extras including QuickEmail, NewsPublisher, SiteCheck, GoRevo, Personalize, EZfaq, MyComponent and many more. His website is Bob’s Guides. It not only includes a plethora of MODX tutorials but there are some really great bread recipes there, as well.