Posted on by David

Tweaking phrozn logo front-matter

Wanting something set up fast, simple and sturdy, when we started setting up a website for tentwentyfour, we opted for phrozn, a static site generator written in PHP and inspired by similar generators like Jekyll (ruby) and Hyde (python).

Although you could probably just as easily create a website with a CMS such as WordPress, creating websites with phrozn has the benefit of generating static html pages that will load fast and definitely withstand any attempts at SQL- or code injection attacks. Also, there’s little that can break, at least in terms of server-side code, since there’s none at all (well almost none ;-) ). And deployment is kind of trivial and easy going on your hardware with no parsing taking place on your webserver.

What’s the front-matter?

Phrozn also came in handy, since it supports multiple markup processors — twig, markdown and textile for content and LESS for CSS — and it also enables you to write your own. We make use of that flexibility by using twig for the more advanced stuff and markdown where we need to get a lot of content down fast — such as these blog entries.

By default, phrozn doesn’t require you to do much configuration, hardly any actually. Running phrozn init once and then creating your entries is usually enough, but since that’s not the topic of this blog entry, please refer to the Getting Started Guide on the phrozn website, which will help get started with your first set of pages.

If you wanted to tweak your site a little further, say adding additional functionality, you’d use the so-called Front-Matter, a section defined in YAML (YAML Ain’t a Mark-up Language) syntax inside your entry files. Front-matter allows you to set some predefined parameters, but more importantly, your own custom variables.

The front-matter section constitutes the header of your respective entries and is delimited from the real content by three consecutive dashes — the standard YAML markup to separate directives from document content. If you have more than one template file for your site, you could for instance specify the one to use for this entry and create a custom variable as follows:

layout: fancy.twig
author: david
---

When calling phr up on your files, phrozn will make the author variable available in the fancy.twig file as entry.author, allowing you to use that data — for instance in your meta data — like so:


<html>
    <head>
        <meta name="author" content="{{ entry.author }}">

This allows you to actually use the templating capabilities of twig where you would probably only have used the {{ content }} variable and {% block footer %} functionality if you’re working template inheritance. But this is where it becomes really interesting: while the phrozn documentation states that the front-matter is to be written as YAML and that you can use it for your own custom variables, it doesn’t really say what type of variables it can hold or even parse. Which is where we got adventurous by going ahead and assigning some lists and associative arrays to one of our own variables:

layout: fancy.twig
object:
    property: value
---

Or using YAML’s inline style (which is very similar to JSON actually):

layout: fancy.twig
object: { property:value }
---

And lucky as we were, the property creatively names property would indeed be available inside fancy.twig:

{% if entry.object.property is defined %}
    The value of entry.object.property is {{ entry.object.property }}
{% endif %}
Taking it a step further

Note that this by itself is good to know but nowhere near really useful. What would make it useful though was if we could iterate through lists of objects with multiple properties each. Now that would definitely leverage the templating functionality of twig. Most entries and pages on this website have two special variables named sections and inject. Looking at this very blog post, here’s what its front-matter contains:

sections: [{id:flexible, title:"Quite flexible", icon:null}, {id:frontmatter, title:"Front-matter", icon:network}, {id:further, title:"Taking it further", icon:unlock}]
inject: [ {type:css, value:prettify.css}, {type:js, value:prettify.js}, {type:inline-js, value:"prettyPrint();"} ]

When looking at the above YAML, you’ll notice that we used inline style. In fact, writing lists of associative arrays isn’t possible using indented syntax only. So if you’re confused by all this indented and inline YAML style, just imagine you’d be writing JSON and all will be perfectly fine.

You might have noticed that we have links at the top of the page that kind of act like shortcuts to the various sections on a page. Well, the sections variable with its objects of 3 properties each allows us to do three things at once:

<dt>id</dt>
    <dd>Tell the browser what element to jump &mdash; or scroll if you have javascript enabled &mdash; down to when the link is clicked</dd>
<dt>title</dt>
    <dd>Supply a title to be displayed in the shortcut menu</dd>
<dt>icon</dt>
    <dd>Specify an icon from the css definitions to show.</dd>

In order to make use of these variable, the main template for our page has some twig logic looking for and interpreting these variables:

{% for section in entry.sections %}
    <li class="section-{{loop.index}}">
        <a href="#{{section.id}}">
            {% if section.icon is not null %}
            <i class="el el-{{section.icon}}"></i>
        {% endif %}
        {{section.title}}</a>
    </li>
{% endfor %}

The other variable, the inject variable is being used to inject CSS and JavaScript code and files into specific pages only. Instead of hardcoding these into the main template even subtemplates, this allows us to selectively retrieve only those resources we really need on a page, thus making it load and render faster. The inject objects do also have 3 properties, although this page only uses the first two of them:

<dt>type</dt>
    <dd>The type variable simply tells twig whether this is a css or a javascript resource we want to inject into the page.</dd>
<dt>value</dt>
    <dd>Supply a title to be displayed in the shortcut menu</dd>
<dt>remote</dt>
    <dd>Specify an icon from the css definitions to show.</dd>

The following two sections manage the injection inside the base html.twig in the header and footer regions respectively:

{% for injection in entry.inject %}
    {% if injection.type == "css" %}
        <link rel="stylesheet" href="/styles/{{injection.value}}">
    {% endif %}
{% endfor %}
{# Enables us to inject javascript libraries from the entry pages #}
{% for injection in entry.inject %}
    {% if injection.type == "js" %}
        {% if injection.source == "remote" %}
            <script src="{{injection.value}}"></script>
        {% else %}
            <script src="/scripts/{{injection.value}}"></script>
        {% endif %}
    {% endif %}
{% endfor %}
[...]
<script type="application/javascript">
{% for injection in entry.inject %}
    {% if injection.type == "inline-js" %}
{{ injection.value }}
    {% endif %}
{% endfor %}
</script>
Some room for improvement

Although using JSON in your front-matter in combination with the twig templating engine makes phrozn already pretty powerful, there is some room for improvement. Luckily phrozn is licensed under version 2 of the Apache License, which means you or I could be the lucky person implementing these features. Currently, phrozn doesn’t minify or combine your javascript and css files. Doing so would be a real benefit. Also, the directory setup of phrozn is somewhat peculiar. Although it does use composer at its base, some libraries are being pulled through the require section, while other are contained within phrozn’s own directory structure. If you would like to use a copy of composer that pulls in Markdown Extra through composer/packagist, go ahead and clone our fork of phrozn from github.