Jekyll Tags, The Easy Way

Ryan Palo - Aug 14 '17 - - Dev Community

Note: For some reason, I can't include YAML frontmatter triple-dashes within the body of the post. Instead I'll use ### to signify that. Be sure to use triple dashes in your own code.

I was looking at my blog and trying to think of cool yet attainable things that I could add to it and experiment with. I decided that I wanted to add tags to my posts -- if nothing else, just to see what I was writing about. I began my research and planning with the following requirements:

  1. I must be able to add tags to each post that describe that post's content.
  2. In theory, each post will display what it is tagged with.
  3. There should be a way of linking posts with the same tags together, or at least getting from one post with a tag to another one.
  4. The home page should have some kind of list of tags, tag ranking, tag cloud, etc.

My blog is just a static site powered by Jekyll and Github Pages. For more information on this, check out Jekyll's homepage. I began my search with jekyll plugins. I'll admit that I didn't look too hard, because I tend to succumb to "not-built-here" syndrome too often. That being said, in the short time I did search, I didn't see anything that would do exactly what I wanted.

Having some amount of comfortability with Jekyll's templating language (powered by the Liquid Templating Engine), I decided, how hard could it be to do it on my own? Turns out, Jekyll makes it pretty easy!

1. Adding tags to each post

This one is by far the easiest. Every Jekyll post starts with some YAML frontmatter that the parser uses to build the site. There are some built-in variables you can use (like "tags", as it turns out), and you can define your own to be used within the post/page itself! I only had to modify my frontmatter by one line.

###
layout: page
title: Highly Original Example Title
tags: get some dope tags, Add this.  Separate via spaces or commas!
###
Enter fullscreen mode Exit fullscreen mode

2. Each post will display its tags

Again, we are saved by Jekyll's templating and built-in variables. At the end of each post, I added the following html snippet. You could probably be more creative than me.

<small>
    {% for tag in page.tags %}
    <a href="/tags/{{ tag }}/">{{ tag }}</a>
    {% endfor %}
</small>
Enter fullscreen mode Exit fullscreen mode

Here's the result.

Screenshot of rendered tags html

Simple yet beautiful.

3. There should be a way to group posts that share tags

This one gets a bit harder and more involved. I chose to solve this by making a page for each tag that simply lists the posts that have that tag. The first step is to create a basic layout template. Create the code below in _layouts/tagpage.html.

###
layout: page # This template inherits from my basic page template
###
<!-- We're going to give each page a tag when we create it.
This will be the title -->
<h1>{{ page.tag | capitalize }}</h1>

<ul>
    {% for post in site.tags[page.tag] %}
    <li>
        {{ post.date | date: "%B %d, %Y" }}: <a href="{{ post.url }}">{{ post.title }}</a>
    </li>
    {% endfor %}
</ul>
Enter fullscreen mode Exit fullscreen mode

Finally, in the main directory of your site, put a /tags/ directory. For each tag you have, you need to create a file. One of the tags for this post is jekyll, so I have the following file tags/jekyll.md:

###
layout: tagpage
tag: jekyll
permalink: /tags/jekyll/ # This is only required for pretty links.
###

# Thus, this page's link is /tags/jekyll/ rather than /tags/jekyll.html
Enter fullscreen mode Exit fullscreen mode

Now, when Jekyll builds, it will build a page for each of these tags, with a list of the posts for each one. I'm working on a Jekyll plugin to have that tags folder get autogenerated based on the tags of each post. Or maybe a hook into the Jekyll building process so I won't even have to remember to type jekyll tag. We'll see.

4. The home page should have some form of tag cloud

This last one requires some explaining. Add the code below to your home page. Have a glance at the html below before reading this next paragraph, so you'll know what I'm talking about. The site.tags variable that is available to you in Jekyll templates is an interesting structure. If you access it like a dictionary (or dict, or hash, depending on your language of choice), -- e.g. site.tags["nematodes"] -- you will receive a list of the posts that have that tag. If you loop through site.tags directly, each item can work as a tuple: (tag name, list of posts with this tag). In the file below, you see both methods.

<p>
    {% for tag in site.tags %}
    <!-- Here's a hack to generate a "tag cloud" where the size of
    the word is directly proportional to the number of posts with
    that tag. -->
    <a href="/tags/{{ tag[0] }}/" 
    style="font-size: {{ tag[1] | size | times: 2 | plus: 10 }}px">
        {{ tag[0] }} | 
    </a>
    {% endfor %}
</p>
Enter fullscreen mode Exit fullscreen mode

Aaaand baboombah!

Rendering of the final tag cloud

As you can see, the list is unordered due to the fact that the site.tags variable is a dictionary, in which order isn't guaranteed (unless you're programming in Python 3 right now, where dictionaries are ordered by happy coincidence). If you need them ordered, you'll need to get slightly more complicated.

Roundup

My original search provided methods like this:

###
layout: default
title: Tag
###
<!--
The following part extracts all the tags from your posts and sort tags,
 so that you do not need to manually collect your tags to a place.
=======================
-->
{% assign rawtags = "" %}
{% for post in site.posts %}
    {% assign ttags = post.tags | join:'|' | append:'|' %}
    {% assign rawtags = rawtags | append:ttags %}
{% endfor %}
{% assign rawtags = rawtags | split:'|' | sort %}

<!--
=======================
The following part removes dulpicated tags and invalid tags like blank tag.
=======================
-->
{% assign tags = "" %}
{% for tag in rawtags %}
    {% if tag != "" %}
        {% if tags == "" %}
            {% assign tags = tag | split:'|' %}
        {% endif %}
        {% unless tags contains tag %}
            {% assign tags = tags | join:'|' | append:'|' | append:tag | split:'|' %}
        {% endunless %}
    {% endif %}
{% endfor %}
Enter fullscreen mode Exit fullscreen mode

The above snippet taken specifically from @codinfox. You can find his blog here. It looks like it works and has a lot of bells and whistles. I just wanted something simple and easy. Have any ideas for improvement or neat/better layouts? Let me know. I am by no means what they call a "design-oriented" individual. I can make things that function nicely, but pretty is something that I'll have to find some good mentors to learn.


Originally posted on my blog.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .