Templating with PHP

There are two main ways to create templates with PHP.

Header/Footer Files

First, design a one-page static layout for your site. You should come up with something like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
    <title>Untitled</title>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
    <meta name="keywords" content="" />
    <meta name="description" content="" />
    <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
    <link rel="stylesheet" type="text/css" href="/style.css" />
</head>
<body>
<div id="page-wrap">
    <ul id="navbar">
        <li><a href="first-link">First Page</a></li>
        <li><a href="second-link">Second Page</a></li>
    </ul>
    <div id="main-area">
        <a id="logo" href="/"></a>
        <div id="content-container">
            <div id="content-body">
                PAGE-CONTENT-HERE
            </div>
        </div>
    </div>
    <div id="footer">
        <p>yoursite.com &copy; <?=date('Y')?> | <a href="/privacy-policy">Privacy Policy</a></p>
    </div>
</div>
</body>
</html>

Now, take everything above “PAGE-CONTENT-HERE” and throw it in a file like “header.inc.php”. Take the bottom half and put it in “footer.inc.php”. Now for each page, you can do something like this:

<?php
include 'header.inc.php';
echo <<<HTML
<h2>Page Title</h2>

<p>Page content.</p>
HTML
;
include 'footer.inc.php';
?>

Now, if you ever want to change the appearance of your site, you just need to edit your header or footer files!

The advantage of this method is that you can put PHP scripts before you include the header, or make special pages different by using a different header/footer.

Include Method

For this method, you can use the same page layout as above (save it as index.php), but replace PAGE-CONTENT-HERE with something like this:

<?php
include $_GET['p'].'.php';
?>

And then make all your links like <a href="/?p=mypage">. You have to very careful if you use this method though, because malicious users can include whatever they want into your layout! Imagine what would happen if they went to “yoursite.com/?p=index” for example (you’d have a page inside a page inside a page…). Or ?p=http://malicioususer.com/evilscript.

The advantage of using this method is that you don’t have to include a header and footer in each one of your content pages, but you get less flexibility over the layout of your site for special pages.

The Hybrid Method

This method gives you the best of both worlds, although it is perhaps ever so slightly more processor intensive. For this method, you will need create a .htaccess file like this:

RewriteEngine on

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* /?p=$0

Well, I guess you don’t really need to, but it will make your URLs prettier (no file extensions).

Then create an index.php file like this:

<?php
define('DS', DIRECTORY_SEPARATOR);
define('ROOT', dirname(__FILE__));
define('PAGES', ROOT.DS.'pages'.DS);
define('LAYOUTS', ROOT.DS.'layouts'.DS);
define('PHP', '.php');

$pageLayout = 'default';

if(empty($_GET['p'])) $page = 'home';
else $page = $_GET['p'];

if(file_exists(PAGES.$page.PHP)) {
    $pageTitle = ucwords($page);
} else {
    header("HTTP/1.0 404 Not Found");
    $page = '404';
    $pageTitle = '404 - Page Not Found';
}

ob_start();
include PAGES.$page.PHP;
$pageContent = ob_get_clean();
include LAYOUTS.$pageLayout.PHP;

You probably won’t need to edit that at all unless you want to change a few default settings. Then create two folders, “layouts” and “pages”.

In the layouts folder, create a default layout called “default.php”. Something like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
    <title><?=$pageTitle?> - Your Site</title>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
    <meta name="keywords" content="" />
    <meta name="description" content="" />
    <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
    <link rel="stylesheet" type="text/css" href="/style.css" />
    <?=$pageScripts?>
</head>
<body>
<div id="page-wrap">
    <ul id="navbar">
        <li><a href="first-link">First Page</a></li>
        <li><a href="second-link">Second Page</a></li>
    </ul>
    <div id="main-area">
        <a id="logo" href="/"></a>
        <div id="content-container">
            <div id="content-body">
                <?=$pageContent?>
            </div>
        </div>
    </div>
    <div id="footer">
        <p>yoursite.com &copy; <?=date('Y')?> | <a href="/privacy-policy">Privacy Policy</a></p>
    </div>
</div>
</body>
</html>

Notice the usage of variables $pageContent, $pageScripts, and $pageTitle. You can set the $pageTitle and $pageScripts within the page. $pageContent is where your content will appear in the layout. There is also one more variable you can set, $pageLayout, which you can set to use a layout other than the default one.

Now your page URLs will look something like “yoursite.com/page” with no file extension. You shouldn’t have to worry too much about evil users including bad files because they can only include stuff within the “pages” folder. You can also still access all your other files directly, by using the full URL with extension.

Oh, also make sure you have a file called “404.php” within the “pages” folder, or bad things might happen :) This is the file that will get called if no page could be found. It uses the layout too.

I think that’s everything… so happy templating!

XHTML 1.0 Strict Template

Just a little template I like to use every time I create a new HTML page. The DOCTYPE does make a difference as to how the page is rendered.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Untitled</title>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
    <meta name="Keywords" content="" />
    <meta name="Description" content="" />
    <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
    <link rel="stylesheet" type="text/css" href="/style.css" />
</head>
<body>

</body>
</html>

Edit: And here’s a 1.1 template. Ready for Django flatpages, but easily modifyable.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
    <title>{{ flatpage.title }}</title>
        <link rel="stylesheet" type="text/css" href="/media/css/style.css" />
</head>
<body>
    <h1>{{ flatpage.title }}</h1>
    {{ flatpage.content }}
</body>
</html>