There are a number of ways to show length of an article in terms of time. We can either manually estimate the time or we can use some nifty code to automate the calculation for us. Although there are plenty of Javascript/PHP code snippets that we can use (e.g. here), I feel they require too much work to integrate with Jekyll blogs. Among the automated methods that are easy to integrate with Jekyll, most robust and scalable one uses Jekyll plug-in (here). But the problem with most Jekyll plug-ins is - in all probability it is not supported by Github pages.[1]

Liquid Tags to the Rescue

Why Liquid? Because Liquid is simple and Jekyll is built on it! I’ll start with a very basic approach (here), and then modify it to make the most out of it.

So, here is what we are going to do…

  1. Get the number of words in a post
  2. Calculate the time required to read those words
  3. Show the time estimate to the reader

1. Get the number of words in a post Jekyll has a nifty built-in Liquid filter number_of_words that can return the number of words in a string. We will apply this filter on page.content (variable which holds the content of the page) to get the number of words in a post. In addition to that, we will use the native Liquid filter strip_html to the page content to remove all the HTML tags before counting words.

{% assign num_words = page.content | strip_html | number_of_words %}

2. Calculate the time required to read those words According to Wikipedia, reading speed of an average adult is 250 to 300 words per minute.[2] However, a lot of factors like article type, multitasking etc affects reading speed. I’ll use 200 WPM as the reading speed to take into accounts that there might be some embedded images or code snippets in my article. Feel free to set your own reading speed. Now, estimated reading time is nothing but number of words divided by average reading speed. To perform this division, we will use Liquid math filter divided_by as follows.

{% assign minutes = num_words | divided_by: 200 %}

However, divided_by is supposed to round the output to the nearest integer which doesn’t work with Jekyll. In Jekyll rounding doesn’t work and it behaves like integer division.[3] So, with a reading speed of 200, articles with word count of 201 and 399 will result in reading time of 1 minute. This is not fair! So, we are going to trick Jekyll in thinking that it is doing a floating point division– by dividing word count with 200.0 instead of 200. Now, articles with word count 201 and 399 will mean reading time of 1.005 minutes and 1.995 minutes.

{% assign minutes = num_words | divided_by: 200.0 %}

But, Jekyll still doesn’t support rounding! So we are going to do a little bit of number manipulation. We will calculate the fractional part of the minutes and manually round up or down minutes towards the nearest integer. Remember to remove the comments I added followed by ‘#’.

{% assign minutes_f = num_words | divided_by: 200.0 %}      # minutes in decimal
{% assign minutes_i = num_words | divided_by: 200 %}        # minutes in integer
{% assign diff = minutes_f | minus: minutes_i %}            # fractional part of minutes
{% if diff >= 0.5 %}
    {% assign minutes = minutes_i + 1 %}
{% else %}
    {% assign minutes = minutes_i %}
{% endif %}

3. Show the time estimate to the reader This is easiest part but we need to take care of pluralization of “minute”.

{% if minutes <= 1 %}
    {% assign reading_time = '1' | append: ' minute' %}
{% else %}
    {% assign reading_time = minutes | append: ' minutes' %}
{% endif %}


Wrapping Up

Sometimes it might happen that your article is not a casual read and an average reader is going to take some time to go through the text, e.g. this article. In that case, wouldn’t it be nice to override automatic reading time estimation with your manual estimate? We can easily do that by adding a minutes variable in the post front-matter and setting it to some expected value.[4] All we need to do in our modified code is to check whether page.minutes is set. If it is set we’ll use it as our minutes variable. And if not, we’ll use our automatic calculation of minutes. And finally to make things easier and truly automated, I’ll put the complete code snippet in a html include file and include the file in the post layout as

{% include <file_name>.html %}


References

  1. Using Jekyll Plugins with GitHub Pages
  2. Words per minute in Wikipedia
  3. Integer Division
  4. Jekyll Variables