Developing Hyde Templates - Part 1

'Just Me…' by Jerry, Flickr

Seh Hui Leong

Programming

Let’s see… it’s been close to three weeks I’ve migrated this blog from Wordpress to Hyde. And ever since then I have been constantly fixing bugs in my template.

Let’s run down the commit history and show you some of the lessons that I’ve learned along the way :).

[Note: I’ll be referencing my own template]

Multiple Layouts with Template Inheritance

For my site, I needed two different layouts that shares the same base design: a two-column layout for my blog and full page layout for other static pages.

This is easily achieved by using template inheritance using the extends feature. In my current template, you can refer to the following three files:

  • layout/base.j2 — The overall site design, acts as base template
  • layout/blog.j2 — (child template) The two-column layout for my blog
  • layout/full_page.j2 — (child template) The full page layout for static pages of my site

In base.j2, you can define blocks where your child template can override with their content. For example:

<title>{% block title -%}My Take In Life{%- endblock title %}</title>

And creating a child template is as easy as extending from the base template. For example:

{{ '{%' }} extends "base.js" {{ '%}' }}
{{ '
{# This will override the "title" block in base.j2 #}
{% block title -%}
  {{ res.meta.title }} | My Take In Life
{%- endblock title %}

Once you have those templates, you can specify which template you’d want to use for a particular page in the metadata:

---
extends: blog.j2
title: ...
---

Your content here...

And yes, it’s that simple!

One important note: you can extend templates up to two levels deep. Or in other words:

  • This will work perfectly: base.j2 > full_page.j2 > manga_tutorial.j2
  • In this scenario, manga_tutorial_listing.j2 will not extend properly and will become broken: base.j2 > full_page.j2 > manga_tutorial.j2 > manga_tutorial_listing.j2

MetaPlugin Caveats

I really love MetaPlugin, where you can specify metadata in YAML format for each page. For example, the raw blog post would look something like this:

---
title: Working Remotely
created: !!timestamp "2012-01-26 23:42:52"
extends: blog.j2
tags:
    - productivity
    - life
default_block: post
---

Content here...

As you would notice, you can use Jinja2 templating syntax here as well and it’ll work — great when you want to use Jinja2 text filters.

The only caveat of using MetaPlugin is that you will not be able to override template blocks using the {{ '{% block ... %}' }} syntax and the content you’ve specified will still go into the default_block that you’d specified.

If you wanted more creative freedom, you may want to forego using MetaPlugin by removing the reference from site.yaml. Check out Steve Losh’s template if you want to see such an example.

Partial Templates with include

Partial templates is a great way to split your base template into several reusable components. So instead of having one long and monolithic HTML page that’s hard to read and maintain, you can break it up to logical parts.

In my current implementation, base.j2 uses the following partial templates:

  • analytics.j2 — For Google Analytics tracking code
  • sidebar.j2 — For my sidebar, mainly used for my blog
  • teaser.j2 — The teaser portion of my homepage

Once you have written your partial templates, you just drop it in your main template file with the include syntax:

{% include "analytics.j2" %}

Dynamic, Reusable Components with Macros

Another way of writing reusable components is by writing Jinja2 macros. Take a sneak peak into macros.j2 and you’ll notice that defining macros is like defining Python functions that takes arguments — it’s power lies in the ability to take parameters and thus gives you more versatility than partial templates.

One specific use case is the render_share_button(res) macro, which takes a resource (res) as it’s argument. With this macro, I’m able to reuse the template snippet for a single blog post (see blog.j2) and each blog entry resource that’s iterated when generating the blog post listing page (see listing_paging.j2).

Writing the same snippet as a partial template would be a big mess of conditional statements.

To define a macro, all you need to do is to define the macro at the top of the page. And invoking a macro is similar to calling a Python function. For example:

{% macro render_share_button(res) %}
  {% if res.meta.enable_sharing -%}
    <a href="https://twitter.com/share"
        class="twitter-share-button"
        data-url="{{ full_site_url(res) }}"
        data-text="{{ res.meta.title }}"
        data-via="felixleong"
        data-related="felixleong">Tweet</a>
    <div class="fb-like"
        data-href="{{ full_site_url(res) }}"
        data-send="false"
        data-width="450"
        data-show-faces="false"></div>
  {%- endif %}
{% endmacro %}

{# Calling the macro #}
<div class="postmeta">{{ render_share_button(resource) }}</div>

If you want to invoke a macro that’s defined in a separate template file, you’ll need to import it first. For example:

{% from "macros.j2" import render_share_button with context %}
{{ render_share_button(resource) }}

To Be Continued…

Well, this wraps up the broad strokes of modular template development for Hyde. I’ll be covering some of the more exciting theme development tricks in the next instalment: like generating tag cloud and great ways of using metadata and more.

Stay tuned!

Written by

Seh Hui Leong

Python programmer by trade, interested in a broad range of creative fields: illustrating, game design, writing, choreography and most recently building physical things. Described by a friend as a modern renaissance man.