Jekyll features a simple “related posts” variable per post page with site.related_posts, which contains the 10 most recent posts in default. However, it only works perfectly when lsi (latent semantic indexing) option was enabled.1 As explained in Jekyll documents, with lsi features enabled, the build process will slow down. What’s more, it’s not supported by GitHub Pages.

So I find a post that solved this issue by using only Liquid tags to generate the related posts with tags or categories. It works by going through the related posts collection and selecting the posts that contain any tags (or categories) in common with the current post, up to a self-defined limit number. If there are enough posts to fill that limit, fine, it stops there. Otherwise, it goes again through the most recent, possibly unrelated posts, and outputs them until the limit is finally reached.

The full snippet is presented below.2 Simply adapt the HTML format using your styles.

{% assign RELATED_POSTS_THRESHOLD = 3 %}

<ul>
  {% assign related_post_count = 0 %}
  {% for post in site.related_posts %}
    {% if related_post_count == RELATED_POSTS_THRESHOLD %}
      {% break %}
    {% endif %}
    {% for tag in post.tags %}
      {% if page.tags contains tag %}
        <li>
          <h3>
            <a href="{{ site.url }}{{ post.url }}">
              {{ post.title }}
              <small>{{ post.date | date_to_string }}</small>
            </a>
          </h3>
        </li>
        {% assign related_post_count = related_post_count | plus: 1 %}
        {% break %}
      {% endif %}
    {% endfor %}
  {% endfor %}

  {% assign posts_left = RELATED_POSTS_THRESHOLD | minus: related_post_count %}
  {% unless posts_left == 0 %}
    {% for post in site.related_posts %}
      {% if posts_left == 0 %}
        {% break %}
      {% endif %}

      {% assign already_related = false %}
      {% for tag in post.tags %}
        {% if page.tags contains tag %}
          {% assign already_related = true %}
          {% break %}
        {% endif %}
      {% endfor %}
      {% unless already_related %}
        {% assign posts_left = posts_left | minus: 1 %}
        <li>
          <h3>
            <a href="{{ site.url }}{{ post.url }}">
              {{ post.title }}
              <small>{{ post.date | date_to_string }}</small>
            </a>
          </h3>
        </li>
      {% endunless %}
    {% endfor %}
  {% endunless %}
</ul>

You can also replace the site.related_posts with site.posts if you want more posts beyond the ten recent posts.