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:
- I must be able to add tags to each post that describe that post's content.
- In theory, each post will display what it is tagged with.
- 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.
- 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!
###
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>
Here's the result.
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>
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
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>
Aaaand baboombah!
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 %}
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.
Top comments (4)
Implemented this on my site today, thanks for sharing!
Nice! Glad it helped!
Thanks for sharing this solution Ryan, she solved my problem! :)
Woo! Glad I could help. Check out my blog repo too because I wrote a local plugin that goes through on every build, checks the existing tags vs those in my articles, and automatically creates the new tag pages for me! 😀