Selecting Chunks -- The Fast Way

Converting a slow conditional output modifier solution to a fast snippet

It can make your life easier if you use the same Template on many pages, but you might not want them all to look exactly the same. Say, for example that you want to vary the header depending on which parent the page is under. You could do something like this:


The performance of this code will be painfully slow because not only will each line have to be parsed and evaluated, the nested chunk tags will all execute and the all four chunks will be retrieved even though only one (or none) will be used.

You could improve the performance significantly by using Jason Coward's "Mosquitoes" technique:


This will help a lot since at most only one chunk will be processed, but it will still be fairly slow. Each of the conditional tags will have to be parsed and then evaluated even though most of them won't result in any output. What if we could use a single tag that didn't contain a conditional statement?

The trick is to put the logic in a very simple snippet that uses the PHP switch statement to make the choice. You should be able to to use this method even if you're not that familiar with writing PHP code. If you care at all about page-load times (and you should), learning a little PHP is essential.

The Code

Here's the tag:

[[SelectChunk? &parentId=`[[*parent]]`]]

Here's the snippet code:

/* SelectChunk snippet */

/* get the parent property from the $scriptProperties array */
$parent = $modx->getOption('parentId', $scriptProperties, null);

/* Set a default chunk to use */
$chunkName = 'MyDefaultChunk';

/* Set $chunkName based on the parent */
switch($parent) {
    case 1:
        $chunkName = 'headerChunk1';
    case 5:
        $chunkName = 'headerChunk2';
    case 7:
        $chunkName = 'headerChunk3';
    case 9:
    case 11:
        $chunkName = 'headerChunk4';

/* Return the appropriate chunk name*/
return $modx->getChunk($chunkName);

The first line of PHP code in our snippet calls $modx->getOption() to get the &parentId property we sent in the snippet tag. The 282 tag inside the SelectChunk tag will be replaced with the content of the parent field of the resource, which as you probably know, holds the Resource ID of the resource's parent (or 0 if the resource is at the root of the tree).

We discussed the $modx->getOption() method in the previous article. To review, it takes three arguments, separated by commas. In this case, the first one is the name of the property we're looking for (parentId). The second argument is the array to look in, which in the case of snippet properties is always the $scriptProperties variable. The third (optional) argument is the default value to use if the property is not sent in the tag (in this case, null, because we want to make sure it's not a number). As long as you include the &parentId property in the tag, the third argument will never be used.

To sum up that first line: after it executes the $parent variable will be set to the value sent in the &parent property. Since we're using a tag to send the parent field. The variable will be set to the ID of the resource's parent.

The switch Statement

The PHP switch statement is very simple. The first line tells PHP what value to use to select which options to execute (in parentheses). In this case, we're "switching" on the value of the $parent variable. That's followed by an opening curly brace ({), then the options, followed by a closing curly brace (}).

Each option starts with the word case followed by a value, then a colon. Indented below that is one or more lines of PHP code to execute followed by the break; statement, which tells PHP "break out of the switch statement", in other words, to jump to the line after the closing curly brace.

When PHP encounters the switch statement, it checks the value in parentheses at the beginning, then looks for a case that matches it. If it finds one, it executes the code for that option, if not it does nothing and jumps past the end of the switch statement. It does this with blinding speed, using a jump table to jump to the appropriate case.

Notice the final two cases in our switch statement. There's no break; statement between them. The code below them will execute if the parent is either 9 or 11. You can have as many cases as you like here and you could have similar sets of multiple cases anywhere in the switch statement if you want to execute the same code for multiple cases.

Remember, though, that a given section of PHP code needs a break; statement at the end. If it's not there, the execution will "fall through" to the next case and its code will execute too. Leaving out the break; statement at the end of a case is the most common mistake made by people learning to use a switch statement. Multiple cases execute and they have trouble figuring out why.

We're not using it here because we set our own default chunk name near the top of the snippet, but you can have a default case in a switch statement. Its code will execute of none of the other cases provides a match. That looks like this:

        /* some code here */

By convention, it comes at the end of the switch statement, but it doesn't have to. In fact, you can do this if you want to:

    case 23:
    case 34:
        /* some code here */

The first two cases are unnecessary because the default case would execute anyway, but sometimes you want to make it clear what happens in those cases. The speed penalty is negligible.

In our example snippet, the code in each case of the switch statement simply sets the value of the $chunkName variable to the name of the appropriate chunk.

At the end of our code, we simply return the content of the selected chunk with return $modx->getChunk($chunkName). The contents of that chunk will replace the SelectChunk snippet tag.

Other Uses

With fairly minor modifications, the code above could be used to select chunks based on almost any characteristic of the current resource. The value at the top can be a string, so for example, you could send the pagetitle or the value of a TV in the snippet tag and adjust the code accordingly. You can also return a string directly rather than getting a chunk. Here's an example:

[[!SelectChunk? &tvValue=`[[*Tv1]]` ]]

$tvValue = $modx->getOption('tvValue', $scriptProperties, 'someValue');
$output = 'someValue';
switch($tvValue) {
   case 'red':
        $output = "The color is red"
   case 'blue':
        $output = "The color is blue"
   case 'green':
        $output = "The color is green"
return $output;

Because we're evaluating a string here, rather than a number, the value in each case has to be in quotes.

The only restriction for using a switch statement is that there has to be a single value in the parentheses at the top of the switch statement and the case has to match it. You can't do any of these:

    case $parent > 5:
    case $parent != 6:
    case empty($parent):
In those cases, you would have to construct an elseif tree like this:
if ($parent > 5) {
     /* some code */
} elseif ($parent != 6) {
    /* some code */
} elseif (empty($parent)) {
    /* some code */
} else {
    /* default case here */

Using the elseif method would still be *way* faster than creating the same options with conditional output modifiers.

Comments (6)

  1. Stephen HuttonSep 03, 2014 at 06:25 PM

    Hi Bob
    I really appreciate your fascinating and very helpful articles regarding MODx.
    I did notice one little error (I think) in your first code example.
    Is it missing a in front of $headerChunk4 in line 4?
    Keep these articles coming - this one just solved a current problem I was having.
    Thanks Stephen

  2. JM AddingtonSep 04, 2014 at 07:25 AM

    With MODX's caching why would we worry about it running slowly? It wouldn't be a regular occurrence, right?

  3. Bob RaySep 22, 2014 at 09:58 PM

    Thanks. Fixed!

  4. Bob RaySep 22, 2014 at 10:00 PM

    My Philosophy is that speed is always good, especially when the cache has been cleared. Also, many snippets have to run uncached so the faster they run, the better. ;)

  5. Hugo PeekOct 05, 2015 at 01:08 AM

    Hi Bob,

    Thank you for the time and patience you put into writing these amazing guides. I'm always struggling to understand PHP, but your step by step explanations and insightful background info make things so much easier, rewarding and fun.

    I was abusing output modifiers extensively up till now, so this method will come in very handy. For a bunch of chunks that used the new :contains modifier, I altered the snippet a bit to check if the input contains a certain string:

    switch($input) {
    case stripos($input,'link') !== false:
    $output = "link";
    case stripos($input,'card') !== false:
    $output = "card";
    case stripos($input,'segment') !== false:
    $output = "segment";

  6. Bob RayOct 09, 2015 at 11:40 PM

    Thanks for the kind words and the code. :)

Please login to comment.