Documentation

Table Of Contents

Installation

Just include phpTemplateInheritance.php somehow. Code Igniter users can drop it into their helpers - dir and make sure that it gets loaded (via autoload or manually).

Configuration

If you are using Code Igniter, you shouldn't have to do anything.

Otherwise you'll have to define a TI_VIEWS_DIR constant, like

define ('TI_VIEWS_DIR', 'views/');

which should be a path where PHP can find your view files. You can make it relative to the current PHP working dir or absolute, it shouldn't matter.

If you don't do this, you'll have add the correct path to your files to your extend() calls.

Quick Tutorial

Imagine you have a website with the same basic structure on every page. Something like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>
        Dan's Music Store
    </title>
    <link rel="stylesheet" href="css/base.css" type="text/css" media="all" />
</head>
<body id="body">
    <div id="container">
        <!-- Content goes here -->
    </div> <!-- container -->
</body>
</html>

Then you might have different subpages which actually use the same basic structure.

Now you can use PHP to include separate files for every area of that template, but I always felt like this was a suboptimal solution.

So the idea is this: Let's put some kind of markers into the base template which can be extended from child templates. We'll call it main_template.php. An example could look like this:

main_template.php:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>

        <? start_block_marker('title') ?>
            Dan's Music Store
        <? end_block_marker() ?>

    </title>

    <? start_block_marker('extra_head') ?>
        <link rel="stylesheet" href="css/base.css" type="text/css" media="all" />
    <? end_block_marker() ?>

</head>
<body id="body">
    <div id="container">

        <? start_block_marker('content') ?>
            <h1>Welcome to the Dan's Music Store</h1>
            <p>Instruments from all over the world</p>
        <? end_block_marker() ?>

    </div> <!-- container -->
</body>
</html>

If you'd include just this, essentially you would get the same output as in the first example, because no special block content has been assigned yet. We only added some "Markers" which we can fill from within child templates.

To use this file as a base template for different content, you have to use the extend() function and start overriding the blocks of the base template. Let's call this one guitars.php. It will be a section template which includes some extra content for the guitar section of our music store.

guitars.php:

<? extend('main_template.php') ?>

    <? startblock('title') ?>
        <?= get_extended_block() ?>
        - Guitars
    <? endblock() ?>

    <? startblock('extra_head') ?>
        <?= get_extended_block() ?>
        <link rel="stylesheet" href="css/guitars.css" type="text/css" media="all" />
    <? endblock() ?>

    <? startblock('content') ?>
        <h2>Look around!</h2>
        <p>Such a fine selection of Guitars!</p>
    <? endblock() ?>

<? end_extend() ?>

With extend("filename"), you tell this template which base template it should extend. You need to wrap this file up with a call to end_extend() to make the magic work.

You can call get_extended_block() to inherit / receive the content of the parent block, which is useful for adding additional data to the base template.

In this example it's used to add a second part to the <title> - tag and to add an additional stylesheet.

Now we would include guitars.php instead of main_template.php.

The output would look like this (I fixed the indentation a little):

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>

        Dan's Music Store
        - Guitars

    </title>

                <link rel="stylesheet" href="css/base.css" type="text/css" media="all" />
            <link rel="stylesheet" href="css/guitars.css" type="text/css" media="all" />

</head>

<body id="body">
    <div id="container">

                <h2>Look around!</h2>
        <p>Such a fine selection of Guitars!</p>

    </div> <!-- container -->
</body>
</html>

So now we have the extra content for the title and the head. The body has been overwritten by the content of guitars.php.

Then we need a page where we display the specific guitars. We'll create a file destroyer_guitar.php. It will extend the guitar.php - file. Of course the contents of this file will probably be dynamic in your case and not only a file for a specific guitar, but this is an example, mkaaaaay?

destroyer_guitar.php:

<? extend('guitars.php') ?>

    <? startblock('title'); ?>
        <? get_extended_block() ?>
        - Destroyer ZX80
    <? endblock() ?>

    <? startblock('content') ?>
        <h1>Destroyer ZX80</h1>
        <p>A most excellent heavy metal Axe.</p>
        <p>Available in the following sizes:</p>
        <ul>
            <li>Small</li>
            <li>Large</li>
            <li>Troll</li>
        </ul>
    <? endblock() ?>

<? end_extend() ?>

So here we once more replace the content with something different. The content - data will overwrite the content from guitars.php and main_content.php. If we wanted to preserve it, we could have left the content block out or could have inserted get_extended_block() somewhere. Then the content from guitars.php would appear in that spot in the main template.

We did this for the title - block, which inherits the data from the base templates.

If we would include destroyer_guitar.php now instead of main_template.php or guitars.php, the output would look like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>

        Dan's Music Store
        - Guitars
        - Destroyer ZX80

    </title>

                <link rel="stylesheet" href="css/base.css" type="text/css" media="all" />
            <link rel="stylesheet" href="css/guitars.css" type="text/css" media="all" />

</head>
<body id="body">

    <div id="container">

                <h1>Destroyer ZX80</h1>
        <p>A most excellent heavy metal Axe.</p>
        <p>Available in the following sizes:</p>
        <ul>
            <li>Small</li>

            <li>Large</li>
            <li>Troll</li>
        </ul>

    </div> <!-- container -->
</body>
</html>

... now isn't that just beautiful? :)

Caveat Emptor (Please Read This!)

1. Performance and logical Issues

EVERY block within the inheritance hierarchy will be executed ONCE - wether its contents will be used or not.

That means that if some base template block contains anything, it will always be executed, whether its output will be used or not.

If this calculation would be too expensive or the rendering would cause side effects, like changing variables other blocks use, there is a function you can call to check if the current block's content is required or if it only will be overwritten by child templates anyways. Call block_rendering_neccessary() to check that the block you're currently crafting is really required.

<? startblock('weather') ?>
    <? if (block_rendering_neccessary()): ?>
        <?php simulate_global_warming_effects() ?>
    <? endif; ?>
<? endblock() ?>

2. Don't Cross The Streams

This is a (potential) work - in - progress and really a hack. You may encounter strange errors if you mix up the markers or forget the end_extend(). Please also be careful not to embed one top-level block inside another like this:

WRONG:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <? start_block_marker('head') ?>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>

            <? start_block_marker('title') ?>
                Dan's Music Store
            <? end_block_marker() ?>

        </title>

        <? start_block_marker('extra_head') ?>
            <link rel="stylesheet" href="css/base.css" type="text/css" media="all" />
        <? end_block_marker() ?>

    <? end_block_marker('head') ?>
</head>
<body id="body">
    <div id="container">

        <? start_block_marker('content') ?>
            <h1>Welcome to the Dan's Music Store</h1>
            <p>Instruments from all over the world</p>
        <? end_block_marker() ?>

    </div> <!-- container -->
</body>
</html>

Can you spot the error?

The calls to start_block_marker("title") and start_block_marker("extra_head") are the problem here, because there's another block marker around them ( start_block_marker("head") ). This will (currently) lead to strange errors (you'll notice, believe me). I hope that I'll be able to add some error checking to PHP Template Inheritance one day.

Further Reading

You could also check django's template inheritance documentation for another example. Django's template inheritance was my inspiration - actually I pretty much copied its functionality. I hope they don't mind.

Django Template Inheritance Documentation