Simplifying the T4 JS Layout Processor
Where I work, we use TERMINALFOUR as our main content management system. It’s a real beast of a CMS targeted at higher education, written in Java, and capable of handling very large, high-traffic sites straight out of the box. The only major hangup is that its normal publish processor for outputting HTML from user content is somewhat limited, and its JavaScript processor is not terribly well-documented and results in very murky code. To solve this issue, I created a paste-in language superset library called t4Query that abstracts what T4 is actually doing using a familiar, semantic, and short syntax.
The TERMINALFOUR Processors
TERMINALFOUR has a number of “layout processors,” or environments each with their own language for generating the HTML output from a content item. For the most part, everyone uses the standard layout processor. It’s direct output HTML with a special tag that can retrieve data that the user entered into the content item’s predefined fields. Various attributes on the tag determine how the data is output in the template. It’s pretty easy once you get the hang of it, but there’s very little logic available. The extent to which the layout can react to the content is a feature called “selective output,” wherein HTML can be output depending on whether or not there’s content in a field. There is no way to output different HTML depending on the page layout, no way to implement case logic, and no way to examine the contents of a field (like a date) and then do different things depending on what it says. This can be a pretty foreign experience for a developer who’s used to doing layouts in PHP on WordPress.
To get around this, you can use one of the alternative layout processors. The one that’s included and best supported is the JavaScript processor. It’s all the fun of a PHP layout, but there is one problem: Finding your data and outputting it how you want is quite an ordeal. This may be easier if you have access to actually see the database or log to a console, but if you’re just a system admin sitting outside of IT without shell access to the server, enjoy spending the day writing for-in loops to log properties and taking guesses at what functions do as they quickly drop off into Java black boxes you can’t look into.
What it Looks Like
How all of this affects your layouts is probably best illustrated with some examples. Say you wanted to output the path to an image (for use in a lightbox, maybe). Here’s how you would do it:
importClass(com.terminalfour.publish.utils.BrokerUtils); BrokerUtils.processT4Tags(dbStatement, publishCache, section, content, language, isPreview, '<t4 type="content" name="Media Field" output="normal" modifiers="" formatter="path/*" />');
Good luck walking in on your first day and figuring out what that does or why it works.
Say you wanted to use an if statement to see if someone checked a checkbox. Here’s how you access that checkbox’s value:
if (!content.get('Checkbox Field').publish().isEmpty()) { /* your code here */ }
Or perhaps you want to place a link to send an email to a particular address:
document.write('<a href="mailto:' + content.get('Email Address').publish() + '">send email</a>');
That’s not so bad, you say. But what if you wanted to sanitize the email field to ensure no stray HTML tags had appeared in it?
document.write('<a href="mailto:' + BrokerUtils.processT4Tags(dbStatement, publishCache, section, content, language, isPreview, '<t4 type=" name="Email Address" modifiers="striptags" />') + '">send email</a>');
It’s not horrible at first, but your content layout quickly becomes a garbled, unreadable mess. The code is very descriptive of what T4 actually needs to do under the hood to retrieve that data, but not ideal if you just want to open up a content layout and make a quick change.
Enter t4Query
What my designer and I needed was a library of shortcut methods that would allow us to use the power of the JavaScript processor, but be super-readable, super-familiar, and easily memorized. We needed a jQuery for TERMINALFOUR–so I made one. It works exactly how you’d expect: A selector to choose your content element, and then chainable methods to adjust how you want the output handled.
Getting an image path becomes:
$('Media Field').formatter('path/*')
Checking that checkbox becomes:
if ($('Checkbox Field').checked()) { /* your code here */ }
Including that email address in the link becomes:
document.write('<a href="mailto:' + $('Email Address') + '">send email</a>');
And stripping those stray HTML tags out of said email address becomes:
document.write('<a href="mailto:' + $('Email Address').modifiers('striptags') + '">send email</a>');
The library works by building a t4 tag as an object when you use a selector, and then adding or removing properties as you chain modifiers onto your statement. Finally, due to the magic of custom valueOf and toString methods in the tag object it creates, it’s able to automatically know when the tag has ended and pass it through TERMINALFOUR’s broker utilities to return the output in place. More info about how that’s done is available from this fascinating blog post about valueOf on Medium.
To use t4Query, just grab the javascript (full or minified) from the t4Query Github page, read the documentation on how to use it, and then paste it into the top of your content layout. Enjoy the power of the JavaScript processor!