mahiwaga

I'm not really all that mysterious

tags in Jekyll

So it took me a while to figure out how to implement tags in Jekyll the way I wanted.

What I wanted was two-fold:

(1) http://mahiwaga.pw/tag/*tag* would link to a list of all the posts tagged tag

(2) http://mahiwaga.pw/tag/ would link to a list of all tags and under each tag would be all the posts tagged with that tag

While searching through Google yields a bunch of old plugins and some Liquid kludgery that can approximate this, (1) was most easily achieved by installing jekyll-archives which can automatically generate pages for each tag as well as for each year and for each month.

I then added the following lines to _config.yml:

  
gems:
  - jekyll-archives
	
jekyll-archives:
  enabled:
    - year
    - month
    - tags
  layouts:
    year: year-archive
    month: month-archive
    tag: tag-archive
  permalinks:
    year: '/:year/'
    month: '/:year/:month/'
    tag: '/tag/:name/'

  

(This is also enables links to lists of posts by year—http://mahiwaga.pw/*yyyy*/ and lists of posts by month—http://mahiwaga.pw/*yyyy*/*mm*/)

I then created the file _layouts/tag-archive.html:

  

---
layout: default
---
<h1>Archive of posts with {{ page.type }} '{{ page.title }}'</h1>
<ul class="posts">
	{% for post in page.posts %}
	<li>
		<span class="post-date">{{ post.date | date: "%b %-d, %Y" }}</span>
		<a class="post-link" href="{{ post.url | prepend: site.baseurl }}">{{ post.title }}</a>
	</li>
	{% endfor %}
</ul>


  

This layout could probably use a little a lot more work, but it will do for now.

Just as an aside, at least as of jekyll-2.5.3, tags that are just numbers—

  
tags:
- 2001
- 42
- 1337

  

—will cause jekyll to crashout with non-obvious error messages.

Also, another thing I learned was that using tags with colons(:)—

  
tags:
- 2001: A Space Odyssey
- Star Trek: Voyager

  

—will get misinterpreted as YAML hashes.


Implementing (2) was a bit trickier.

It’s not too difficult to just iterate through all the tags to get to all the posts, but the tags are stored in the order of their occurrence, which seems quite haphazard and not that useful.

I did find a page explaining how to get a sorted list of tags using only Liquid, but ASCII sorting instead of alphabetically sorting still seemed rather messy.

(As an aside, I was highly amused by these rants regarding the fact that programming languages tend to always default to ASCII sorting and it’s rare to find a natively-implemented natural sorting function or subroutine, leading people to recurrently reinvent the wheel:

I laughed at this particular quote: “…what sane person would want ASCII order?”)

The specific issue is that the sort Liquid filter implemented by Jekyll can only do an ASCII sort. While the master branch of Liquid has partially implemented a natural sort (really, it’s just a case-insensitive sort) I couldn’t figure out how to get Jekyll to use the liquid-4.0.0.alpha gem and it kept pulling in liquid-3.0.3 instead.

So I decided to implement this custom filter (adapted from Tanguy Krotoff):

I created the file plugins/customfilter.rb which implements a Liquid filter named sortcasecmp:

  
module Jekyll
	module CustomFilter
    
   		def sort_casecmp(input)
	   		input.sort { |apple, orange| apple.casecmp(orange) }
	   end
	end
end
Liquid::Template.register_filter(Jekyll::CustomFilter)

  

Then I created tag.md in the top level directory:

  

---
layout: page
title: tags
permalink: /tag/
---
{% capture unsortedtags %}{% for tag in site.tags %}{{ tag | first }}{% unless forloop.last %}|{% endunless %}{% endfor %}{% endcapture %}
{% assign sortedtags = unsortedtags | split:'|' | sort_casecmp %}

{% for tagindex in (0..site.tags.size) %}{% unless forloop.last %}
	{% capture currenttag %}{{ sortedtags[tagindex] }}{% endcapture %}
<a href="/tag/{{ currenttag | downcase | slugify }}/" title="posts tagged  {{ currenttag }} ">{{ currenttag }}</a>
<ul>
	{% for post in site.tags[currenttag] %}
	<li>
   		<a href="{{ post.url }}">{{ post.title }}</a>
   		<span class="date">{{ post.date | date: "%B %-d, %Y"  }}</span>
	</li>
	{% endfor %}
</ul>
{% endunless %}{% endfor %}


  

Voila!

initially published online on:
page regenerated on: