Preface: This is one of the hacks that I had contributed to the O'Reilly Blog Hacks
projects until it was pulled from production. For awhile, I've been meaning to release what I did through my weblog like the legenary Tom Coates did in his. Today I put my foot down and take some action.
Back in November 1997 I read a Webmonkey article by Jeffery Veen entitled Object-Oriented Publishing on the Web. In the article Veen notes that building a Web site should not be redundant activity. Rather then cutting-and-pasting markup, content and links throughout your templates or pages, he suggests that developers think of a sites as chunks of content
that can be assembled in various ways to form pages. He goes on to explain that these chunks are compartmentalized elements in your page layouts, such as header, footer, navigation, sidebars, and the page body, are the functional equivalent of objects
in object-oriented programming. (He later went on to dedicate an entire chapter to the concept of object-oriented publishing in his book The Art & Science of Web Design and later excerpted in another Webmonkey article.)
Generally speaking, object-oriented techniques eliminate redundant effort, ease maintenance and future modification, increase reuse and improve quality. Object-oriented techniques also better support evolutionary, iterative and incremental development then other means. For those not familiar with object-oriented development theory we will not be able to go into the topic any further. There are dozens of books and scholarly papers written on the topic if you're interested.
Being a programmer that was already familiar with the principles of object-oriented design, the notion of applying them to web publishing resonated with me though I hadn't considered it until I had read Veen's article. Since then I've always tried to apply these object-oriented publishing principles to any website I've built including weblogs.
So how do we apply object-oriented publishing to weblogs? It depends on the tool you are using as to how and to what extent. Here I'll cover how I do it with my weblogging tool of choice, Movable Type. To demonstrate that this notion is adaptable to other environments, I will also walk through another method using Apache's XSSI (Extended Server Side Includes) – the one Veen used to illustrate his principles in the original article. Its one that I've used in the past before the various publishing tools and page generation technologies we have today were readily available. (I've personally adapted these principles to ColdFusion and I'm confident they are applicable to PHP, ASP, JSP and any many others.) While not as elegant, the XSSI method that can be applied to weblogging tools such as Blogger that can write static files that are being served up with the Apache web server. Let's discuss these approaches to object-oriented publishing.
Movable Type (MT) structures your content and keeps it separate from its display via templates. What it lacks in the grand scheme of object-oriented publishing is a facility for applying a global layout template – a single template that can wrap the layout of any other page's content with the common elements (header, footer, navigational links) used throughout.
Ideally you would create a module that is a global layout template with placeholders for various pieces of content to be plugged into. Each template would create the body of content and set other meta data variables before calling in the global layout template to assemble the page. I initially found that there is a catch to doing this in MT though. While MT allows for variables to be set and retrieved in templates using <MTSetVar> and <MTGetVar> tags, it only permits small bits of static text to be stored – not paragraphs with markup and links. It also meant you could not capture the output of a block of MT template code, which is precisely what is needed for inserting the content body into the global layout template.
In trying to work within MT's capabilities initially, I broke my content objects into MT modules and used <MTInclude> tags to call them into each template. While this helped minimize a certain amount of redundancy and provide some reuse, adding a new element or reshuffling the order of objects in the layout still required making the same change multiple times.
With the later introduction of plugins to MT, I was able to create a better and more elegant solution for implementing a global page template and achieving a better object-oriented publishing effect.
I created a very simple container tag plugin, <MTSetVarBlock>. (The mt-setvarblock plugin is freely available under the Artistic License.) This tag is similar to <MTSetVar>, but instead of taking in its value as a tag argument, it stashed the output of what was between its start and end tags. Now any amount of text, markup and, most importantly, MT template tags could be included and its output captured into a variable. The block of content could be retrieved with a <MTGetVar> tag just as you would output a variable set with <MTSetVar>. With this added bit of functionality, I could create a consistent look and feel for my entire weblog with a modicum of template code by reusing the common elements.
First I created a global layout template with the elements that appear throughout the site and frame the various content layouts. You may want to break the various elements into their own separate modules and use <MTInclude> to bring them into the global template. It depends on your situation and personal preference whether you will want to do this. In many cases I have elected not to because these elements where only used solely by the global template.
One word of caution. As Movable Type users know, MT statically renders its content to files. This is generally a very good thing, however there are a few side effects of this feature that my impact the implementation of technique. In order to avoid having to needless rebuild the entire site each time new content (an entry, comment or ping) is published, MT attempts to selectively rebuild files based on tags usage that it has mapped and the template type. MT does not map modules and it does not allow you to directly nest templates. Suppose you want to render a list recent entries and include it in your global page layout. Movable Type will not recognize that all of the templates using the global layout template module needs to be rebuilt. You probably don't want your whole site rebuilt every time you make an entry anyway. In these situations you should generate a file using a standard template, like an index template. Then by including some dynamic scripting code such as XSSI or PHP in your template, include that generated file into the layout.
Here is a simple example of a global layout template module.
<html>
<head>
<title><MTGetVar name="title"/></title>
</head>
<body>
<h2><MTGetVar name="title" /></h2>
<MTGetVar name="body" />
</body>
</html>
With the global layout stored as a module, I created my various index and archive templates. Since there was no need repeat all of the elements that was in the global layout, these templates consisted of creating a layout for the body of that specific template and wrapping it in a <MTSetVarBlock> tagset with a name of body.
I also set variables with information (meta data) that needed to be inserted into the template. While these are optional and will vary based on what you are doing in your global template, I've found them helpful in refining my template by giving me more control on a template-by-template basis. At a minimum, I tend to create and store a variable that contains at least part of the page title. You can have as may or as few as you like. You may also want to set a variable for controlling a conditional statement inside your global layout.
Finally I include the global layout module. MT retrieves the module and processes it, inserting the content where I had placed my markers using <MTGetVar>.
Here is a simple example of a master archive listing of hyperlinked entry titles for a blog in reverse chronological order using the global layout template.
<MTSetVarBlock name="title"><MTBlogName/> Archive</MTSetVarBlock>
<MTSetVarBlock name="body">
<MTEntries>
<a href="<MTEntryLink/>"><MTEntryTitle/></a><br />
</MTEntries>
</MTSetVarBlock>
<MTInclude module="Global Layout Template"/>
Rebuild your blog and you have a consistent layout throughout your site with a minimum of template coding necessary. Want to give your weblog a different look? Change the global layout template, save, rebuild all and viola! Your whole weblog has a different look.
As I mentioned earlier, object-oriented publishing is adaptable to other weblog tools. How and to what extent varies. Now we'll look at how you may apply these principles to other weblogging tools using static files and the Apache Web server's XSSI capabilities.
XSSI is a set of built-in commands for (as its name implies) inserting files and doing basic if-else conditionals in addition to setting and output variables. The commands are quite limited and only provide the most rudimentary of functions – they're no loops nor there any type of lists/arrays to work with. Creating extensions or plugins means modifying C code and recompiling the server – not a trivial task though some have made valiant attempts with some success. Despite all of this, a remarkable amount can be done with XSSI including web publishing in an object-oriented style.
Unlike the Movable Type example, XSSI does not have the ability to set variable with a block of content and requires two files and some file naming conventions to achieve. Since its not connected to a database all data must be loaded in variables or individual files. While it's not ideal, it's not so laborious when you have a tool to do all of the hard work. XSSI does allow for your changes to be seen immediate since the pages are assembled dynamically.
Let's look at how XSSI can be applied.
Each piece of content would require two smaller files. The first file is the file users will retrieve. It defines the meta data for the content before finally calling the global layout that we'll look at momentarily. Here is a simple example file we'll call foo.shtml.
<!--#set var="title" value="My foo title." -->
<!--#set var="description" value="This is an excerpt of the content that will be inserted." -->
<!--#include file="global_template.shtml" -->
In order to accommodate inserting the body content into the global layout template, we place it into a separate file and give it the same name as its meta data mate and a .body appended. This way we can use the built-in DOCUMENT_URI HTTP server variable in our global template to programmatically make the association between the two content files. So this example file, foo.shtml.body, is just the main body of content – plain text and markup.
<p>This is a simple example to demonstrate body copy being inserted into a template using just Apache XSSI.</p>
<p>These are not the droids we are looking for. Move along. Move along.</p>
You can include XSSI commands in this file if necessary though I wouldn't advise it. Besides you'll have to configure the server to parse files with .body extensions.
The final piece is the global layout where we output (echo) meta data and include the body of content. Here is a sample global layout template in XSSI loosely based on the one used in the Movable Type solution.
<html>
<head>
<title><!--#echo var="title" --></title>
<meta name="description" content="<!--#echo var="description" -->" />
</head>
<body>
<h2><!--#echo var="title" --></h2>
<!--#include virtual="${DOCUMENT_URI}.body" -->
</body>
</html>
That's all. Like I said using XSSI is not as ideal, but with Apache's widespread deployment it provides virtually any tool the can output static files a means of applying an object-oriented style to publishing.