Notice (2023-08-16): This post is now outdated, as my website no longer uses Jekyll. Nearly all the features described in this post are no longer available on this site. I am leaving this up purely for archival purposes.

I’ve recently undertaken a complete revamp of this website, going through all the content, writing a new theme, and organizing things on the back-end (the Jekyll site structure). In the process, I’ve learned a lot about Jekyll, CSS, Liquid templating, and web development in general. Writing my own theme allowed me to fine-tune each and every single outward-facing aspect of the website, and many of the inward-facing ones, too. This is how I fine-tuned the site’s Atom feed.

I’m a heavy user of RSS1. I almost never subscribe to email newsletters; I only consider it if a website doesn’t have an RSS feed. And even then I usually decide that I don’t need to follow the site’s updates. :P So, of course I have high standards for my own personal website’s feed! I have it in my own feed reader (I use Newsboat), which is how I came to realize how inadequate it was.

My problem

Nearly every Jekyll website uses the jekyll-feed plugin. It’s a great plugin: you can set it and forget it, and it works great. By default it syndicates the entire content of a post. I don’t prefer this behaviour – I’ve put a lot of effort into this website’s theme, come and look at it! – so I set the plugin to produce a feed that only contains excerpts for each post. This is pretty close to what I wanted. However, in my preferred feed reader, each post displays like so:

Screenshot of an RSS feed entry in my terminal, using the program Newsboat. The body of the entry shows a single paragraph of text from a blog post.
View image at full size

There is no indication that there is more to this post. Sure, I have the option to view the article at the source website, but why would I do that when there’s no sign that there’s more to view than what’s shown here?

My requirement was simple: I want to add a line of text below the excerpt that tells the reader that there’s more where that came from.

Modification 1: Customizing the entry text

I had to implement jekyll-feed from scratch to do this. Well, okay, not from scratch. First I tried this snippet from Jekyll Codex. However, it doesn’t include an author name in the post entry, nor does it provide an option to syndicate only an excerpt instead of the full contents of a post.

Bear in mind that I’m a total noob when it comes to XML and RSS/Atom. Sure, I know how to add a feed URL to my reader, but that’s it. I don’t know anything about XML or feed structure. So I just looked at the output of jekyll-feed and added the corresponding line for including the author’s name in entries. Easy, right? But no! It threw a bunch of errors. The feed refused to load at all in Newsboat. The few ham-fisted edits through which I attempted to rectify this led nowhere.

The prospect of editing the Jekyll Codex feed suddenly seemed daunting.

So I figured, jekyll-feed was working fine enough for my purposes. Why reinvent the wheel? I can just copy its output and add a line pointing people to the article at my blog at the end of each entry.

This was easier said than done. I went through the entire thing line by line, substituting Liquid variables wherever applicable. Once I did that, I was faced by a multitude of errors, and after tearing my hair out for a bit, I turned to the W3C Feed Validator. I implemented its suggestions one by one. I learned a lot about escaping characters for XML-safe and URI-safe output. I learned about date formats (RFC 3339, anyone?). And then I was the proud owner of a valid Atom feed!

[Valid Atom 1.0]

Some tricky Liquid syntax was involved. I’ve uploaded the fruits of my labour to a GitLab snippet here. There’s one block I’m particularly proud of:

<summary type="xhtml">
    <div xmlns="http://www.w3.org/1999/xhtml">
        {% if post.excerpt %}
        {{- post.excerpt | remove: "</p>" | append: " […]" | markdownify -}}
        <p>
            Read the full post at <a href="{{ post.url | prepend: site.baseurl | prepend: site.url }}">{{ post.title | xml_escape }}</a>.
        </p>
        {% else %}
        {{ post.content | markdownify }}
        {% endif %}
    </div>
</summary>

If the post has a defined excerpt, we display that, followed by a directive to read the rest on the website. If there is no excerpt, we syndicate the entire post.

I wanted to have an ellipsis at the end of the excerpt, but Jekyll kept putting it on the next line, like so:

I had a bit of a scare a couple of days ago. My laptop just came back from (hardware) repairs, and on switching it on, I was dropped into a GRUB shell. I hadn’t updated my laptop or done anything out of the ordinary – I still don’t know why this happened. Here’s how I fixed it.

[…]

That is, just using the append Liquid filter wasn’t cutting it. I used strip to strip a newline. No change. I suspected the presence of a closing paragraph tag to be the culprit, so I tried stripping the HTML tags from the excerpt (not a good idea, in retrospect). Still no change. Then, after some trial and error, I came up with this line:

{{- post.excerpt | remove: "</p>" | append: " […]" | markdownify -}}

This is clever because </p> is an optional tag! Once we remove it, markdownify will make sure it gets closed. Even if it’s not closed, there’s no harm done. This approach retains all the HTML in the excerpt as well.

Screenshot of an RSS feed entry in my terminal, using the program Newsboat. The body of the entry shows a single paragraph of text from a blog post truncated by an ellipsis, followed by a line directing the reader to read the entire post.
View image at full size

Voilà, our desired result!

Modification 2: Feed styling

After I was done creating my brand new Atom feed, Jekyll (or maybe my browser?) chose to render it like a normal HTML page. I suspect the use of markdownify. In any case, it was ugly:

Screenshot of the feed in my browser, appearing as a wall of text.
View image at full size

I looked up styling XML. I learned that you can use an XSLT file, but I wasn’t interested in playing with (to me) a brand new syntax. You can achieve more limited styling with plain old CSS. And that’s what I did! Meet my gorgeous new feed:

Screenshot of the feed in my browser, looking like a normal webpage with clearly defined headings and post entries.
View image at full size

All I needed to do was insert a line after the XML version:

<?xml-stylesheet type="text/css" href="/rss-style.css" ?>

Check out the feed here, and add it to your RSS reader :)


  1. I use the terms RSS and Atom interchangeably throughout the post. For my ends, they’re interchangeable; but it’s worth noting that they’re different