Jekyll has built-in support for tagging of pages and posts, but doesn’t provide any functionality to create tag clouds. Because this is so common, there is a nice plugin for it: jekyll-tagging.

When upgrading to Jekyll 3.3.1 I found that the plugin stopped working. So I decided to cook my own simple solution to get it to work. In this post I’ll shortly explain how I solved it.

Preparations

For the proposed solutions to work, you will have to set a tag_dir variable in your _config.yml:

# Tags
tag_dir: tag

Tag Cloud for a Post

This is the simple one, you can see an example at the bottom of this post. In the post template (_layouts/post.html), you can add:

{% if page.tags != empty %}
    <footer>
      <p>Read more:</p>
      <ul class="tag-list">
        {% for tag in page.tags %}
        <li><a href="{{ site.tag_dir | prepend: '/' }}/{{ tag | uri_escape }}">{{ tag }}</a></li>
        {% endfor %}
      </ul>
    </footer>
{% endif %}

This simple loop lists the post tags and creates a link to the tag page (see below).

Tag Cloud for your entire Site

This creates a sorted collection of all tags used throughout your site and renders it in a list:

{% assign all_tags = '' | split: ',' %}

 {% for post in site.posts %}
    {% for tags in post.tags %}
        {% for tag in tags %}
            {% assign all_tags = all_tags | push: tag %}
        {% endfor %}
    {% endfor %}
{% endfor %}

{% assign all_tags = all_tags | sort %}
{% assign all_tags = all_tags | uniq %}

<ul class="tag-list">
    {% for tag in all_tags %}
        <li><a href="{{ site.tag_dir | prepend: '/' }}/{{ tag | uri_escape }}">{{ tag }}</a></li>
    {% endfor %}

</ul>

Generating a Tag Page for each tag

When users click a tag, they should see a list of pages that also use that tag (Tag Index). The snippet below creates those pages for you (based on the Category page generator example).

Make a new file _plugins/jekyll-tag-pages.rb:

module Jekyll

  class TagPage < Page
    def initialize(site, base, dir, tag)
      @site = site
      @base = base
      @dir = dir
      @name = 'index.html'

      self.process(@name)
      self.read_yaml(File.join(base, '_layouts'), 'tag_index.html')
      self.data['tag'] = tag

      tag_title_prefix = site.config['tag_title_prefix'] || 'Tag: '
      self.data['title'] = "#{tag_title_prefix}#{tag}"
    end
  end

  class TagPageGenerator < Generator
    safe true

    def generate(site)
      if site.layouts.key? 'tag_index'
        dir = site.config['tag_dir'] || 'tag'
        site.tags.each_key do |tag|
          site.pages << TagPage.new(site, site.source, File.join(dir, tag), tag)
        end
      end
    end
  end

end

We also need to provide the Tag Index with a view. The code above expects the view to be in _layouts/tag_index.html. To render the list, use this snippet:

<ul class="archive-list">
    {% for post in site.tags[page.tag] %}
    <li>
        <a href='{{post.url}}'>{{post.title}}</a>
        <time datetime='{{post.date | date: "%Y-%m-%d"}}'>{{post.date | date: "%Y-%m-%d" }}</time>
    </li>
    {% endfor %}
</ul>

That’s a wrap!

That should give you enough information to roll your own custom tag clouds. Feel free to get in touch if you have any questions or suggestions!


Sources