A simple PHP HTML/CSS templating system (REDUX)

It is beyond silly to repeatedly copy and paste the same HTML into the top and bottom of every HTML file that you create. That’s why god invented include() but, the humble header/footer HTML include file needs to be extended slightly - that is, unless you want all your pages to have the same title/meta description/CSS files etc.

A while ago I wrote about my PHP-based HTML template system. It has since been rewritten to make better use of PHP5’s object oriented approach and here it is:

My template structure is as follows

  • a basic HTML page - aka the View in the Model-View-Controller (MVC) approach
  • a header HTML includes file - /templates/header.php
  • a footer HTML include files - /templates/footer.php
  • a simple template class - /class/template.class.php

The page (view)

  1. <?php
  2. require_once($_SERVER['DOCUMENT_ROOT'].'/class/template.class.php');
  3. // Initialise template object
  4. $objTemplate = new Template();
  5. // SEO
  6. $objTemplate->setTitle($objTemplate->site_name);
  7. $objTemplate->setDescription("This is the page's meta description.");
  8. // CSS
  9. $objTemplate->setStyle(array('home','forms'));
  10. $objTemplate->setExtraStyle('p.example{color:red;}');
  11. // JavaScript
  12. $objTemplate->setBehaviour(array('jquery'));
  13. $objTemplate->setExtraBehaviour("$(document).ready(function(){$('#paragraph').addClass('example');});");
  14. // Header HTML file
  15. include($objTemplate->header_file);
  16. ?>
  17. <p id="paragraph">Page content goes here</p>
  18. <?php include($objTemplate->footer_file); ?>

Download page file

The idea here is to minimise the amount of repetitive code.

This page could be index.php, about.php or anything. If you’re using PHP’s autoload function you can skip the require_once($_SERVER['DOCUMENT_ROOT'].'/class/template.class.php');
line. You may have a universal initialisation file/class that is automatically included at the top of each page/view and in that you could add the line $objTemplate = new Template(); which would reduce your code size again.

The header

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml"<?=$objTemplate->language?>>
  3. <head>
  4. <?=$objTemplate->charset?>
  5. <title><?=$objTemplate->title?></title>
  6. <?=$objTemplate->description?>
  7. <?=$objTemplate->style?>
  8. <?=$objTemplate->robots?>
  9. <link rel="Shortcut Icon" href="/favicon.ico" type="image/x-icon" />
  10. </head>
  11. <body id="<?=$objTemplate->body_id?>">

Download header file

If this were a flat include file, it would be difficult to alter the <title> and other values in this file. In this approach, it is very easy to set the correct values via the page/view, meaning this file never needs touching by your pesky front-end developers again - in theory.

The footer

  1. <div id="footer">
  2. <div id="copyright">
  3. &copy; <?=date('Y')?> <?=$objTemplate->site_name?>
  4. </div>
  5. </div>
  6. <?=$objTemplate->behaviour?>
  7. </body>
  8. </html>

Download footer file

The class

  1. <?php
  2.  
  3. class Template{
  4.  
  5. public $site_name;
  6.  
  7. public function __construct(){
  8. $this->site_name = 'Amazing website';
  9. $this->setTitle();
  10. }
  11.  
  12. public function setTitle($value = false){
  13. $this->title = ($value) ? $value : $this->site_name;
  14. }
  15.  
  16. }
  17.  
  18.  
  19. ?>

For brevity’s sake, the majority template class code has been omitted from above, leaving only this simple example of how the title is created.

Download the (full) template class file

OO advantages

In my first template code, I used a function-based (procedural) approach with lots of separate includes file for elements such as CSS. It was good but this approach has a few distinct advantages.

  • It is hopefully easier to read and follow for someone with less PHP experience
  • You can create a subclass for sections in your site that need a different appearance e.g. and set a different header file to be included.
  • All the options could excluded e.g. setTitle(), setStyle() and the page would still work great.

Disclaimer

This template is quite simplistic, and I use it mostyly when creating HTML/CSS templates for people from Photoshop designs. In more demanding scenarios, I have a more complex template class which checks whether I’m in production mode, local mode, test mode, etc and acts accordingly. This may mean putting all the CSS and/or JavaScript into one file and compressing the filesize. It may mean adding a Google Analytics script at the bottom of the page on the live server.

Another question, you may be asking is, ‘Why not just use Smarty or similar?‘ Well the answer to that, is because I think they make the situation more complicated than it needs to be. My solution saves me time and when I pass my HTML templates onto the development team, it often saves them time too.

What do you think?

Is the code ugly? Is your PHP HTML/CSS templating system much better? Do you prefer a smarty approach?

I’d like to know.

Share and Enjoy

These icons link to social bookmarking sites where readers can share and discover new web pages.

Tags:

Responses

There have been 16 responses to A simple PHP HTML/CSS templating system (REDUX).

  1. Comment made by Andy on

    Good to see. One extra improvement could be make your setStyle expect an associative array so that you could specify the CSS media.

    Also… where are your getters?

  2. Comment made by phil on

    @Andy, that’s a good idea about the associative array. I should also modify the code so it expects a string as well because I can imagine a lot of people not thinking to use an array when specifying just one CSS file and causing an error.

  3. Comment made by will on

    Good idea, I implemented something similar to this on a site I am developing a few days ago… Not sure it is needed in all cases though.

  4. Comment made by Jimmi on

    You should look at this…

    http://www.massassi.com/php/articles/template_engines/

    The basic template class is only a few lines, and amazingly it does nested templates!

    You should consider using this as the basis for your template class.

  5. Comment made by Niobe on

    That’s awesome. I’ve used a crude method by declaring $title before the include and echo’ing the $title in the tag, but this is much more sophisticated, especially for pages that need included javascript.

  6. Comment made by phil on

    @will: Sure there will be times when this is overkill but I think they are few and far between. This is just as useful and timesaving on a website with 5 pages as it is on a site with 50.

    @Jimmi: I had a look, I like the caching feature but I think there’s too much going on in that class without enough benefit.

    @Niobe: I started very similarly to you and only improved my technique when projects warranted it.

  7. Comment made by louis w on

    Very simple and gets the job done. Good work.

    About choosing a media type for the css, I would do this:

    $objTemplate->setStyle(array(’home’,'forms’), ’screen’);
    $objTemplate->setStyle(’print’, ‘print’);

  8. Comment made by phil on

    @louis w: I like the way you think. The current class does allow a (rather clunky) way around with the setExtraStyle method e.g:

    $objTemplate->setExtraStyle(’@import url(”/style/print.css”) print;’);

    or

    $objTemplate->setExtraStyle(’@media print{ css{rule: goes-here;} }’);

    but your way is better!

  9. Comment made by DaeWoo on

    Nice work. And clean, notation as well, habit I’ve got to get into. Have you thought of using php DOM (compiled with PHP 5), I’m building a similar tmeplate system at the moment using it, which lets you insert html elements on the fly (just in case you missed something).
    Can send you a copy of the class if you want it.
    Keep up the good work.
    D

  10. Comment made by phil on

    @Daewoo: Ta for the tip. I’m not familiar with php DOM is it similar to html_element class by David Walsh

  11. This looks great. I have been searching for a good template to build my website (v2) on. I have tow questions:

    1. The code seems to work fine if I comment out –> $objTemplate->setExtraBehaviour(”$(document).ready(function(){$(’#paragraph”).addClass(’example’);});”); Any idea why?

    2. *Noob Alert* But why not just include the footer file and header file? Why go through the trouble of using OOP for a template? Like I said, noob, but I have seen it used over and over and never quite understood the benefit.

    Thanks for your time and contribution! -SP

  12. Comment made by phil on

    @Sean-Paul:

    1: There is a mistake in the code, it should be
    $objTemplate->setExtraBehaviour("$(document).ready(function(){$('#paragraph').addClass('example');});"); note the after #paragraph, I’ll fix the example.

    2: You can just include the header and the footer file and that will work great in most cases. A lot of people even include the Doctype at the top of their pages instead of putting that in a header file. The beauty of this approach is that you can suddenly switch which header file to include based upon any number of factors.

    I’ll be honest and say this OOP approach’s advantages over a procedural approach can be difficult to see and that’s because they’re not that big. The code looks nicer and OOP is flavour of the day. Using this template, you’ll hoping find updating/creating basic websites much quicker.

  13. Comment made by daewoo on

    @Phil
    Similar principles to javascript Dom (but serverside.) Basically, allows you to manipulate XML docs to W3C DOM spec.
    Have a look here http://uk3.php.net/dom.

  14. Comment made by Vinny on

    Good to see that more ppl finally start using this habit of dividing pages into included parts.

    But it was certainly not God that invented it

    It’s a good point mentioning it again. but the Idea is already SO OLD

  15. Comment made by phil on

    @Vinny: I’m confused as to what your point of view is. You seem both annoyed that this is an old topic yet pleased that it is being brought up again.

  16. Smarty++

    (But that’s just because we’ve a large stack of working / additional code based upon it)