October 07, 2017

Using YAML front matter to customize Jekyll pages

To one just starting out with Jekyll, the concept of YAML front matter may seem as incomprehensible as alien ciphertext. However, this post will explain to you, in plain English, how simple it is to utilize YAML to flexibly build pages.

An actual Quick Start

1. This is a block. A “front matter” block.

Three dashes start the block. The next three dashes end it. Put this at the start of your Markdown file. Presumably that is why they call it “Front Matter”.

---

---

2. Define variables as you would in a normal programming language.

variable: value. That’s it. This is called YAML; you can think of it as a serialization standard similar to JSON.

---
name: "Kanye"
millionaire: true
---

3. You can use these variables in your HTML files

Reference the variable with {{ page.var }} . These are what people enjoy referring to as “Liquid objects”. You can see that page is a special variable predefined by Jekyll. Several more are listed in the documentation.

<body>
    <p>My name is {{ page.name }}</p> <!-- "My name is Kanye" -->
</body>

4. You can use conditionals, loops, and much more.

Logic and control flow syntax uses a slightly different set of braces: {% tag %}. One thing that differs from traditional programming languages is that the tags have to be closed with an {% endtag %}.

<body>
    <p>My name is {{ name }}</p> <!-- "My name is Kanye" -->
    
    {% if page.millionaire %}
        <p>I am rich</p> <!-- Since page.millionaire == true, this paragraph will be displayed. -->
    {% endif %}
</body>

For information on other tags, such as for and unless, see the Liquid documentation. Thankfully, it’s quite human-friendly.

Actual usage examples

With variables and control flow statements, there’s not much you cannot do. Here are some basic examples taken from this very blog.

1. Toggle Google Analytics

In each page, I set a boolean variable named analytics. By toggling the value between true and false, I can enable and disable the analytics code snippet which is embedded in head.html.

some-page.md

---
analytics: true
---

head.html

<head>
    ...
    {% if page.analytics %} <!-- This code block is only included when analytics == true -->
        <!-- Google Analytics -->
        <script>
            (function (i, s, o, g, r, a, m) {
                i['GoogleAnalyticsObject'] = r;
                i[r] = i[r] || function () {
                        (i[r].q = i[r].q || []).push(arguments)
                    }, i[r].l = 1 * new Date();
                a = s.createElement(o),
                    m = s.getElementsByTagName(o)[0];
                a.async = 1;
                a.src = g;
                m.parentNode.insertBefore(a, m)
            })(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');

            ga('create', '123456789', 'auto');
            ga('send', 'pageview');

        </script>
    {% endif %}
    ...
</head> 

Note that when you do not specify an analytics variable inside the front matter of a page, it is automatically evaluated to false.

2. Toggle Disqus comments

This is done in exactly the same way as toggling Google Analytics, by defining a comments boolean in my page’s front matter. The only difference is that I keep the code for Disqus in a separate file, and use the include tag to inject it within the HTML body.

some-page.md

---
comments: true
---

/_layouts/post.html

<body>
    ...
    {% if page.comments %}
        {% include disqus.html %}
    {% endif %}
    ...
</body>

3. The rest of post.html

You probably get the gist of front matter by now. For the final example, I’ll share my full /_layout/post.html file, which is the layout used in the page you’re reading right now.

/_layouts/post.html

<!DOCTYPE html>
<html>
{% include head.html %}

<body>
    {% include header.html %}
    <main>
        <div class="container--main">
            <article class="post">
                <h3 class="date"> {{ page.date | date: "%B %d, %Y" }} </h3> <!-- A predefined variable, plus the date format -->
                <h1>{{ page.title }}</h1> <!-- A predefined variable -->
                {{ content }} <!-- A predefined variable -->
            </article>

            {% if page.comments %} <!-- A custom-defined variable -->
                {% include disqus.html %}
            {% endif %}
        </div>
    </main>
    {% include footer.html %}
</body>

</html>

A rant, now that the tutorial is over

When I was first beginning to build my statically generated blog using Jekyll, I was extremely annoyed at encountering some foreign concept called “Front Matter”. The long-winded definition provided by the documentation did not help at all:

… Any file that contains a YAML front matter block will be processed by Jekyll as a special file. The front matter must be the first thing in the file and must take the form of valid YAML set between triple-dashed lines.

… Between these triple-dashed lines, you can set predefined variables (see below for a reference) or even create custom ones of your own. These variables will then be available to you to access using Liquid tags both further down in the file and also in any layouts or includes that the page or post in question relies on.

YAML? Liquid tags? How many new languages did I need to familiarize myself with just to get a single blog post up and running? The link to the YAML homepage exacerbated my agitated condition. “YAML is a human friendly data serialization standard for all programming languages” declared a website written in PURE MONOSPACED FONT.

YAML homepage

Conclusion & references

Although I do have my share of issues with the official Jekyll documentation (as you probably noticed from the rant above), it did become an invaluable resource once I got over the initial hurdle in understanding the concepts. The problem, I think, is that official documentation is often too formal and tediously exhaustive to someone just wanting to implement a feature quickly, and then iteratively revise. It gets worse when multiple new frameworks are combined—such as Jekyll, YAML, and Liquid—and you must skim through several foreign documentations simultaneously.

Hopefully this informal guide was more helpful in getting you started. For further reference, here are a list of resources I found useful in understanding YAML in Jekyll.