SPUDSTALKER

Offline Templating

Table of Contents

  1. Note – Deprecated
  2. Introduction
  3. Premise
  4. Idea
  5. Steps
  6. Specifics
    1. Code – Explained Briefly
  7. Conclusion

Note – Deprecated

This method is no longer used for this site, and is provided here for educational purposes, or possibly for somebody to use if it fits their needs adequately.

This page is provided for posterity, and the general premise is much the same, simply making use of flat files and a less sucky scripting language.

Introduction

When we think of things like templating engines and scripting languages, we often think of a severely overtaxed "budget" server running a full LAMP stack just to serve up some static XHTML.

Let's face it, for things like a personal website, having your server perform the same mundane task of splicing together some HTML fragments into a page (that won't change that often) and sending it to the client is a little ridiculous.

Premise

However, if that was ridiculous, so is the act of editing several files just to change one link in your navigation bar.

The positives outweigh the negatives in this case... it's always a lot easier to deal with something like a templating engine rather than dealing with raw HTML/XHTML on its own.

Applications like WordPress or any other CMS aside, a simple templating engine is a must when managing any site you take marginally seriously.

For instance, Smarty is a lightweight, easy to use, and easy to implement piece of PHP code which makes mundane website maintenance a hell of a lot easier.

But, do you really want to install a full LAMP stack on your server, and have it perform the steps necessary to apply the templates to your pages every time somebody accesses your site? Even barring things like caching, which helps a lot, there's still the issue of simplicity and security. Why install more than necessary when all you want to do is put up a personal website which you will change sparsely and without user-generated content?

It stands to reason, that you could do away with the templating engine and object storage schema on your server, and offload that workload to your personal computer. You could then "compile" your websites, and upload simple static HTML/XHTML to your server, which then simply requires any number of small, fast, and secure HTTPD's to serve your content.

The Idea

Of course, the idea isn't new. Most HTML editors/IDE's support "templates" in the easiest sense of the word. Some good ones even approach the idea of a "one-click" compilation of a website with a changing template and page objects.

As the "old-soul" (yeah right, fuck off they say...) I am, I've never been much for IDE's, and have NEVER been much for WYSIWYG editors and "IDE's" like DreamWeaver/Bluegriffon/insert-your-project-here. Ever since I first put this website up, in high school, I edited my pages in a plain-old text editor (I hadn't unlocked the sorcery of vim yet, so I used things like notepad++/geany). As I started to get interested in PHP, I still used my handy-dandy text-editor and raster graphics editor instead of an overly-complicated IDE.

So, rather than search for a pre-made solution, I realized that the concept I had in mind for website "compilation" wasn't that computationally difficult, and, in fact, only required a handful of lines of code.

Rather than writing a "program" to do this, I simply used the scripting languages already installed on my PC: batch scripting for file copying/folder creation, and PHP for the actual "templating" and saving complete XHTML pages.

So, here's the...

Steps

  1. First, you will need PHP installed on your computer. Get it here, or use your package manager. If compiled or simply extracted, make sure to add the binary path to your local PATH variable.
    1. If you are proficient in another scripting language which has another templating engine rather than Smarty, for instance, Python with Django, use that instead, and the steps will only be marginally different.
  2. I will not go into the specifics of setting up Smarty to work with your script. Smarty already has excellent documentation on that.
  3. Set up a database to hold your pages.
    1. You can use any schema available to your scripting language, or even use something like Access and OBDC if available.
    2. I myself use SQLite3. It's public domain software and has libraries for almost every programming and scripting language there is.
    3. Use a separate management tool for editing the database. If you're using MySQL or similar, you can use phpMyAdmin in a local development environment.
  4. Write the script. It's really trivial to loop through the page table of your database and generate a page which can be saved to disk.

Specifics

Now that we got those exceedingly vague instructions out of the way, here's a little more in-depth discussion on how I did it.

First off, having PHP installed and configured, as well as added to the path variable, was simple enough.

Now, it's time to setup your database of pages. You can set up your database however you need to, in order to provide the functionality you would like. I started with something simple enough...

Basic database setup

Most of the fields are obvious. "slug" is the name of the file to output, without the .html extension. "title" is obviously the title of the page, "content" is the content, "objects" is what to include in the page, defaulting to the "main" navigation bit of HTML.

Now, it's time to write a script, using smarty, to loop through this table and format the information using Smarty, saving the output.

Code – Explained Briefly

Include the configuration file and smarty libraries, and initialize some smarty settings.

The configuration file contains the baseurl and a string to include in links to highlight them if they reference the active page.

<?PHP
  require("./smarty/Smarty.class.php");
  require("config.inc.php");
  $smarty=new Smarty();
  $smarty->caching=0;
  $smarty->setTemplateDir("./smarty/light");
  $smarty->setCompileDir(
    "./smarty/light/compile");

Connect to the database. This can be MySQL as well, without too many changes here. If you are adapting this script to server-side use, make sure you are sanitizing your inputs correctly, and also realize there are much better scripts to use in this context.

  $db=new SQLite3("./res/pages.sqlite");
  $st=$db->prepare("SELECT * FROM pages");
  $r=$st->execute();

Then, start the main program loop.

  while($rr=$r->fetchArray()) {

Now, for each iteration of this loop, we are operating on a single "page". First thing to do is handle includes on that page, things like the menu, and any other HTML "snippets" that should be included.

So, explode the "objects" field at commas, and loop through that array first.

For each requested "object", assign a smarty variable with the name of the requested object.

    $objects=explode(",",$rr["objects"]);
    foreach($objects as $object) {
      $st2=$db->prepare("SELECT * FROM pages WHERE ".
        "slug=:slug LIMIT 1");
      $st2->bindValue(':slug',$object,SQLITE3_TEXT);
      $r2=$st2->execute();
      $rr2=$r2->fetchArray();
      $smarty->assign($object,$rr2["content"]);
    }

Now, we will assign the rest of the per-page smarty variables, and fetch the page into the variable page.

The reason I do this instead of simply echoing the results is to enable other filters instead of just smarty. For instance, I use PHP's built-in "str_ireplace()" function to render smilies in the complete script I use for this site.

The htstr variable is a little snippet I include to highlight links to the active page. Both this and the baseurl variable are included in the configuration file.

    $smarty->assign("baseurl",$baseurl);
    $smarty->assign("page_title",$rr["title"]);
    $smarty->assign("page_content",$rr["content"]);
    $smarty->assign("page_author",$rr["author"]);
    $smarty->assign("page_mod",date("D dMY",
    $rr["modified"])." at ".
      date("Hi",$rr["modified"]));
    $smarty->assign($rr["slug"]."hl",$hlstr);
    $page=$smarty->fetch("index.html");

Finally, if the write field is enabled, write the file to the build directory. This field should be disabled for things like menus and included HTML snippets... in other words, incomplete pages.

Clear the assigned variables and compiled templates before running through the main loop again.

    if($rr["write"]==1) {
      file_put_contents("./build/".$rr["slug"].
        ".html",$page);
    }
    $smarty->clearCompiledTemplate();
    $smarty->clearAllAssign();
  }

The creation of the build directory and copying of the images and other files is handled by a simple shell script...

The "rm -rf build" can be eliminated if you would rather handle the build directory yourself.

#!/bin/bash
rm -rf build
mkdir build
cp -r ./res/images ./build
cp -r ./res/external ./build
php build.php
rm build/main.html
rmdir smarty/light/compile

Conclusion

This may have been tough to follow, and that's halfway the point. This page was not designed to be a "how-to", merely an eye-opener, and an invitation for you to come up with your own method of doing something which is really a good idea in most cases.

Who knows, maybe in a few months, I'll be downloading your script to do all of this without the headache.