Templates can bring order and structure to a web site. In this article I describe how templates can be used to control the page layout for a site that is currently composed of many pages of static HTML, using a popular template class and a new feature of PHP4.
But first, let's set the scene. There are two distinct motivations for introducing templates:

Separating Functionality from Layout

The first motivation is the most-often discussed. Here the situation is that a group of programmers produce PHP scripts to generate the content of a page, whilst a group of graphic designers produce HTML and images to control the appearance of the finished page. The idea is to allow both groups to work on independent sets of files. The programmers can work on files that contain only PHP, without concerning themselves with producing nicely presented HTML, whilst the graphic designers can work on the layout of the page using their favourite visual editor, without worrying about breaking any embedded code.
If you have read any tutorial on templates you will have seen the way this works. Consider a simple page layout with a header, left-hand navigation bar and a central area for the page content. A site like this might have the following template files:
<!-- main.htm -->
<html>
<head><title>Example</title></head>
<body>
<table><tr><td>{HEADER}</td></tr>
<tr><td>{LEFTNAV}</td><td>{CONTENT}</td></tr>
</table>
</body></html>

<!-- header.htm -->
<img src="sitelogo.jpg">

<!-- leftnav.htm -->
<br><a href="foo">Foo</a>
<br><a href="bar">Bar</a>
You can see how the page is going to be built from these elements. The main template controls the layout of the page, and the header and leftnav templates control the common elements. The identifiers in braces {} act as placeholders and get substituted by the template code. The key benefit is that the graphic designers can edit these files as they see fit, adding fonts, colours and graphics, or perhaps completely altering the layout of the page. They can edit these files using normal HTML editing tools, even visual ones, because the files are straight HTML (or HTML fragments) with no PHP code.
The PHP code goes in a separate file. This is the file that is actually called up by the page URL. The web server uses the PHP engine to parse this file and returns the result to the browser. Typically the PHP code produces the content for the page dynamically, perhaps by querying a database or performing a calculation. The file might be as follows:

<?php

  
// example.php
  
require('class.FastTemplate.php');
  
$tpl = new FastTemplate('.');
  
$tpl->define( array( 'main' => 'main.htm',
                       
'header' => 'header.htm',
                       
'leftnav' => 'leftnav.htm' ) );

  
// PHP code here to set $content to the required page content

  
$tpl->assign('CONTENT'$content);
  
$tpl->parse('HEADER''header');
  
$tpl->parse('LEFTNAV''leftnav');
  
$tpl->parse('MAIN''main');
  
$tpl->FastPrint('MAIN');
  
?>
We are using the popular FastTemplate class here, but the idea is the same for many of the available template classes. You instantiate the class, tell it where to find the template files, and tell it which template file corresponds to which page element. You generate the content for the page, perhaps by querying a database, and assign the result to an identifier. Then you parse the template files one by one and the template class performs the required substitutions for you. Finally you output the resulting string to the browser.
The key benefit is that this file is entirely PHP. There is no HTML in it. The PHP programmer can now concentrate on writing the code to generate the page content without having to worry about generating HTML to format it nicely for the final page.
You can build a whole site using this technique and just these files. If the code that generates the page content does so on the basis of a query string in the URL, you could build a magazine, for example, using a URL like http://www.foo.com/example.php?article=099
On the face of it, it looks like we have a second benefit too. In the example, the left-hand navigation bar is in its own file. We can change how it looks on every page on our site by editing this one template file.

Avoiding Duplication of Repeated Elements

"That's great", you might think. "I have a site full of largely static pages. Now I can remove all the common elements from all my pages, which were a real pain to keep updated, and using templates I can generate an easily maintainable common layout". Not so fast. That phrase "largely static" is a problem.
Consider the example above. There is in fact only one page, example.php. The reason it can generate a whole site is that it uses information in the URL to construct the page dynamically, from information in a database.
Many of us do not run completely database-backed sites. We have sites composed of many pages of static content, and we use PHP here and there to add some functionality -- a search engine perhaps, or a feedback form. How to apply templates to such a site?
The simple solution is to duplicate the PHP file above for each page, and to set the content variable to the right page content in each one. For example, if I had three pages; home, about and products, I might generate them with three files that each looked like this:

<?php

  
// home.php
  
require('class.FastTemplate.php');
  
$tpl = new FastTemplate('.');
  
$tpl->define( array( 'main' => 'main.htm',
                       
'header' => 'header.htm',
                       
'leftnav' => 'leftnav.htm' ) );

  
$content "<p>Welcome to my web site.</p>
              <img src=\"demo.jpg\">
              <p>I hope you like it.</p>"
;

  
$tpl->assign('CONTENT'$content);
  
$tpl->parse('HEADER''header');
  
$tpl->parse('LEFTNAV''leftnav');
  
$tpl->parse('MAIN''main');
  
$tpl->FastPrint('MAIN');

?>
There are three obvious problems with this: we have to duplicate this complex template-related PHP code on every page, which is just as un-maintainable as duplicating the common HTML elements; the file now has HTML mixed in with the PHP again; and generating the content variable is going to be tedious because we are going to have to escape special characters.
The key to solving the problem is to address the mixing of PHP and HTML, not by removing the HTML from this file, but by removing most of the PHP.

A Template Framework for Static Sites

First, we write template files like the ones above for all the common elements of our pages, and the overall page layout. We remove all the common elements from our page files, leaving just the page content. Then we add three lines of PHP to each page, like this:

<?php

<!-- home.php -->
<?
php require('prepend.php'); ?>
<?php pageStart
('Home'); ?>

<h1>Hello World</h1>
<p>Welcome to my web site.</p>
<img src="demo.jpg" alt="demo image">
<p>I hope you like it.</p>

<?php pageFinish(); ?>

?>
This has largely addressed the problems. There are just three lines of PHP in the file, none of which contain any template-related code and are thus never likely to need changing. And the HTML is outside the PHP tags and thus does not need special characters escaping. We can easily add these three lines of PHP to all our static HTML pages.
The require function includes a PHP file which contains all the necessary template-related PHP code. The pageStart function sets up the template object (and sets a page title), and the pageFinish function parses the template and generates the output for the browser.
How is this done? Why does the HTML in this file not get sent to the browser before the pageFinish function gets called? The answer is a new feature introduced in PHP4 that allows output destined for the browser to be captured in a buffer. A look at the prepend.php file shows how this works:

<?php

require('class.FastTemplate.php');

function 
pageStart($title '') {
  GLOBAL 
$tpl;
  
$tpl = new FastTemplate('.');
  
$tpl->define( array( 'main' => 'main.htm',
                       
'header' => 'header.htm',
                       
'leftnav' => 'leftnav.htm' ) );
  
$tpl->assign('TITLE'$title);
  
ob_start();
}

function 
pageFinish() {
  GLOBAL 
$tpl;
  
$content ob_get_contents();
  
ob_end_clean();
  
$tpl->assign('CONTENT'$content);
  
$tpl->parse('HEADER''header');
  
$tpl->parse('LEFTNAV''leftnav');
  
$tpl->parse('MAIN''main');
  
$tpl->FastPrint('MAIN');
}

?>
The pageStart function instantiates a template and sets it up, then turns on output buffering. Now, all HTML from the page itself is captured in the buffer. The pageFinish function extracts the buffered content and uses it to define the template object's content before parsing the templates and outputting the finished page.
pageStart flow chart
That's it. Write template files containing HTML fragments to define your site's common elements. Delete all the common page layout stuff from all your pages and replace with three lines of PHP you will never need to change. Put the FastTemplate class file and the prepend PHP file in your include path. Now you have a web site where the page layout is centrally controlled, enhancing reliability and maintainability and making site-wide changes easy.

Resources

Zipped archive of the files in this article, including a working example site and with more comments in the code than shown here.
The FastTemplate class can be found at http://www.thewebmasters.net/. The latest version is 1.1.0 and there is a small patch to apply to ensure correct operation with PHP4. Alternatively, the zipped archive above includes the class already patched.

Acknowledgments

The functions in prepend.php are based on ones (without output buffering) described in "Professional PHP Programming" by Harish Rawat, et al.
-- Matthew