TPac Configuration and Customization
Template toolkit documentation
For more general information about template toolkit see: official documentation.
The purpose of this chapter is to focus on the Evergreen-specific uses of Template Toolkit ('TT') in the OPAC.
The URL for the TPAC on a default Evergreen system is
localhost to match your hostname or IP
Perl modules used directly by TPAC
The source template files are found in
These template files are installed in
You should generally avoid touching the installed default template files, unless you are contributing changes that you want Evergreen to adopt as a new default. Even then, while you are developing your changes, consider using template overrides rather than touching the installed templates until you are ready to commit the changes to a branch. See below for information on template overrides.
Apache configuration files
The base Evergreen configuration file on Debian-based systems can be found in
/etc/apache2/sites-enabled/eg.conf. This file defines the basic virtual host
configuration for Evergreen (hostnames and ports), then single-sources the
bulk of the configuration for each virtual host by including
TPAC CSS and media files
The CSS files used by the default TPAC templates are stored in the repo in
Open-ILS/web/css/skin/default/opac/ and installed in
The media files—mostly PNG images—used by the default TPAC templates are
stored in the repo in
Open-ILS/web/images/ and installed in
Mapping templates to URLs
The mapping for templates to URLs is straightforward. Following are a few
<templates> is a placeholder for one or more directories
that will be searched for a match:
The template files themselves can process, be wrapped by, or include other
template files. For example, the
home.tt2 template currently involves a
number of other template files to generate a single HTML file:
[% PROCESS "opac/parts/header.tt2"; WRAPPER "opac/parts/base.tt2"; INCLUDE "opac/parts/topnav.tt2"; ctx.page_title = l("Home") %] <div id="search-wrapper"> [% INCLUDE "opac/parts/searchbar.tt2" %] </div> <div id="content-wrapper"> <div id="main-content-home"> <div class="common-full-pad"></div> [% INCLUDE "opac/parts/homesearch.tt2" %] <div class="common-full-pad"></div> </div> </div> [% END %]
We will dissect this example in some more detail later, but the important thing to note is that the file references are relative to the top of the template directory.
How to override templates
Overrides for templates go in a directory that parallels the structure of the default templates directory. The overrides then get pulled in via the Apache configuration.
In the following example, we demonstrate how to create a file that overrides
the default "Advanced search page" (
advanced.tt2) by adding a new templates
directory and editing the new file in that directory.
bash$ mkdir -p /openils/var/templates_custom/opac bash$ cp /openils/var/templates/opac/advanced.tt2 \ /openils/var/templates_custom/opac/. bash$ vim /openils/var/templates_custom/opac/advanced.tt2
We now need to teach Apache about the new templates directory. Open
and add the following
<Location /eg> element to each of the
elements in which you want to include the overrides. The default Evergreen
configuration includes a
VirtualHost directive for port 80 (HTTP) and another
one for port 443 (HTTPS); you probably want to edit both, unless you want the
HTTP user experience to be different from the HTTPS user experience.
<VirtualHost *:80> # <snip> # - absorb the shared virtual host settings Include eg_vhost.conf <Location /eg> PerlAddVar OILSWebTemplatePath "/openils/var/templates_algoma" </Location> # <snip> </VirtualHost>
Finally, reload the Apache configuration to pick up the changes:
bash# /etc/init.d/apache2 reload
You should now be able to see your change at http://localhost/eg/opac/advanced
Defining multiple layers of overrides
You can define multiple layers of overrides, so if you want every library in your consortium to have the same basic customizations, and then apply library-specific customizations, you can define two template directories for each library.
In the following example, we define the
template_CONS directory as the set of
customizations to apply to all libraries, and
template_BR# as the set of
customizations to apply to library BR1 and BR2.
As the consortial customizations apply to all libraries, we can add the
extra template directory directly to
# Templates will be loaded from the following paths in reverse order. PerlAddVar OILSWebTemplatePath "/openils/var/templates" PerlAddVar OILSWebTemplatePath "/openils/var/templates_CONS"
Then we define a virtual host for each library to add the second layer of customized templates on a per-library basis. Note that for the sake of brevity we only show the configuration for port 80.
<VirtualHost *:80> ServerName br1.concat.ca DocumentRoot /openils/var/web/ DirectoryIndex index.html index.xhtml Include eg_vhost.conf <Location /eg> PerlAddVar OILSWebTemplatePath "/openils/var/templates_BR1" </Location> </VirtualHost> <VirtualHost *:80> ServerName br2.concat.ca DocumentRoot /openils/var/web/ DirectoryIndex index.html index.xhtml Include eg_vhost.conf <Location /eg> PerlAddVar OILSWebTemplatePath "/openils/var/templates_BR2" </Location> </VirtualHost>
Changing some text in the TPAC
Out of the box, the TPAC includes a number of placeholder text and links. For
example, there is a set of links cleverly named 'Link 1', 'Link 2', and so on
in the header and footer of every page in the TPAC. Let’s customize that for
To begin with, we need to find the page(s) that contain the text in question.
The simplest way to do that is with the handy utility
ack, which is much
grep but with built-in recursion and other tricks. On Debian-based
systems, the command is
ack conflicts with an existing utility.
In the following example, we search for files that contain the text "Link 1":
bash$ ack-grep "Link 1" /openils/var/templates/opac /openils/var/templates/opac/parts/topnav_links.tt2 4: <a href="http://example.com">[% l('Link 1') %]</a>
Next, we copy the file into our overrides directory and edit it with
bash$ cp /openils/var/templates/opac/parts/topnav_links.tt2 \ /openils/var/templates_BR1/opac/parts/topnav_links.tt2 bash$ vim /openils/var/templates_BR1/opac/parts/topnav_links.tt2
Finally, we edit the link text in
<div id="gold-links-holder"> <div id="gold-links"> <div id="header-links"> <a href="http://example.com">[% l('Link 1') %]</a> <a href="http://example.com">[% l('Link 2') %]</a> <a href="http://example.com">[% l('Link 3') %]</a> <a href="http://example.com">[% l('Link 4') %]</a> <a href="http://example.com">[% l('Link 5') %]</a> </div> </div> </div>
For the most part, the page looks like regular HTML, but note the
")%] that surrounds the text of each link. The
[% … %] signifies a TT
block, which can contain one or more TT processing instructions.
l(" … ");
is a function that marks text for localization (translation); a separate
process can subsequently extract localized text as GNU gettext-formatted PO
As Evergreen supports multiple languages, any customizations to Evergreen’s
default text must use the localization function. Also, note that the
localization function supports placeholders such as
[_2] in the text;
these are replaced by the contents of variables passed as extra arguments to
Once we have edited the link and link text to our satisfaction, we can load the page in our Web browser and see the live changes immediately (assuming we are looking at the BR1 overrides, of course).
If there is a problem such as a TT syntax error, it generally shows up as a an ugly server failure page. If you check the Apache error logs, you will probably find some solid clues about the reason for the failure. For example, in the following example the error message identifies the file in which the problem occurred as well as the relevant line numbers:
bash# grep "template error" /var/log/apache2/error_log [Tue Dec 06 02:12:09 2011] [warn] [client 127.0.0.1] egweb: template error: file error - parse error - opac/parts/record/summary.tt2 line 112-121: unexpected token (!=)\n [% last_cn = 0;\n FOR copy_info IN ctx.copies;\n callnum = copy_info.call_number_label;\n