For the past week or so, I've been experimenting with Web development on GitHub Pages, a free hosting service provided by GitHub. The system is powered by Jekyll, a static site generator written in Ruby that has powerful features for organizing information. Jekyll makes use of Liquid templating logic and the Markdown text to HTML converter to provide a solid platform for creating static Web sites that mirror some of the features provided by popular content management systems such as WordPress or Drupal.
There are a number of excellent resources available for getting started with GitHub Pages and Jekyll, including the documentation linked from the previous paragraph. After reading up on the basics, I learned the most from the source code of published Jekyll sites. Browsing through the directory structure and files is probably the best way to understand how HTML, CSS, and YAML front matter interact with Liquid in a Jekyll site.
I am especially interested in how YAML metadata and Liquid logic combine to organize and display information in meaningful ways; this is the reason folks typically turn to a CMS to manage their online content. After much trial and error, I cobbled together a simple blog that makes use of tags to group content.
There are a number of excellent resources available for getting started with GitHub Pages and Jekyll, including the documentation linked from the previous paragraph. After reading up on the basics, I learned the most from the source code of published Jekyll sites. Browsing through the directory structure and files is probably the best way to understand how HTML, CSS, and YAML front matter interact with Liquid in a Jekyll site.
I am especially interested in how YAML metadata and Liquid logic combine to organize and display information in meaningful ways; this is the reason folks typically turn to a CMS to manage their online content. After much trial and error, I cobbled together a simple blog that makes use of tags to group content.
Theme & Jekyll
I chose the Minimal Theme by orderedlist as the basis for the site design. By itself, the theme is a traditional static Web site. You can add HTML files to the directory and link them together, but it does not take advantage of Jekyll's templating functionality. For that, I chose Jekyll Bootstrap as a model, and this is where it starts to get interesting.
After installing the JB system wholesale to see how it worked, I borrowed and modified a few parts for my customized blog:
Layouts provide the structure for a Jekyll site. My site has two layouts: default.html, which serves as a wrapper for every page in the site, and post.html, the vehicle for blog content. Each time the site is generated, Jekyll looks at the YAML front matter to determine how to construct the HTML. For example, every blog post must have the following code at the top of the file:
---
layout: post
---
YAML Front Matter & Liquid
This sets up a cascade effect to construct an HTML file from the modular parts. The post itself, a Markdown file, provides the content and metadata. It points to post.html, which adds a title, description, and a list of tags. Finally, post.html points to the default layout for standard page branding. A complete YAML header might look something like this:
---
published: true
layout: post
title: CMS-Free Content Management with GitHub Pages
description: Getting started with the Jekyll static site generator.
tags: github jekyll liquid markdown yaml
---
Each time Jekyll encounters Liquid markup, it adds information to the HTML according to the metadata in the YAML header. This allows for creative repurposing of data throughout a site. In addition to displaying the YAML description at the top of a blog post's page on my site, Jekyll also adds the description in the page's header as a <meta> tag, and as a tooltip on all links to the post throughout the site.
Liquid <meta>:
{% if page.description %}
<meta name="description" content="{{ page.description }}" />
{% endif %}
Liquid <a> tooltip:
{% if post.description %} title="{{ post.description }}" {% endif %}
Jekyll really shines when you harness the various layers of contextual metadata that YAML provides. For the sake of simplicity, I chose to only implement tags for starters, but there are many options if you wish to build more complex sites. Here's the basic code I use to create a list of tags at the end of a post:
<ul >
{% assign tags_list = page.tags %}
{% include JB/tags_list %}
</ul>
The code assigns all of the tags listed in the YAML front matter to an array called "tags_list." It then inserts the code from the JB/tags_list helper to produce a small box for each tag. (I had to borrow the CSS from the JB stylesheet for this to work.)
Sorting Tags
Each of those tag boxes links to the the tag's reference on tags.html. For the frequency ordered list of tags at the top of the page, I modified the hash sort in the JB/tags_list helper as described by Stephen McDonald.
The alphabetized tag listing was a much bigger challenge. Out of the box, GitHub's Jekyll implementation does not support Liquid's sort function with variables, a fact much-lamented across the Internet. After considerable searching, I modified some code from David Seifried to create a sorted array of tags from site.tags with Liquid's capture function.
The resulting array works well for a simple display, but it requires some modification for use with Liquid variables. Capture grabs information as rendered in HTML. As a result of the capture processing, the tags array contains a bunch of characters that prevent it from matching against the site.tags hash. I use the following code to strip any extra spaces, new lines, and HTML from each item pulled from the tags array:
{% assign display_word = this_word|strip_html|remove:' '|strip_newlines %}
<ul>
{% for post in site.posts %}
{% if post.tags contains display_word %}
<a>link to post</a>
{% endif %}
{% endfor %}
</ul>
Managing Content & Metadata
The beauty of working with Jekyll lies in its simplicity. After coding the site structure, every post added to the site is just a Markdown file that can be created and added to the system in a variety of ways (text editor, GitHub Web interface, command line git, etc.). I chose to use Prose.io as a convenient tool for writing and uploading posts.
Prose has a number of configuration options for automatically adding YAML metadata. These options are specified in _config.yml and produce a customized interface in the Prose metadata editor. Keep in mind that each commit with Prose linked to a GitHub account is an unauthenticated request to the GitHub API. The current rate limit is 60 unauthenticated requests per hour. If you're a habitual text tweaker like myself, it's easy to encounter a rate limit error in Prose if you're adding and editing a lot of content in one session.
As someone who makes a living creating digital objects and metadata for several systems (Chronicling America, Portal to Texas History, New Mexico Digital Newspapers), I look forward to exploring the content management possibilities provided by GitHub Pages and Jekyll. Although static site generators may not entirely replace traditional CMS infrastructures for large sites, they certainly have the potential to streamline the development workflow for small to medium scale projects.
Update 2013-08-27
I recently added a gadget called the SCM Music Player to my GitHub Pages site. It's a great tool, but for some reason it broke the #-ref link that scrolled to the tag listing on the Tags index when clicking on a tag link in a blog post. No worries, I found something better.
This blog article on searching with Jekyll has a walk-through and code links for creating search results pages for categories and tags. More info on how I added that feature is available here.