Tuesday, September 24, 2013

Bringing PHP Templates to MojoMotor

Recently, one of my clients added a site that leverages MojoMotor (MM) to the list of assets that I now help maintain and improve. MM has an almost Perch like philosophy about being a CMS: it's all about being as lightweight as possible. And to the credit folks behind MM, they have managed to put together a lean system.

MM uses a sort of tag based markup language to power its templates. While handy for simple tasks, I vastly prefer using PHP as a template language, rather than something ad hoc. Luckily, MojoMotor is easily extendable and in about 40 lines of code, I had a full PHP based template engine running within MojoMotor.

Now, a MM layout can contain code like:

     {mojo:snippet:apply path="assets/js" src="foo.js"}

Which invokes snippets/assets/js.php and sets $src to the value foo.js. Within that file, I may have:

   * Render a javascript include
  $xcache = calculate_our_cache_busting_value();
  $should_mini = should_mini_files();
  $src = $should_mini ? "/assets/mini/$src" : "/assets/full/$src";
<script src="<?= $src ?>?xcache=<?=$xcache?>"

Using this tiny function, it's possible to invoke one snippet (PHP template) from within another, making for easy abstractions.

To implement this in MM, I created the following directory structure:

system/mojomotor/third_party/snippet/index.html   (an empty file)

Inside of snippet.php is this hunk of PHP code:

<?php if (!defined('BASEPATH')) exit('No direct script access allowed');

/* CHANGE ME: At the top level of the source tree.  */
define('SNIPPET_BASE_DIR', dirname(__FILE__) . '/../../../../../snippets');

 * Snippets are small chunks of HTML code that are
 * imported and evaluated on the fly.
class Snippet {

  public function apply($template_data) {
    $_path = $template_data['parameters']['path'];

    if(!$_path) {
      return "Snippet error: no path param";
    if(!file_exists(SNIPPET_BASE_DIR . "/$_path.php")) {
      return "Snippet error: not found: $_path";

    $body = $template_data['tag_contents'];  

    require(SNIPPET_BASE_DIR . "/$_path.php");
    $content = ob_get_clean();

    return $content;

I'm sure there are optimizations to made (add caching of snippets, perhaps?), but as a quick and easy way to add a lot of power (and abstraction) to your templates, this approach is hard to beat.

No comments:

Post a Comment