Exploring MODx From the Inside: How MODx Templates Work

How MODx Templates Work

A MODx template can be created from any static HTML page. You can view the source of any web page, copy the HTML, and use it for your template. You can create the template using any HTML generator, even Word if you really feel you must. All you need to do is copy the generated HTML code, open a new template editor in the Manager, and paste the code in the field.

Just like a static HTML page, the template will need a doctype, a head and a body. Ideally, the template should only contain the HTML structure, all text and dynamic content is represented by the appropriate MODx templating tags.

The template editing field is just a plain textarea. There are a few options if you don't feel comfortable working with HTML in plain text like that. One, as was mentioned before, is to use an HTML generator such as Dreamweaver, Rapidweaver, Bluefish or even Word. The disadvantage of this is that you need to copy/paste your changes into the form in the MODx Manager, which can slow your development as well as break your concentration.

Another method is to use a snippet to include an external .html or other text file. This will be covered in more detail in the article on snippets. In this case, you can simply edit the text file as you would any other static HTML document.

Yet a third option is to use Firefox and install the It's All Text! extension. Right-click on the textarea and select your editor; this extension also adds a little "edit" button to a textarea field when you put the mouse pointer in it. It will open your preferred text editor with the content of the textarea. When you save your work in the text editor, it is automatically pasted into the textarea. This way you get the advantage of line numbers, syntax highlighting, and any other features you use a text editor for in the first place, without any effect whatsoever on how MODx stores and uses the template.

A MODx Template Framework

Let's look at a basic three-column source-ordered template the MODx way. As you can see, this is almost entirely a plain old HTML document. Some of the values are generated dynamically by using MODx tags. All content is inserted with tags. This is what makes it a template; this one bit of HTML code will serve for all the pages on your site.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>[(site_name)] » [*pagetitle*]</title>
<meta http-equiv="content-type" content="text/html; charset=[(modx_charset)]" />
<meta name="keywords" content="" />
<base href="[(site_url)]"></base>
<link rel="stylesheet" type="text/css" href="assets/templates/MyTemplate/site.css" /> 
<link rel="shortcut icon" href="./assets/images/favicon.ico" />
<!--[if lt IE 7]>
    <style type="text/css">
        body { behavior: url(assets/js/csshover.htc) }
        img { behavior: url(assets/js/pngbehavior.htc) }
    </style>
<![endif]-->
</head>
<body>

<div id="masthead">
<h1>[(site_name)]</h1>
<h2>[*longtitle*]</h2>
<div class="clearing"></div>
<!-- end masthead --></div>

<div id="wrapper">
    <div id="main">
        [*content*]
    <!-- end main --></div>
    <div id="side1">
        [*LeftSide*]
    <!-- end side1 --></div>
    <div id="side2">
        [*RightSide*]
    <!-- end side2 --></div>
    <div class="clearing"></div>
<!-- end wrapper --></div>

<div id="footer">
    {{Footer}}
<!-- end footer --></div>

</body>
</html>

To create a new template, log in to your site's Manager. From the main menu, select Resources -> Manage Resources. Usually the right frame will open with the first tab, Templates, already opened. Click the New Template link, and a form with a few text fields and a large textarea field will be displayed. Give the template a name, a brief description, and if you like, select a category or create a new category for it. The category is only for organizing the lists of resources displayed, but it does make things easier to keep track of.

Since this template code is being displayed in an HTML document, the brackets and braces have been encoded so they will be displayed properly. The best way to copy it would be to open a simple text editor and copy/paste the template code into the text editor, then copy/paste again from the editor into the template textarea field. This will ensure that the actual characters are being copied, and not the encodings.

All of the positioning and styling of the columns is done in the external .css file. There are several different ways to get the desired results; it doesn't have to be source-ordered, it doesn't even have to have all three columns displayed. For example, the home page could use all three columns for various content, while the rest of the pages could use a simple display:none on one of the columns to turn it into a two-column layout. The article on Template Variables will do just that, using a TV to determine how each page or even each section of your site wants to style the template.

* html body {border: 0; margin: 0; padding: 0;}
body {font: 100%/1.25 arial, helvetica, sans-serif; background:#fff; color: #000; width:100%;}
/********** Layout **********/
#masthead {width: 980px; margin: auto;}
#wrapper {width: 980px; margin: auto;}
#main {float: left; width: 34%; margin-left: 33%;}
* html #main {display: inline;}
#side1 {float: left; width: 33%; margin-left: -67%;    }
#side2 {float: left; width: 33%;}
#footer {width: 980px; height: 40px; margin: auto;}
.clearing {clear: both; height: 0; line-height: 0; font-size: 0;}

/********** Presentation **********/
/***** Masthead *****/
#masthead {height: 100px; background: green; color: white;}
#masthead h1 {}
#masthead ul {}
#masthead img {}
#masthead a {}

/***** Wrapper *****/
#wrapper {background: darkgreen;}

/***** Main *****/
#main {background: white;}
#main h2 {}
#main p {}
#main ul {}
#main p a {}

/***** Side 1 *****/
#side1 {background: lightgreen;}
#side1 h2 {}
#side1 p {}
#side1 ul {}
#side1 p a {}

/***** Side 2 *****/
#side2 {background: lightgreen;}
#side2 h2 {}
#side2 p {}
#side2 ul {}
#side2 p a {}

/***** Footer *****/
#footer {background: darkgreen; padding-top: 10px; text-align: center;}
#footer p {}
#footer a {}

The .css file can be stored anywhere in your site's filesystem that you like. Just make sure that the link in the document head has the correct path to wherever you put it. This goes for any other external files such as .js or .htc files the template may use.

the MODx Template Tags

Dynamic content is handled by replacing the various MODx tags with the content or the output of the structures the tags represent. There are several different tags used for different types of content.

Site Variables

Site variables are taken from the site configuration, which is stored in the system_settings table of the database, and in some cases in the config.inc.php file that was created when MODx was installed. They take the form [(fieldname)]. Only a few of these values are actually of any use to a web designer; do you really want to display on your page which Rich Text editor is the system default, or what the site's availability status is? Programmers can access these values with the $modx->config['fieldname'] array.

One item of especial note in our template is how the site variable tag [(modx_charset)] is used to define the charset in the content-type meta tag. This uses the site configuration setting. When MODx generates the HTTP headers for the page it will use the character set specified in the site configuration. By using this MODx tag in your template you make sure that the HTTP header character set matches the meta tag's charset. This will, among other things, avoid the character encoding mismatch warning from the W3C validator.

Besides the charset setting, the site variable tags are used in a couple of other places. One is in the title of the document head; this makes use of the site name. Another is to set a base href to the site url, which is useful for letting scripts and such know exactly what their full url should be. The particular format using a closing tag is used to keep both Internet Explorer and the W3C validator happy.

Document Variables

A number of document variable tags, [*fieldname*], are used. The current document's title is used in the document head's title tag, as well as using its long title as part of the masthead. The [*content*] tag is used to insert the document's main content into the template's "main" block.

Every field in the site_content table of the database is accessible as a document variable, although most of them would be of very little use to a web designer. For example, you may want to display the publishing date of the document. This value is stored in the database as a Unix timestamp, and would not be of much use if displayed directly. In the article on snippets, we'll create a simple snippet to convert that into a human-readable form. Programmers can access these document variables in PHP code with the $modx->documentObject['fieldname'] array.

Template Variables

Using the same tags, [*TVName*], and with similar results, TVs are sort of like the big brother of document variables; actually they are in a large sense custom document variables. There are some major differences, however.

Template Variables are assigned to templates, and only documents that use one of those templates can access them. When a document uses the same template that a TV is assigned to, a new field will appear beneath the main Content field when editing the document.

TVs can be given a default value when they are created, and all documents using them will have that same value unless the TV is edited in the individual document. It is also possible to edit a TV in a container document and have all of that document's children inherit the value.

TVs are such an important and powerful resource in creating web pages that an entire article will be devoted to them. In our template, the two sidebar sections are populated by TVs. They will be created and discussed in detail in that article.

Chunks

A chunk, {{Footer}}, is used to insert the site's footer content into the "footer" block. Chunks are simply small chunks of HTML, text, or MODx tags that can be used in different places, while maintaining just the one place to edit them. In this case, it's used more to keep the template itself clean so the structure can be quickly grasped with just a glance at the HTML. If several lines of copyright information, address and other contact information, and perhaps even a simple menu to TOS and privacy policy pages were in the template it would clutter up the HTML. The goal of any template system is to separate structure from content, and chunks are an important way of doing that.

Chunks are created in the Manager and stored in the database like templates. As with templates, the It's All Text! extension makes creating and editing chunks a lot easier.

Chunks are also often used for mini-templates for menus, news and blog listing snippets, and form handling snippets. For example, the Wayfinder menu generating snippet can use chunks to specify exactly what HTML structure every part of the menu should have, and the Ditto news and article aggregating system uses a chunk to specify the HTML layout of each news or blog summary in the listing. Different chunks can be specified for every alternate item, as well as for the first and the last items in the list.

Chunk tags can be used in your template, as the {{Footer}} tag is, or in your document's content. They can also be used in TVs, and even in other chunks. Programmers can access chunks in PHP with the $modx->getChunk('chunkname') function.

Snippets

Snippets are the containers for PHP code, and take the form [[SnippetName]]. They are created in the same manner as templates and chunks, with a few more options for configuration and default values. Their output is displayed in the location the [[SnippetName]] tags are placed. They can be placed in templates, chunks, content, or TVs. They can even be run inside of other snippets with the $modx->runSnippet() function.

Snippets behave much like the PHP inline construct <?php ... ?> does.

Snippet tags take two forms. Since MODx documents can be cached after they are generated for the first time, then served from the cache without full processing on subsequent requests, forms and other dynamic elements would never be processed. The form to specify that a snippet needs to be processed even if the document is cached is [!SnippetName!]. When the parser loads the cached document, it checks for these tags. If it finds any, it processes the snippet and inserts its output in its place, then serves the document.

Snippets can take parameters to control their behavior. These are in a format similar to the query string of a URL:

[!eForm? &formid=`ContactForm` &tpl=`ContactForm` &report=`ContactReport` &subject=`Site Contact` &thankyou=`ThankYou` &replyto=`email`!]

If the snippet call has parameters, the snippet name must be immediately followed with a question mark. The snippet call's parameter list must be all on one line. Each parameter takes the form of &name=`value`. Note that those are NOT single quotes, but backticks (usually found to the left of the 1 key). This is probably the most common cause of "newbie" problems with snippets not working as expected.

Often you'll find a need to use the output of one snippet as the value of a parameter to another snippet. Ordinarily this wouldn't work, since the first snippet encountered is processed before the second, inner one has been processed, so its value is not available yet. The solution is to nest the snippets with the outer snippet called uncached, and the inner snippet cached:

[!SnippetName? &param=`[[SecondSnippet]]` &param2=`value2`!]

Placeholders

Snippets can store parts or all of their output in placeholders. Then you can display that placeholder with [+PlaceholderName+] wherever you want the output to appear.

Links

Links to internal documents are generated with [~42~] tags, where the desired document's ID is the number. In the Document Tree panel on the right of the Manager page, the documents' IDs are the numbers in parentheses to the right of the document's title.

Document ID

This is useful because any of the other fields such as pagetitle or alias or menu title can be changed, but the document's ID is part of the database function and cannot be changed. If you needed to use a document's title, for example, then changed that title, you would have to remember every location where you had a link to the document!

MODx tags can be nested here, and document variables such as [*id*] or [*parent*], site variables such as [(site_start)] or TVs and snippets are often used:

<a href="[~[*TVName*]~]">Link</a>

The parser automatically generates an appropriate URL to the document with the supplied ID. One thing to keep in mind is that if you use this with a query string, you need to remember to use a ? prefix for the first name=value pair, and & as the prefix for all subsequent name=value pairs if your site is configured to use friendly URLs. If it is not, the index.php?id=42 is using that ? prefix already, so your first name=value pair must start with the & prefix.

Creating a MODx Chunk

Let's go make the footer chunk for our template. Log in to your Manager, and from the main menu go to Resources -> Manage Resources. Open the "Chunks" tab, and click on the New Chunk link. As in creating a template, a form will be displayed with a few text fields and a textarea field.

Give the chunk the name of Footer (it must match the name used in the tag exactly), and a brief description; perhaps "container for site footer content". The Category is not required, although it does make things easier when you have a long list of chunks and want to edit your footer. If the category "Template" doesn't already exist in the Existing Category drop-down, add it by putting Template in the New Category field.

In the Chunk code field, put something like this:

<p>&copy; 2008 My Site | Content managed by <a href="http://modxcms.com" target="_blank">MODx</a> | <a href="[~42~]">Contact Me</a></p>

As you can see, the chunk can have HTML code and MODx tags. It could also have any javascript tags that your page used. Here we use a link tag, where 42 is the ID of your contact form document.

How to Select The Template

Now we have a nice, clean template, with its structure completely separated from the page content. Chunks are a convenient way of keeping it that way. Now the question is, how to get a document to use our new template?

As with most things MODx, there is more than one way. In the Configuration form (in the main menu, that's Tools -> Configuration), in the Site tab, there is a select drop-down to set the site's Default Template.

Default Template

All documents created will automatically be assigned to use that template.

There are also a couple of radio buttons, one to change all existing documents to use the selected template, and one to only change those documents that are using the old default template. If you don't use these options, existing documents will continue to use their original templates.

The other way is to set each document when it is created. By default, as mentioned, a new document will use the default template set in the site configuration. Just above the main Content field in the document editing frame is a select drop-down, Use Template.

Document Template

When you select a new template, the frame will refresh. The document is not saved at this point! The refresh is done to make sure the document only has fields for the TVs that are attached to the template you selected. You still need to click the Save Button button to save your changes.

Yet a third way to determine what template a document will use is provided by the Inherit Template plugin, included in the default MODx installation. This will automatically set the document to use its parent's template; if the document has no parent (it's a root or top level document in the Tree, and its parent ID is 0) it will just use the default site template. Documents will only inherit their parent's template when they are first created; if you change the parent's template later, that change will not be propogated to the children.

By default the DocManager module is installed with MODx. This can be accessed from the main menu with Modules -> DocManager. The Templates tab allows you to choose the template you want to assign, then specify which documents to set to use the chosen template.

How MODx Uses Templates

Once the MODx parser (manager/includes/document.parser.class.inc.php) determines that the document exists, the viewer has permission to view it, and it is not going to be served from the cache, the template the document is assigned to use is taken from the database. The parser goes through the template, replacing the various tags with their processed output. The document will be passed through the parser up to 10 times in order to get everything processed (this is set in the main index.php file).

In the case of uncached snippet calls ([!SnippetName!]) the [! and !] tags are replaced by [[ and ]] tags and left for the next pass over the document. That's why nested snippets work the way they do; the outer uncached snippet just gets its tags replaced for later processing, while the inner cached snippet is processed right away, thus making its value available for the next pass when the outer snippet, now marked as an ordinary cached snippet, is processed.

The parser keeps track of the number of passes, as well as the length of the processed document content. If, at the end of a pass, the max number of passes has not yet been reached, and the document content length has changed from the previous pass, it will go through again. If the max number of passes has been reached, or the document's length did not change in the previous pass, the parser will return the presumably finished document content for final processing.

Finally, the parser does a bit of cleaning up, and exits. It always amazes me how fast computers are; all of this work is done in less than a split second! To see what I mean, go to the home page and take a look at the footer, where the time is displayed.

Comment On This Article


The information on the MODx parser is really valuable. This means chunks are allowed to contain snippetcalls. One of the things MODx lacks a bit is proper documentation, your efforts are really welcome and recognized!

thank you,
noes
You are my new Guru!
Great work and this info made it easier for a J++mla whizz to convert!

Chris
Stop doing other things and keep writing Susan!

Cheers,

Max