The Land of Oz Ozzie Liu

Listing Jekyll Blog Posts by Tags with Liquid

Today I was working on some enhancements on my blog and I hit a wall trying to create an blog post archive listed by tags. I did some Googling and couldn’t find anything helpful right away, so I did some research and testing to get it to work. You can find the result on my archive page. Here’s what I had to do:

Foreward

My blog is not hosted on github.io; I understand there are some limitations with Ruby plugins there. But my approach only uses Liquid tags so it should still work. Anyway, your mileage may vary.

Problem

I just wanted a simple way to list my blog posts by tags and by date on my archive page, so readers have an easy way to find my blog posts. I had been tagging each posts with tags, but today I had to figure out how to call each of them by tags.

Just something like this:

Tag 1
  - Post 1
  - Post 2
Tag 2
  - Post 3
  - Post 4

YAML Frontmatter for Blog Posts

I already tagged my blog posts with their respective tags in the YAML frontmatter, like such:

---
layout: "post"
title: "Listing Jekyll Blog Posts by Tags with Liquid"
date: "2016-06-25 16:40"
tags: [jekyll, website, data-science]
---

Archive Page to List Tags

Now on my blog.md page where I will have my tag list, I use Liquid template to call site.tags variable that lists all the tags from all my blog posts. I sort site.tags so that it’s alphabetical and assign the sorted tags to the variable ordered_tags.

Then I iterate through the ordered tag objects and for each tag, call the tag name and assign it to t. The posts of that tag are assigned to p.

Print out t for my tag heading and “prettify” the text. camelize is a custom ruby plugin that I wrote to keep tags in camelized case. Here’s the inspiration from StackOverflow, and here’s what the code looks like:

# Ruby script to camelize my tag names
require 'liquid'
require 'uri'

# Capitalize all words of the input after splitting by dashes
module Camelize
  def camelize(words)
    return words.split('-').map(&:capitalize).join(' ')
  end
end

Liquid::Template.register_filter(Camelize)

Now I iterate through all the posts of that tag, and create an unordered list of their title, URL, and date. Putting it all together so far:

{% assign ordered_tags = site.tags | sort %}

{% for tag in ordered_tags %}
  {% assign t = tag | first %}
  {% assign post_data = tag | last %}

  <h2>{{ t | camelize | replace: "-", " " }}</h2>

  <ul class="archive">
    {% for p in post_data %}
        <li>
          <small>{{ p.date | date: "%Y/%m/%d" }}</small> -
          <a href="{{ site.baseurl }}{{ p.url }}"></a>
        </li>
    {% endfor %}
  </ul>

{% endfor %}

Result

Hope you can find this simple guide helpful. Check out my archive page to see what my tag listing looks like.

Challenges Writing Liquid Template in Markdown Code Blocks with Jekyll

Believe it or not, I ran into an interesting issue when I was writing this blog post. Since I’m using Jekyll and my posts are written in Markdown format, Jekyll will try to process and double curly brackets like {{ for ... }} and {% ... %} that appear anywhere in the file. And it results in errors like this when compiling:

Regenerating: 1 file(s) changed at 2016-04-26 18:33:20   Liquid Exception: Liquid syntax error: Tag '{% ... %}' was not properly terminated with regexp: /\%\}/ in /_drafts/2016-04-25-tags-in-jekyll.md ...error:

Error: Liquid syntax error: Tag '{% ... %}' was not properly terminated with regexp: /\%\}/

Error: Run jekyll build --trace for more information.

It looks it’s just a caveat of using a templating language with markdown, but there are few workarounds. I explore them in a separate blog post.

References

Here are two pages that I found extremely helpful as I was solving this problem: