We can address these issues by applying the basic principles of template processing. Rather than creating the HTML page directly, we write a template for generating the HTML page. In this document, we use template variables to store these values instead of hardcoding them.
Example 2-2 shows a source template for the HTML page in Example 2-1. The author’s name, page title, background color, and year have been replaced by the variables author, title, bgcol, and year, respectively.
Example 2-2. hello.tt
Processing Templates with tpage
Of course, a template isn’t something a browser can make sense of. We need to process the template to generate HTML to send to the browser. Let’s use the tpage command we met in Chapter 1:
$ tpage --define author="Arthur Dent" \
The hello.html now contains the same HTML that we saw in Example 2-1. This time, however, it has been generated from a template. The benefit of this approach is that we easily change any of these variable values and generate a new HTML page, simply by invoking tpage with a different set of parameters.
Example 2-2 shows a template for generating a complete HTML page. We refer to this kind of template as a page template to distinguish it from the other kind of template that we’re now going to introduce: the template component.
We use the term “template component” to help us identify those smaller templates that contain a reusable chunk of text, markup, or other content, but don’t constitute complete pages in their own right. Template components are no different from page templates as far as the Template Toolkit is concerned—they’re all just text files with embedded directives that need processing and get treated equally. Examples of typical template components include headers, footers, menus, and other user interface elements that you will typically want to use and reuse in different page templates across the site.
When we start using ttree a little later in this chapter, we will need to be more careful about storing our page templates separately from any template components. For now, however, we can keep them all in the same directory, simplifying matters for the purpose of our examples. As a general naming convention, we use a .tt or .html file extension for page templates (e.g., hello.tt), and no extension for component templates (e.g., header), but this is entirely arbitrary. If you want to give them an extension (e.g., header.ttc), that’s fine.
Headers and Footers
Our first components can be created easily. Extract the header and footer blocks from Example 2-2 and save them in their own header and footer template files, as in Examples 2-3 and 2-4.
Example 2-3. header
The PROCESS directive
We can now load these template components into a page template using the PROCESS directive. Example 2-5 shows this in action.
Example 2-5. goodbye.tt
[% PROCESS header %]
When the Template Toolkit encounters a PROCESS directive, it loads the template from the file named immediately after the PROCESS keyword (header and footer are the two templates in this example), processes it to resolve any embedded directives, and then inserts the generated output into the calling template in place of the original directive.
We can use tpage to process the goodbye.tt template and save the generated output to goodbye.html:
$ tpage --define author="Arthur Dent" \
Example 2-6. goodbye.html.
The INSERT directive
The Template Toolkit provides a number of different directives for loading external template components. The INSERT directive, for example, inserts the contents of a template, but without processing any directives that may be embedded in it:
[% INSERT footer %]
INSERT is faster than PROCESS because there’s much less work involved in inserting a file than there is in processing it as a template. It’s not going to work for us in our current example because of the year and author variables in the footer that need resolving. If we INSERT the footer as it is, we’ll see the [% year %] and [% author %] directives passed through as literal text.
However, we can hardcode the variables in the footer to make it a fixed block of text that we can then load using INSERT . For example:
Although we’ve no longer got the benefit of using variables or other template direc tives, we are still defining the footer in one place where we can easily make changes, should we ever need to.
In most day-to-day applications, the difference in speed between INSERT and PROCESS isn’t going to be noticeable unless you really go looking for it. You’re generally better off using whatever is most convenient for you, the template author. Worry about performance only if and when it ever becomes an issue. With this in mind, we’ll leave our variables in the footer and continue to use PROCESS .
The other directives for loading templates are INCLUDE and WRAPPER , which we’ll be looking at shortly.