Using Cheetah to structure a web site

[Go to main articles index]

Anyone maintaining a moderately complex web site has to face the problem of comfortably editing a large amount of pages, with some content that must be kept consistent between them. Dynamic sites based on scripting languages (PHP, ASP...) can often use such mechanisms to handle these issues.

The main NGEDIT site was done with raw html, but very soon I started looking for ways to handle the complexity. Adding a "FAQ" section, for example, would require modifying many pages to include it in the navigation bar. Any change to the layout would have to be done to all the html files.

My idea was to define some elements in a central location, and then call up these elements from each page. On the other hand, I wanted to do this processing statically and upload simple html files to the server - no need to act dynamically for something that doesn't need to be regenerated often.

I was thinking about hacking together some mechanism, as I could not find any text preprocessor that would work. I checked m4, a long time Unix preprocessor I had some time read about, but it wouldn't lend itself well to multi-line blocks, which I needed for the web page.

I asked about this in a blog post, and fortunately a reader called Lena suggested that I check out the Cheetah template language. Off I went, downloaded it, and I started trying to use it. It took a while to get working, but the end result it great! Here you have a "getting started" description in case you are interested in using it yourself.

I use a Windows system, so some of the comments will be specific to this platform.

Cheetah is developed using Python, so the first thing you need to do is to download and install the Python system. You can't actually install Cheetah until Python is installed. I don't know Python, but I could grok enough of it to get Cheetah working.

Once you have installed Cheetah, there are a few steps you have to take to get started. First, go to a directory called Scripts within the Python installation directory (in my case, that was C:\Python24\Scripts). If Cheetah has been installed, there should be two files called cheetah and cheetah_compile - the first thing to do is to add the ".py" extension to them. This makes using them much easier. Under Unix, they are probably marked as executable scripts, and that lets you use them as executable commands. Under windows, given that the Python installer sets up things so that ".py" files are associated with the python executable, if you add the proper extension that lets you also use them as commands in the command line.

The next step would be to add the Python directory and the Python\Scripts directory to your path variable.

Once this is working, you should be able to write "cheetah.py" in the command line and get Chetah's command line syntax help (as you would expect from any command-line utility).

There is a quite long user's guide up for download from the Cheetah web site - I will only detail how I have set up my web editing framework to benefit from Cheetah.

I have created a "main.hi" file with all the general definitions that the different web pages use, and I write a ".hs" file for each web page. "hs" means "html source" and "hi" means "html include", it's just two extensions I chose for this goal - and all hs files include the main.hi file as one of the first lines.

How do you define a macro in the .hi file? The easiest way is to use the Cheetah "#set global" command:

#set global $ARTICLESUBTITLE = '''\
    <a href="articles.html"><b>[Go to main articles index]</b></a>
''' 

The three quotes allow defining a multi-line string constant in Python. $ARTICLESUBTITLE is the variable name to which the value is assigned. The backslash at the end of the first line quotes the actual line feed after the #set line, avoiding an extra line feed that you probably don't want to include in the output.

And how do you invoke this from the hs file? You simply type $ARTICLESUBTITLE wherever you want to include it, and it will get substituted. You can write it in the middle of a line, a string, or on a separate line.

Using this system, a web page in your site with a navigation bar, logos, a copyright notice, CSS styles, and some content, may actually just look like this:

#set global $PAGE_TITLE = "Using Cheetah to structure a web site"
#include "main.hi"
$HEADER
  $NAVBAR
  $BODYHEADER

    <h2>$PAGE_TITLE</h2>
    This is the actual content of the page!

  $BODYFOOTER
$FOOTER
    

Ain't it neat? This framework has allowed me to extend the web site as needed in the minimum amount of time required to actually write the content and link it.

As you have seen above, I'm also defining values in the ".hs" file. These values are used in some of the macros defined in the ".hi" file. I first tried to simply use them within the macro, but that didn't work because the strings are not scanned for variable substitution (you can force that, but you lose the simple #macro invocation done with $MACRO). The trick is to define the macro as an actual Python expression concatenating the different parts:

#set global $HEADER = '''\
    ... first lines of header ...
    <title>''' +  $PAGE_TITLE + '''</title>
    ... more lines of header ...
''' 

How do you generate the html files from the hs source files? I actually use a simple bat file, which reads:

cheetah.py fill --iext hs -R --odir html %1
copy main.css html\main.css 

The 'fill' command means that Cheetah should process the file and generate the final result (you can also 'compile' the file and instantiate it later, multiple times, with different variable assignments, but I'm not actually using that). The '--iext hs' option means that it should process files with the 'hs' extension. '--odir html' means that output files should be written to the html directory. '--R' means that Cheetah should recurse folders looking for '.hs' files - I actually use a flat file layout, but this option means I don't need to list all '.hs' files explicitly. The final %1 option allows running it with a filename parameter, which I use when I want to process a single file (if you don't give an explicit filename, the '--R' option will have Cheetah process all '.hs' files. Then, I just copy the CSS file to the html directory (no processing done to the CSS file, but it's useful to maintain the separation between "source" and "object" directories).

All in all, Cheetah has turned to be really useful for my text-file automation needs. Although it defaults to writing '.html' files as output, that is also customizable and then you can use it for any kind of text output.

Kudos to the Cheetah team!