Blogging about individual self-contained ideas is great. But some ideas require a more structured approach. Chaining together simple ideas into one big whole is a great journey for both the writer and the reader. Which is why I wanted to add a Series feature to this Jekyll blog. As you may have guessed already, Jekyll’s high degree of customsation makes this a breeze.

Goal

What I want to achieve is:

  1. Each article should list the other articles which are part of the same series.
  2. To simplify content discovery, the home page should display all series in a category.
  3. Moving articles into different series should be easy since they may evolve over time.

Step 1: Adding series metadata to posts

Given Jekyll’s high customisability there are several ways to handle a series. Either we can leverage Jekyll variables in the config to keep a list of series. Or we can use collections. Or define a Liquid list somewhere in a global template and iterate over it.

The cleanest way is to keep the series along with the posts contained in that series. For example, for all the posts in the Jekyll series, I’ve added the following 2 variables in the post front matter:

is_series: true
series_title: "Jekyll"

The first variable, is_series, is a simple boolean which says whether this post is part of a series or not. Booleans work great with Liquid filters and will allow me to filter only those posts which are part of a series. This will come in handy later on when we’re trying to list all the series in one go.

The second variable, series_title, is the title of this series, in this case Jekyll. It’s important that posts in the same series contain the exact same title. We’ll use this title to match posts to a series. If it contains extra spaces or special characters it won’t match the series.

You can view the source-code for this here.

With our series defined, we now need to show other articles in the series. Meaning if I’m seeing a post in the Jekyll series there should be a list of other articles in the Jekyll series. A series won’t make sense without this essential navigation.

This blog uses the posts layout to display posts. To display other posts in the same series as the currently viewed post, I’m using the code below:

<!-- Series links -->
{% if page.is_series == true %}
<h3 class="text-success p-3 pb-0">{{ page.series_title | upcase }} series</h3>
{% assign posts = site.posts | where: "is_series", true | where: "series_title", page.series_title | sort: 'date' %}
 
{% for post in posts %}
        {% if post.title == page.title %}
 <p class="nav-link bullet-pointer mb-0">{{ post.title }}</p>
        {% else %}
 <a class="nav-link bullet-hash" href="{{ post.url }}">{{ post.title }}</a>
        {% endif %}
{% endfor %}

{% endif %}

The logic above goes as follows:

  1. Check if the is_series boolean of the current page is true, meaning the post is part of a series.
  2. Fetch posts where is_series is true and series_title is the current series_title. Sort these in ascending order of date.
  3. Display links to other posts in the series. Or show a non-clickable span if the list item is the current post.

I’ve stripped some of the HTML for clarity but you can view the full source-code here.

We now have the post pages showing links to other posts in the same series. Next, I want to add a navigation to all series under a category on my home page.

For example. On the home page, the Technology section should show all series in Technology. The same for Life Stuff, Video Games, and META categories as well. This will make it easier for users to browse and read a complete series.

<!-- Series posts -->
{% assign series = "" | split: "," %}
{% assign series_post = "" | split: "," %}
{% assign posts = site.posts | where:"Category", cat.title | where: "is_series",true | sort: 'date' %}

{% for post in posts %}
{% unless series contains post.series_title %}
{% assign series = series | push: post.series_title %}
{% assign series_post = series_post | push: post %}
{% endunless %}
{% endfor %}

{% if series.size > 0 %}
<div class="row m-1 row-cols-1 row-cols-md-4 g-3 align-items-center">
 <div class="col">
 <span class="h3 text-success">Article series →</span>
 </div>
    {% for post in series_post %}
        {% include card-link.html url=post.url title=post.series_title %}
    {% endfor %}
</div>
{% endif %}
{% endfor %}

To identify all series for a particular category, I’m using the code above, which:

  1. Initalizes two variables: one for series names and another for the first post of each series.
  2. Fetches all posts which have is_series set to true and which belong to the current category.
  3. Adds the series_title to the series names array and the first post to the series post array.
  4. Finally, it displays the name of the series which links to the first post in that series.

You can find the full source code here.

Conclusion

Jekyll’s high degree of customisation is why I enjoy working with it so much. And why this blog’s underlying Jekyll engine has survived redesigns and refactors. Jekyll makes it easy to add dynamic logic to your otherwise static website. And while my website remains static, the logic that renders it doesn’t have to be.

There are many improvements you can make to what I’ve shown you today.

One improvement I’m thinking of is handling series post ordering. For example, right now the posts in a series show in ascending order of their publish date. But I’ve published several posts belonging to a series at different times. So I can add a series_order key and use it to order articles rather than their publish date. This is one of the many ways you can build your own series feature.

Happy coding :)