MODX Web Templates - One Way To Do It

Jun 13, 2012

MODX CMS Templates are so flexible that there's literally countless ways to set them up. HTML Chunks can help you organize your markup into "objects" (object-oriented cms templating?) With the ability to add placeholders in Chunks, you can also re-use them across different templates and pass different values to them. But who needs different templates when you have MODX Output Filters? These powerful conditional filters are built right into the MODX Revolution core, for quick development. You don't even need to download a Snippet!

Below I'll give you a demonstration of quick-and-easy MODX Templating.

Resources

Official Docs

Template Code

[[$startDoc? &classname=`doc[[*id]]`]]

[[$meta]]

[[$styles]]

[[$scripts]]

[[[[*id:is=`[[++site_start]]`:then=`$homeScripts`:else=`-`]]]]

[[$header]]

[[*content]]

[[[[*id:is=`[[++site_start]]`:then=`$homeGallery`:else=`-`]]]]

[[$footer? &id=`doc[[*id]]` &endScripts=`[[$moreScripts]]`]]  

Break it down:

  • [[$startDoc?... » This chunk just contains your doctype declaration and html element. The funky part is the element property "classname". In the chunk I have this: <!DOCTYPE html><html class="[[+classname]]"> ... MODX first looks at the nested tag and returns the document ID (e.g. "1"), then inserts the resulting property value (e.g. "doc1") into the class attribute of the html element inside the chunk. Voila: an easy override for your global CSS styles: Each page will have a different classname for it's html element.
  • [[$meta]][[$styles]][[$scripts]] » Include those bits of html into your template.
  • [[[[*id:is=``:then=``]]]] » This is an output filter. It's a conditional: "If the document ID [[*id]] is the same as the value in the &is property, then return the value of the &then property. If the return value is a Chunk token and name, like $homeScripts and there are outer MODX tags [[ and ]], then the result will be a fully-formed MODX tag that will display the chunk called "homeScripts". This is a huge time-saver for small sites. You can pretty much get away with a single template, but for the homepage (which is often different) you can call in some different elements.
  • The rest is more of the same. The footer chunk has a property &endScripts that inserts a Chunk at the end of the page that is specific to this template. So inside the chunk we have: [[+endScripts]] The closing body html tag is inside the footer Chunk, so this way you can pass in html to render, saving time and duplication versus creating a new footer Chunk, for example.

The best part: you can make anything an element property!!! You're not going to find &endScripts in the MODX documentation anywhere, cause that property isn't set in a snippet or in the core - I made it up. You can too :) Make up the name of a property, and call it as a placeholder inside the Chunk. IT'S THAT EASY! Name one other CMS that flexible - go on... ;)

Again, this is only one way to do it. There's lots of different "right" ways; only a few "wrong" ways. I've seen MODX installs where there's 40 different templates, and the difference between them is just one chunk with a different name. THAT, in my opinion, is hard to maintain. Why? Because if you want to add or delete one of those common elements, you have to do it in all 40 templates! Waste. Of. Time.

You have better things to do, like play with your kids. Let MODX do the work. It does it really, really well.

*IMPORTANT UPDATE [2012/06]: Jason Coward of the MODX Core Team just enlightened me on a very important issue regarding using conditionals in MODX Templates. Well, TBH he doesn't think we should use conditionals at all in content, and I'm sure he's right, but they're just so darn useful I can't give them up. Call it my "dev crack". BUT there's a really bad flaw in the way I've been forming my Output Filter conditionals.

[[*id:is=`[[++site_start]]`:then=`[[$homeScripts]]`]]

should really be:

[[$[[*id:is=`[[++site_start]]`:then=`homeScripts`]]]]

or, even better:

[[[[*id:is=`[[++site_start]]`:then=`$homeScripts`:else=`-`]]]]

NOTE: It does not matter if you're using Output Filters or Snippets like "If" to form your conditionals, the following still applies!

In the first example above, the MODX parser comes across the nested [[$homeScripts]] Chunk tag and processes that chunk, regardless of whether the condition is met! This can cause a lot of extra, unnecessary processing. If the Chunk contains plain HTML it's not that bad, but if it contains a Snippet call, like [[$homeGallery]] might, then it's really sub-optimal. It helps a bit that the Resource output is cached, but with a minor adjustment in the way we form the tag, we can avoid all that.

In the 2nd, correct example, we call a chunk, and the name of the chunk is returned by the conditional, into the outer tag. If no name is set, the chunk call is empty and no processing takes place. BRILLIANT! I'm now forever changing the way I write these Chunk calls. Thanks Jason :)

*UPDATE [2018/12] Actually the call for a non-existent Chunk does cause some processing. The parser checks the Element cache and if it doesn't find the element there, it does a query for the Chunk. An empty Chunk name may not escape this processing. Not a huge impact, but the 3rd example is best, where if the condition isn't met, a MODX comment token is returned into the outer tag, forming [[-]] which will be skipped by the parser (it returns an empty string before doing anything else whatsoever). This is the syntax I've been using the past several years. It's performant and reliable.

*Another Update [2012/09]: You can find out more about the use of conditionals in MODX Templates on the Official blog here: https://modx.com/blog/2012/09/14/tags-as-the-result-or-how-conditionals-are-like-mosquitoes/