Multiple page layouts with a single template: exploring the power of template variables

…realize that a guy my size might take a while just to
try and figure out what all this is for

-Barenaked Ladies, “Pinch Me

Pinch me, indeed.

Although I had dabbled with MODx Template Variables a little bit, I must confess that until recently I didn’t really have any grasp whatsoever of their real usefulness. Chunks and snippets, those I understood.  But for whatever reason I just couldn’t grasp why a TV would ever be more useful than a chunk or snippet.  In my defense, the example provided in the official documentation doesn’t provide much insight, since the same functionality could be done with a chunk.

But then last week a light bulb finally went on for me.  It began, as do many of my mental breakthroughs, out of stubbornness.   I started transferring our new site design into MODx, setting up an initial template, and breaking it up into logical, reusable bits (chunks).  (All of which, incidentally, is ridiculously easy to do).   For the sake of this discussion, I’ll focus on a few different basic content layouts our site is going to need:


  1. content layout with 75% content area, 25% right column

  2. content layout with 25% left column, 50% content area, 25% right column

  3. content layout with full-width content

My first instinct was to create a template for each of these layout variations.  That would have worked, would have been okay.  But it somehow struck me as wrong; most of the code stays exactly the same in each variation; only a small bit of div structure changes in each layout.  Why not… use a single template, with a – wait for it – template variable to determine which layout div structure is used?

Now that I finally had the concept of a problem that required a template variable, I was sufficiently motivated to figure out how to go about solving it.   I did so simply by relying on the helpfulness of the MODx user community.  A few posts on the MODx forum, a few Twitter questions, and before long I had exactly what I needed.  It might not seem like a huge deal; in fact In some ways, compared to some of the brilliant MODx tutorials available elsewhere on the web, this seems like the type of thing that is hardly worthy of documenting.  But the way I look at it, if I can help even one other person have the “aha” moment that I had regarding the power of template variables, then I will have done a good thing.  Therefore, what little knowledge I have, I now pass on to you.

Step one:  create your template

Creating a basic MODx template is literally as simple as pasting your skeletal HTML source code into a form field, and then putting in placeholders for the document title and content.  Breaking up some of the HTML into chunks based on functional purpose is an extra step, but actually makes the template even simpler to work with.  Here’s what mine more-or-less looked like, before creating the TV:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>[[*pagetitle]]</title>
[[$css_block]]
[[$script_block]]
</head>
<body>
<div id="container" class="container_16">
[[$header]]
[[$contentDisplay]]
[[$footer]]
</div>
</body>
</html>

Notice how I created chunks for the css, javascript, header, and footer.  I find this to be very readable and  intuitive.  Also, by breaking things up into logical bits like this, you rarely ever have to edit the template itself.  If you need to add a new css file, you edit your css chunk.  Need to change your banner structure? Go straight to the header chunk.  A system like this can help keep multiple developers from stepping on each others’ toes, but can also help a lone web developer work more efficiently.

[[$contentDisplay]] here represents one of the content layouts depicted above.  (This is what we’ll soon be replacing with a Template Variable!)

Layout #1, for example, has a div structure that looks like this:

<div id="content" class="grid_12">
[[$fullcontent]]
</div>
 <!-- right column -->
<div id="rightCol" class="grid_4">
[[rightColumnWidgets]]
</div>

The [[$fullcontent]] chunk just serves as a wrapper for the content itself and an <h1> containing the [[*longtitle]] value:

<h1>[[*longtitle]]</h1>
[[*content]]

 

I thought it important/useful to create this wrapper since the H1 and content always go together – it is a “rule” of our site design, if you will, and it is always helpful to capture logical groupings like that.  Furthermore, since there are going to be other chunks (for the other layouts) that also pull in our content, creating this wrapper chunk makes things easier to maintain.  If we later decide that we want to include another bit of information, such as page author, or publication date, we can simply edit the [[$fullcontent]] chunk and know that the changes will be made in every content layout.

But I digress.

Step Two: create your “content layout” chunks

I’ve already shown you one of the content layouts. You might have noticed we are using the 960 Grid System CSS framework to achieve the various layouts. It just makes it ridiculously easy, and we all like easy, right?  Anyway, here are the other two layouts.

  • (25% left column, 50% center (content) column, 25% right column)
    <div id="content" class="grid_12">
    <div class="grid_4">
    <!-- left column widgets go here -->
    </div>
    <div id="main" class="grid_8 omega">
    [[$fullcontent]]
    </div>
    <div>
    <div class="grid_4 supplemental">
    <!-- right column widgets go here -->
    </div>
    
  • (single content column, 100% width)
    <div id="content" class="grid_16">
    [[$fullcontent]]
    </div>

Now we’ll save these three as chunks. A few important steps here:

  1. Create a new category, called something like ‘contentLayouts’, and assign these chunks  to that category.  When we create the Template Variable, what it will be doing is letting you choose a chunk from amongst all the chunks of a given category.
  2. Give them short names, using alphanumeric characters and underscores.  For these chunks I used 75_25, 25_50_25, and full_width.   (**I’m not entirely clear what the MODx rules/best practices are here, I just know that for whatever reason it makes me feel really uncomfortable to do otherwise)
  3. Use the Description field to give them meaningful descriptions.  When a use is editing a page, they will choose a page layout based on the descriptions.

Here’s what this looks like in my Elements tab:

image of MODx directory tree display of content layout chunks

Step Three: create a snippet to select all “contentLayout” chunks

(From this point on, I’m largely following the formula described in the “Create TV-Based Chunks” page on the MODx Wiki site.  I’ve made a few modifications, so I’ll document exactly what I’ve done to make this work, but that page is an excellent background reference that will greatly help you understand the overall logic of what is happening here.)

As I mentioned earlier, the Template Variable is going to allow the page editor to choose a content layout from amongst all of the chunks in the “contentLayouts” category.  In order to generate that list, we need a snippet, which we’ll name ‘getChunks’.

<?php
/* Get the chunk objects */
$c = $modx->newQuery('modChunk');
$c->leftJoin('modCategory','Category');
$c->where(array('Category.category' => $category));

$chunkArray = $modx->getCollection('modChunk',$c);

$chunkNames=array();

/* Put the chunk names into the array */
foreach($chunkArray as $chunk) {
 $chunkNames[] = $chunk->get('description') .
                 '==' . $chunk->get('name');
}
/* Format the chunknames as a delimited string for the TV */
$l_chunks = implode("||",$chunkNames);

return $l_chunks;
?>

I’m using one of the Revolution versions (with a small modification to the output). Consult the Wiki page for the Evolution version.

What’s happening in this snippet is pretty straight-forward.  First, all of the chunks in a given category (specified in the snippet call) are returned in an array.  Then the array is used to generate a delimited string, which will (with my example chunks) look like this:


25% left column, 50% middle content column, 25% right column==25_50_25||75% left content column, 25% right column==75_25||content spans entire 100% width==full_width

In other words, for each chunk I’m sending

description==name

And using ‘||’ as the delimiter between each chunk.  This delimited string will in turn be used by the Template Variable to generate a dropdown list in MODx Manager, which will look roughly like this:

MODx template variable screen capture

…and will be constructed of HTML like this:

<select>
 <option value="75_25">Content layout w/ content on left (75%), right column (25%)</option>
 <option value="25_50_25">25% left column goes w/ content, 50% middle column content main, 25% right column</option>
 <option value="full_width">Content spans the entire width of the layout</option>
</select>
 

See how that all works?  No need to thank me for the backstage pass;  it’s complimentary.

Moving on …

Step Four: Create the Template Variable

We’re almost there now.

  • Create a new template variable; I’m calling mine [[*content_layout]].
  • Give it a caption to help your content editors grasp it’s meaning; i.e.  “Choose a layout for your content.”
  • Choose “Listbox (Single-Select) as your Input Type.

The “Input Option Values” field is the one that wants a delimited string of input options; this, then, is where we will call our snippet.

To call a snippet as the data source for a TV, we need to use the @EVAL binding.  We’ll be calling our ‘getChunks’ snippet, and asking it to return all chunks where category=’contentLayouts’.  Here’s what that looks like in an @EVAL binding statement:

@EVAL return $modx->runSnippet(‘getChunks’,array(‘category’=>’contentLayouts’));


 

Just a couple more fields to fill in and the TV will be complete.

  • Default Value:  Enter here the name (not the description) of the content layout that you want to be your default option.  This is important – since we are relying on the content-layout-chunks to deliver the content, if we don’t select one, we simply won’t have any content on the page.
  • Output Type:  String.   We will simply be outputting the name of the selected chunk into the body of our template. This will make sense after the next/final step.
  • String Format: None.

Before saving the Template Variable, remember to click over to the Template Access tab and allow the appropriate template(s) access to this template variable.  Not much good otherwise…

Step Five: Modify the Template to Receive the TV Output

Now we go back to the original Template, and modify it to give a landing-place to the output from the Template Variable.  If you named your TV ‘content_layout’, you access it with [[*content_layout]].

But remember – all the TV gives us for output is the name of the chunk that was selected.  What we really want displayed is the chunk itself, in all it’s chunky glory.  To do that, we need to nest the TV tag inside of a chunk tag:

[[$[[*content_layout]]]]

Just to be clear, here’s how this will work.  If the user selected the chunk ’75_25′, the line above will be parsed to:

[[$75_25]]

… which will then be further parsed to:

<div id="content" class="grid_12">
[[$fullcontent]]
</div>
 <!-- right column -->
<div id="rightCol" class="grid_16">
[[rightColumnWidgets]]
</div>

…which will then be parsed yet again to:  … oh, you get the idea.

The final template, then, will look like this:


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>[[*pagetitle]]</title>
[[$css_block]]
[[$script_block]]
</head>
<body>
<div id="container"class="container_16">
[[$header]]
[[$[[*content_layout]]]]
[[$footer]]
</div>
</body>
</html>

 

And we’re done!

We now have a rather nifty, versatile MODx template that lets the resource editor drop the [[*content]] into any number of different inner-div structures, allowing for any number of different content layouts.

Pinch me.

 
Advertisements

26 responses to this post.

  1. Posted by eloisep on February 22, 2010 at 10:53 am

    Great tut, thanks! I choose MODx, too, but waiting for the day am not boggled by the possibilities!

    Reply

  2. Nice tutorial! Thank you for sharing. Keep them coming, we need more ruts!

    Reply

    • Thanks Mary. You are a source of inspiration. My perspective right now is, if I can’t find an example of what I’m trying to do anywhere else on the web, I’ll figure it out and document it, so its there for the next person. It feels good to finally be giving back to the open source community even in this little way.

      Reply

  3. This is great!
    I like your site – Revo sites are quite rare at the time – keep it up!

    Reply

  4. This is full of useful ideas, even though I’m still on Evolution myself.

    The MODx world really needs more stuff like this – without the great tutorials from yourself, Mary and others, I think many would struggle and probably give up on the thing.

    Reply

    • Thanks Alistair, for the kind words. I agree that what the MODx world needs is more tutorials, and at all skill levels; entry/beginner, intermediate, and advanced. I’ll try and do my part, and also link to others who are posting tutorials.

      Reply

  5. Posted by Greg on February 26, 2010 at 3:19 pm

    Another great post.
    More possibilities to expand my brain. As an old bloke relatively new to the world of programming, scripting languages and modx, these kind of articles provide quantum leaps in my understanding and use of modx, PHP et al.
    Thanks again.

    Reply

  6. Great Post ! I like the way you dynamically populate the page layout TV by using chunk category.
    I’ve yet to delve into MODx revolution.
    In MODx Evolution i would use 3col layout=={{3collayoutchunk}}||2col_layout=={{2collayoutchunk}} as values for the dropdown for the Template Variable. (It’s not dynamically populated then, true) In the template [*custom_layout*] should evaluate so that the chunk get’s rendered there.

    Reply

  7. Great post James! I am just getting my feet on the MODx bandwagon as well. Tutorials like this really help me understand what can be possible with the framework. Keep up the good work, looking forward to more!!

    Reply

  8. […] single, swiss-army-knife template.  That’s where the idea to use  a Template Variable to select a content layout came […]

    Reply

  9. This was exactly what I was looking for! I agree that the docuemtnation does not show a clear advantage to chunks and snippets. This is my first project using Modx and it has been a learning process. Actually, I find that I expect it to be more difficult that it really is. Thanks and I’ll be back to glean some more insight.

    Reply

  10. Posted by Jivers on June 29, 2010 at 9:42 am

    Thanks for this. A pre-Revo entry on the MODx wiki describes something similar (http://wiki.modxcms.com/index.php/Create_TV-Based_Chunks). The process described there is different than your write-up in that two snippets are required – the getChunks snippet, as well as a chunk list parser. So, my question is, will the process you’ve described work in Evo (and sorry if I’m missing the obvious)?

    Reply

  11. Hey this is just what I’m looking for too; I have been puzzling over this and figured there must be a way in Modx to make the whole template world easier. Going to try this out tonight. Just one question.
    I would use this on a large site and so prefer the idea of using the docmanager to change the templates used for each group of docs.

    Therefore by using your way instead, can you do this to batches using tv method?

    Thanks and well done!

    Reply

  12. Posted by Hurby on August 10, 2010 at 8:49 am

    Yes finally i understand This is it !!!

    Perfect tutorial

    Reply

  13. Posted by Hanna on August 19, 2010 at 1:24 pm

    Your mission is done. Now I also got it! Thanks, Keep up the god work.

    Reply

  14. Posted by Jane on November 12, 2010 at 9:51 pm

    This is a great concept and the steps are concise enough, but I can’t get it to work…anyone else walked through this? I’m still learning so there is a possibility of missing something. Have stepped through the tut several times with no joy…
    Using Revolution 2.0.4-pl2.

    Reply

    • Jane,

      Sorry for not seeing this sooner. I’m blogging at a different location now (www.cmslesstraveled.com) and haven’t been very good at catching the comments back at the “old” blog. Anyway, I think I’ll probably revisit this approach in a new post at some time in the near future. Meanwhile if you have any specific questions feel free to email me at james at cmslesstraveled dot com.

      Reply

  15. Posted by Basel Shishani on February 17, 2011 at 3:47 am

    James, thanks for the blog and the many useful articles.

    I have one comment about your technique – do we really need to programtically enumerate the sub-template chunks?! It makes things look more complex than they are. Templates are limited in number and not at all dynamic in nature – they don’t keep changing too often. So if a new chunk is added, it can be manually added to the TV, no drama.

    Regards.

    Reply

  16. I just wanted to leave a comment as there doesn’t seem to be a link to your updated blog post regarding this (there is on the updated post but not this one) about using multiple templates to do exactly what you are trying to do here 🙂 I feel the pain I have been there done that and also now understand the logic of multiple templates (the so called on template to rule them all concept) As I used to quote and say the point of a template is that its reused in multiple purposes but then again chunks are mini templates in themselves and I get that now.

    Thanks for the great articles 🙂 inspiration for sure.

    Anyone wondering the link to the updated article is here

    https://ichosemodx.wordpress.com/2010/04/12/thoughts-on-developing-a-template-strategy-and-my-new-template-click-through-utility/

    Reply

  17. Posted by renne on February 16, 2012 at 8:16 am

    Nice tutorial, thanks for this.

    Reply

  18. Posted by Brian on July 18, 2012 at 1:46 pm

    Very good tutorial – respect. You don´t find this level of TV tutos on the modx pages.
    I struggled a long time with TV´s but this tuto immediately made me understand them.

    Reply

  19. Posted by Joshua on August 19, 2012 at 2:53 pm

    Something is causing any text that extends past the right side of the center column to curl underneath and remain hidden. More than half the tutorial’s text is hidden and unreadable for me. And I’m running the latest stable version of FF, IE and Chrome. Tried them all. Same thing. If I use FireBug to adjust the “.entry” css class (line 14 supposedly) and change the “overflow” property from “hidden” to “visible” then the text of-course appears. Just thought I would let you know. If the tut wasn’t as good as you made it then I would’ve just left. But you spent some time sharing so I figured I could at least point this out. Thanks for sharing James. Much appreciated.

    Reply

  20. I’m gone to say to my little brother, that he should also pay a visit this weblog on regular basis to obtain updated from hottest reports.

    Reply

  21. hi!,I really like your writing very so much! proportion we communicate more approximately your article on AOL?
    I need a specialist in this area to resolve my problem.
    Maybe that is you! Having a look forward to look you.

    Reply

  22. thank you for sharing, I found very useful info here, I was delighted to find this web site
    bilimselevlilik

    Reply

  23. Posted by talkinggoat on October 19, 2015 at 9:01 am

    Thanks for the tutorial, but about half way down, the text stops wrapping and flows off the right side of the column. Could not read it all.

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: