An HTML-Friendly Template System using PHP’s Output Buffering

Template systems are an important component of today’s websites. Most of them are designed so that you have to include single splitted header and footer templates into every page. Let’s see whether we can create a template system that does not destroy the natural markup structure of the surrounding HTML at the top and the bottom of a web page.

Tutorial Details

  • Program: PHP
  • Difficulty: intermediate
  • Source : Download

The Problem

If you want to use a template engine you can choose from many mature and feature rich solutions. Nevertheless there is one thing most of them have in common: It’s their basic concept of including one template into another.

{include file="header.tpl"}
Display user profile here.
{include file="footer.tpl"}

The above example in Smarty includes a header file, then displays the content for the current page and at last includes a footer. Now imagine the contents of both included templates. In a very abstract scenario they could look like this:

header.tpl:
<html>
    <body>
 
footer.tpl:
    </body>
</html>

In a real-world example both files always contain much more markup code and often when you want to change the header you also have to change the footer.

This becomes a pain if you have them in two editor tabs and must look where to insert the appropriate ending tag and so forth. Therefore it would be nice if we could have complete markup trees. HTML code that belongs together should be found in one and the same file. Hence the template structure and template management are cleaner and easier.

The Idea

Those of you who have ever worked with Django are likely to be familiar with the concept of extending templates. This is exactly what we want to achieve in PHP now. Just look at the following template code:

main.tpl:
<html>
    <head>
        <title>{ begin "title" }Default title{ end "title" }</title>
    </head>
    <body>
        { begin "content" }
        This is some default content.
        { end "content" }
    </body>
</html>

We have a beautiful unshattered piece of HTML code. It contains some Smarty-like template code defining two extendable or overwritable parts in our template.

sub.tpl:
{ extend "main.tpl" }
{ begin "title" }My sub-template{ end "title" }
{ begin "content" }
<p>
    My sub-template content.
</p>
{ end "content" }

Above you see the extending template “sub.tpl”. What happens now if we load “sub.tpl” and display it is, that all begin/end blocks are parsed separately. Then they are inserted into “main.tpl” at the appropriate positions. Please note that we now have two template files that contain clean HTML markup trees instead of three files with divided HTML elements.

As a side effect we can define parts of the template that are displayed by default. If we omit one section in a sub template the default content of the master template
is used.

So if we use such a template system there are several benefits:

  • We don’t break HTML structure.
  • We can access the specific template file we need without any detours.
  • We can setup a structure of templates extending each other. (So to say OOP templates ;) )

The Implementation

Now that you know what this is all about we can think of a small example implementation. I’ll be using PHP as the template language (since I wonder why people write language parsers in a perfect template language itself…) and the output buffering functions to implement it as fast and slim as possible.

Let’s define how we want to access our templates. I think something like this should be fine:

$template = new Template( 'sub.php' );
$template->display();

So we need a constructor that takes the filename of the template and a method that brings the template to standard output. Also a constant that defines the path to the folder containing our templates and a method called “build” returning the template content as a string would be nice.

class Template
{
 
    const DIRECTORY = './templates';
 
    protected $path;
 
    public function __construct( $name )
    {
 
        $this->path = sprintf( '%s/%s', self::DIRECTORY, $name );
 
    }
 
    public function build();
 
    public function display()
    {
 
        echo $this->build();
 
    }
 
}

As the next step we need the method “extend”. It has to load anotoher template and save it until we’ll access it again in the “display” method.

protected $extendedTemplate = null;
 
public function extend( $name )
{
 
    $this->extendedTemplate = new Template( $name );
 
}

Next we can implement the methods needed for extension templates. The method “start” will set a variable with the name of the section and start output buffering.

protected $sections = array();
protected $currentSection = null;
 
public function begin( $sectionName )
{
 
    ob_start(); // start output buffering
    $this->currentSection = $sectionName;
 
}

When looking at “end” we have to distinguish between two cases: If $this->extendedTemplate has a valid value the method has to save the section content into an array, mapped to the section name. Otherwise the current template is a master template. Then the method shall output either section contents that were set by a sub template or (if not existant) output the buffer data which represents the default section
content. Please note that we won’t use an argument in the “end” method. This would only be necessary for error checking or if we wanted to implement nested sections. Both things are quite useful but are not part of this tutorial. Needless to say you are invited to practice your PHP skills and implement this stuff later. :-)

public function end()
{
 
    if ( !is_null( $this->extendedTemplate ) )
    { // current one is a sub template
 
        // read buffer contents and drop them
        $this->sections[ $this->currentSection ] = ob_get_clean();
 
    }
    else
    { // current one is a master template
 
        if ( isset( $this->sections[ $this->currentSection ] ) )
        {
 
            ob_end_clean(); // drop default content
            echo $this->sections[ $this->currentSection ];
 
        }
        else
        {
 
            // output buffered data and drop buffer
            echo ob_get_clean();
 
        }
 
    }
 
}
 
// will be called from "build" later
public function setSections( $sections )
{
 
    $this->sections = $sections;
 
}

Now the most important part: the build method. Note that we load the PHP template only when “build” is called. So everything we have coded until now is executed in the template files on the fly. Thus it might be a bit hard to understand what’s going on here. B

At the end of this tutorial I want to list some

ut if you follow the order of method calls carefully you’ll get it.

public function build()
{
 
    // start output buffering
    ob_start();
 
    // just include the template file (some error checking would be nice)
    include $this->path;
 
    // Now our "extend", "begin" and "end" methods can be called from the template
    // using $this: $this->extend(), $this->begin() and so on...
    // We can't do anything here, just wait until the template is included
    // Note that we capture the HTML output with the output buffering.
 
    // get our buffered data
    $output = ob_get_clean();
 
    // Now we can check what we've got.
    if ( !is_null( $this->extendedTemplate ) )
    { // we have a sub template, go on with the master template
 
        // Since a master template is set, the "end" method has captured the contents
        // of the template sections. Now we have to provide the master template our
        // data.
 
        $this->extendedTemplate->setSections( $this->sections );
 
        // Now just display the master template.
        return $this->extendedTemplate->display();
 
    }
    else
    { // we have a master template, nothing more to do here
 
        return $output;
        // Since in a master template the "end" method outputs either the default
        // content or the extended data of a section our HTML output is complete.
 
    }
 
}

And that’s all the magic going on. Let’s implement the example from the second part of this tutorial using our new class. Be careful with those “

main.php:
<html>
    <head>
        <title><? $this->begin( 'title' ) ?>Default title<? $this->end() ?></title>
    </head>
    <body>
        <? $this->begin( 'content' ) ?>
        This is some default content.
        <? $this->end() ?>
    </body>
</html>
sub.php:
<? $this->extend( 'main.php' ) ?>
<? $this->begin( 'title' ) ?>My sub-template<? $this->end() ?>
<? $this->begin( 'content' ) ?>
<p>
    My sub-template content.
</p>
<? $this->end() ?>

That’s it. Note that this class is not complete at all. For instance, it has no variable handling and it is also only capable of loading one sub template and one master. (If you change it in a way that the section contents provided by a sub template are saved in a separate variable than in the array containing the own sections you can also extend extended templates…)

Nevertheless, I hope this tutorial has shown you a nice but rare concept among template engines and some interesting aspects of PHP’s output buffering functionality.


6

Comments

Discuss This Post on the ThemeForest Forums