MODX Template Variables
Before learning about Template Variables (TVs), you should have a good grasp of MODX Resources, because it's difficult to learn about TVs without understanding Resources.
All Resources have "Resource Content Fields" (almost always called Content Fields for short). There is a list of these Content Fields on the Resources page. Sometimes, however, the standard Resource Fields are not enough because you want to attach more information of your own to a resource. You might, for example, want to mark a document as outdated or in need of editing and there are no Resource Fields for that information.
The answer is Template Variables. You can create a TV, give it a descriptive name, and attach it to a Template, and the TV will show up on the Template Variable tab of the Create/Edit Resource panel whenever a page that uses the Template is created or edited.
As an aside, I should mention that it's perfectly acceptable to co-opt one of the standard Resource Fields to store your own information, though you'll have to use some common sense about which fields should be left alone. You definitely shouldn't do this with the content, id, published, alias, content_type, or content_dispo fields, for example, but the introtext, description, and longtitle fields are fine as long as you don't need them. If you're not using the longtitle field for anything, you can put any information you want there and it will be displayed on a page anywhere MODX finds the [[*longtitle]] tag. This method is much faster than using TVs and it will also be easier to use the information as a criterion for searches with getResources and other extras that select resources for display.
Although they are attached to Templates, the values of a TV are page-specific. In other words, the value of a TV called "MyTv" for a particular page will show up wherever MODX sees a [[*MyTv]] tag when that page is rendered in a browser.
The Inside Story
To grasp how TVs work, it's helpful to understand how MODX handles them internally. You don't really need to know this information to use TVs, but it can help you understand how they work. Without going into too much detail, TV information is actually stored in several separate tables in the database.
One table holds each TV itself (each TV is a row in the table) along with information about the TV's Input Type (e.g., date, text, image, file, etc.), its Default Value, Input Option Values (how the input form showing the TV will be rendered) and Output Options (how the TV will be rendered on a web page). For some TVs, there is addition information. File TVs, for example, need a path to the file and Image TVs need a path and various attributes like alt, height, and width . When you create a new TV, a new row is placed in this table, but no actual values are set for the TV for individual Resources.
Another table holds the information about which Templates the TV is attached to, and yet another table contains information about any Resource Groups the TV belongs to (if any).
None of the tables above has any actual TV values. Those are stored in another table where each row has three important fields containing a TV ID, a Resource ID, and a value. If MODX wants to know the value of a TV for a particular page, it looks for a row in this table where the TV ID matches the ID of the TV it's processing and the Resource ID matches the ID of the Current Resource. If it finds that row, it grabs the value. If it doesn't, it uses the Default Value of the TV from the first table.
Because there are four separate tables involved, TV tags take time to process. If you have a few TVs on a page, no one will notice the delay, but if you load a page up with a dozen or more, you may see a significant delay before the page shows up in the browser.
If you are working with TVs in PHP code, a quirk that you should know about is that for TVs where the value of the TV for a resource is equal to the TV's Default Value, no value is stored in the table of TV values (the last table described above). It's assumed that MODX will use the Default Value of the TV if no value is found there, so there's no point in storing it. That means you will have to do the same thing in your code or TVs set to the default value may appear empty.
Creating a Template Variable
These instructions are for MODX Revolution. In Evolution, you can go to Elements | Manage Elements | Template Variables tab and click on the "New Template Variable" link.
In Revolution, you can select the Elements tree in the left panel of the Manager, then right-click on the "Template Variables" folder and select "New Template Variable". You can also select "Quick Create TV. That will open a popup window where you can create a TV without losing your place in the Manager, but you won't be able to set certain features of the TV that way, so that option is seldom used.
On the Create/Edit Template Variable panel on the right, you'll see several tabs that allow you to set the various options for a TV.
On the General Information tab, you can set the Name, Caption, Description, and Category. You can also set the Sort Order of the TV, which will determine where it will show up relative to other TVs on the Create/Edit Resource panel's Template Variables tab. TV's with lower numbers show above ones with higher numbers.
Notice that every TV has both a Caption and a Name. The Caption is the heading used in the Manager when you see the TV displayed on the Create/Edit Resource panel. The Name is the actual name of the DB field referring to the TV and what you must use in any TV tag. If you forget the Name of a TV, you can see it by hovering over the TV's Caption when editing a Resource. The name will be shown as it would appear in a TV tag. When you hover near the Caption, you'll also see a little green icon. Clicking on that icon will set the TV for that page to its Default Value (the one you set -- if any -- when you created the TV).
The Properties tab lets you set Properties for the TV. These are just like Snippet Properties. This is a new feature in MODX Revolution, and is not often used with TVs. In Revolution, all Elements can have Properties, but there is seldom any reason to use them with TVs. If you set properties for a TV, any placeholder tags in the TV will be replaced by the value of the property with the same name. In other words, if you have set a property called name with a value of John Doe, if there is a placeholder like this in the TV's value: [[+name]], it will be replaced with John Doe. I've never used this feature, but if you used a TV to display a name and used a property and tag for the name itself, you could update the property of the TV itself and the name would change wherever the TV was used. This is seldom necessary because you could do the same thing more easily using the TVs Default Value.
The Input Options tab lets you set the Input Type of the TV, the Input Option Values, the Default Value, whether the TV can be left blank, and an optional min and max length for the TV. If you select certain Input Types, you'll see more options (try Image to see an example). Explaining all the Input Types is beyond the scope of this page (see my book or this page).
The Output Options tab, lets you select how the TV will be rendered in the Manager, and/or the front end of the site. Much of the time, the default selection will work fine. Note that if you set this to "image", MODX will render a complete img tag to replace the TV tag so you don't need to wrap it in any HTML to present an image in the front end. If you set it to "date", you can adjust the format of the date and specify whether you want MODX to use the current date/time. Note that a "date" is really both a date and a time. Using the format string, you can show either or both in many different formats. There is a page on formatting dates and times here. Except for images and dates, it's usually best to try the default option first to see if it does what you want.
On the Template Access tab, you can specify which Templates the TV is attached to. This is an important step because if you don't select any Templates here, the TV will never show up on the Create/Edit Resource panel. When you select a Template (by checking the box at the far right), the TV will show up and accept values on any page that uses that Template. Note that if you change a page's Template, the values of its TVs may be lost. You will have to manually enter the page's TVs again and save it.
The Access Permissions tab lets you assign the TV to one or more Resources Groups (by checking the boxes at the far right). This is only necessary if you want to hide the TV from certain users (in the Manager, this can also be done with Form Customization). If you haven't created any Resource Groups, you won't see any listed here. If you put the TV into a protected Resource Group, only users with permission for that Resource Group will see it. See this page for more information on using the Security System. You can hide a TV from certain users three different ways: with Form Customization, by putting it in a Resource Group, or by putting it in a Category and hiding the Category. I generally prefer to do it with a Category, but all three methods work.
After setting all the TV options, don't forget to click on the "Save" button at the upper right.
A Concrete Example
Here's a good example of the power of Template Variables. Suppose you're doing a web site for a community group or association. Pages on the site often mention the officers of the group (chair, vice-chair, secretary, treasurer, etc.) by name, but the people in those roles change often. It's a pain to have to find all the references throughout the site and change them every time someone new takes over an officer position. Template Variables are the perfect solution for this.
You can create a TV called "Chair". In any document that refers to the Chair, you can place a tag for the TV: [[*Chair]] and it will be replaced by the name. Obviously, you could do the same thing for the other offices. If that's all you did, you'd have to set the TV for every page that uses it. Fortunatly, there are two ways to avoid that.
First, you can set the Default Value of the TV to the person's name and leave the TV blank on all pages. When MODX sees the blank TV, it will get the Default Value and use that to replace the tag. When the person in the Chair role changes, you simply need to change the default value of the TV. Note that you have to be careful *not* to set the value of the TV for any particular page. If you have other users, you might want to hide the TV from them.
Second, you can use @INHERIT for the Default Value of the TV. When MODX sees the blank TV, it will search up the tree (parent, grandparent, great-grandparent, etc.) for a resource with the TV set and use that value for the TV. This method is handy if you want to have different values for a TV in different parts of your site. If you set the value of the TV on a container, all it's descendants will inherit that value. Again, it's important *not* to set the value of the TV on pages where you want the value to be inherited.
Finally, using a little-known feature of MODX, you can actually combine the two methods above. You can set the Default Value of a TV like this:
With this setting, MODX will look for an ancestor of the Current Resource that has the TV set. If it finds one, it will use that value. If it doesn't, it will use "SomeValue" as the Default Value.
Creating a Real TV
These instructions are for MODX Revolution. In Evolution, some of the steps are different, but the concepts still apply.
Remember that tags in MODX are case-sensitive. If the name of your TV is "Chair" a [[+chair]] tag won't show anything at all. Also, remember the difference between the Caption and Name of a TV. The Caption shows in the Manager when editing a Resource, but the Name is what you must use in tags. Trying to use the Caption in a tag is a common error. One solution is to always make the Name and Caption the same.
Let's create an actual TV and display it on a page. For our example, we'll use a Radio Options TV that lets you rate your each of your pages using a set of adjectives. You'll need to know which is your site's Default Template. If you don't know, go to System | System Settings and type default in the search filter at the upper right, then press Enter. Make a note of the default_template value. If you see a number, you can look on the Element tree in the Templates folder to see which Template it is (the ID is in parentheses next to the name in the tree), or you can double click on the number in the System Settings grid to see the name of the Template highlighted in the list.
On the Elements tree, right-click on the "Template Variables" folder (be careful, you want Template Variables, not Templates) and select "New Template Variable". You should see the Create/Edit Template Variable panel on the right. Enter the following field values on the "General Information" tab:
- Name: Rating
- Caption: Rating
- Description: My Rating of this page
Now, select the "Input Options" tab. Set the following values:
- Input Type: Radio Options
- Input Option Values: Great||Excellent||Fabulous||Tremendous
- Default Value: @INHERIT Fabulous
On the "Template Access" tab, check the box next to your site's Default Template.
Click on the "Save" button at the upper right to save your new TV.
Now, create a new Resource. Call it anything you like. It should have the site's Default Template set. Click on the Template Variable tab and you should see your TV with "Fabulous" selected. Change the value, then put the following text and tag in the Resource Content field to of the Resource to display the TV:
<p>I think this page is: [[*Rating]]</p>
Save the Resource.
Now, preview the page you just created. You should see the value you selected for the TV.
You can experiment further with your TV. Create some children and grandchildren for your page with the same text and tag in the Resource Content field. When you preview them, you should see the TV set to "Fabulous" (its Default Value). If you change the value on a parent page, all its children should now show that value because of the @INHERIT binding. Try editing the TV itself (right-click on it in the Elements tree) and change the Input Type to "Listbox (Single select)". Edit a resource and, on the Template Variable tab, your TV should now be rendered as a drop-down list rather than radio buttons.
@ bindings are a kind of shorthand that will let you extend TVs for special purposes. We've already seen the @INHERIT binding, but there are several others. Here's a quick reference to them:
- @INHERIT [value] — The TV tag will be replaced by the value from the nearest ancestor with a value set for the TV. The [value] term is optional and will be used of no ancestor has the value set.
- @CHUNK — The TV tag will be replaced by the named chunk.
- @RESOURCE — The TV tag will be replaced by the Resource Content field of the named Resource.
- @FILE — The TV tag will be replaced by the contents of the names file.
- @DIRECTORY — The TV tag will be replaced by the filenames in the named directory, separated by ||. This is meant for Radio Option and List TVs to determins the values shown in the Manager.
- @SELECT — The TV tag will be replaced by the results of a MySQL query, separated by ||. This is meant for Radio Option and List TVs to determins the values shown in the Manager.
- @EVAL — The TV tag will be replaced by return value of inline PHP code. Code must begin with return and end with a semicolon. Use with caution as this presents serious security vulnerabilities.
- @ bindings can be nested inside other @ bindings.
@INHERIT blue @CHUNK MyChunk @RESOURCE MyResource @FILE assets/files/myfile.txt @DIRECTORY assets/files/myfiles/ @SELECT name, phone FROM customers @EVAL return "Current time: ".time(); @EVAL return "Message: @CHUNK MessageChunk";
Sometimes, the values you want to use for a TV are long and ugly. There's a way to let users select them without showing the ugly version. Suppose you want to store a path to a CSS file in a TV called "CssTv" but let users select it without seeing the full path. To make it easier to explain, let's assume that you have three CSS files that set the background color of something on each page (or the whole page) to red, green, or blue. In the site Template, you'll have something like this to apply the correct CSS to the page based on the TV:
<link rel="stylesheet" type="text/css" href="[[*CssTv]]" />
Assume that the TV Input Type is set to Radio Options. You can use something like this for the Input Option Values field:
Your users will see just red, blue, and green when they edit the TV, but the actual value of the TV will be set to the path. Notice that each option takes the form captions==value and that the options are separated by || as we saw in our earlier example.
Other Uses for TVs
We've seen examples of using a TV to present a value in the front end and controlling the CSS used for a page, but there are many other uses for TVs. Because TVs can be read in PHP code, they can be used to store information that will control just about anything. For example, the value of a TV could be used to tell a plugin or snippet whether to highlight certain strings on a given page, what kind of highlighting to use, or what strings to highlight on any particular page. In fact, TV values could be used to determine whether a page is shown at all and where the user should be forwarded to if it's not shown.
What you can do with TVs is limited only by your imagination and coding skills. Remember, though, that using too many TVs on a page can slow down the page delivery. It's particularly slow to use TVs in combination with conditional Output Modifiers or aggregating snippets like getResources.
My book, MODX: The Official Guide - Digital Edition is now available here. The paper version of the book may still be available from Amazon.
If you have the book and would like to download the code, you can find it here.
If you have the book and would like to see the updates and corrections page, you can find it here.
MODX: The Official Guide is 772 pages long and goes far beyond this web site in explaining beginning and advanced MODX techniques. It includes detailed information on:
- Installing MODX
- How MODX Works
- Working with MODX resources and Elements
- Using Git with MODX
- Using common MODX add-on components like SPForm, Login, getResources, and FormIt
- MODX security Permissions
- Customizing the MODX Manager
- Using Form Customization
- Creating Transport Packages
- MODX and xPDO object methods
- MODX System Events
- Using PHP with MODX
Go here for more information about the book.
Thank you for visiting BobsGuides.com
— Bob Ray