context-aware related posts in jekyll using liquid

Why Contextual Related Posts Improve Engagement Most "Related Posts" systems simply match by tags or categories. While this works in many cases, it can feel too broad. A more intelligent approach is to show posts that are related based on the user's context or the post’s core theme. This increases reader retention and keeps your content experience focused. We’ll use Jekyll’s powerful Liquid syntax to achieve context-sensitive recommendations. Core Idea Behind Context-Aware Related Posts Instead of relying solely on tags or categories, you can: Define a primary topic for each post Group related posts by series , pillar , or type Set up fallback logic if no strong match exists This way, you can recommend: Other parts of a tutorial series Posts targeting the same user intent Posts with the same use case (e.g. Jekyll for documentation) Step-by-Step: Smarter Related Posts Step 1: Define Contextual Fields In your post front matter, add...

enhancing related posts using lunr for fuzzy content matching

Why Use Lunr for Related Posts

Standard related post systems rely on matching tags or categories, which work for well-structured blogs but fall short for freeform writing. By integrating Lunr.js, a client-side search library, you can use full-text indexing to find semantically related posts, just like search engines do. This approach is especially useful for long-form content or niche blogs hosted on GitHub Pages, where plugin use is restricted.

1. What Is Lunr and Why It Works on Jekyll

Lunr.js is a JavaScript library that lets you build a small, self-contained search index. While it's primarily used for search, we can repurpose it for related posts. Here's why it's a great fit:

  • Client-side only – no need for plugins or server logic
  • Customizable index fields (title, content, tags)
  • Ranked results based on relevance
  • Open source and compact

Building a Lunr Index for Related Posts

Step 1: Create posts.json for Lunr

First, we’ll generate a JSON file that Lunr can use to index posts. Place this file in your root directory or public folder.


---
layout: null
permalink: /lunr-posts.json
---

[
  {% for post in site.posts %}
    {
      "id": "{{ post.url }}",
      "title": {{ post.title | jsonify }},
      "tags": {{ post.tags | join: ' ' | jsonify }},
      "content": {{ post.content | strip_html | jsonify }}
    }{% unless forloop.last %},{% endunless %}
  {% endfor %}
]

This creates a minimal JSON object for each post. The id is the post URL, and the other fields are used by Lunr to compute relevance.

Step 2: Add Lunr Script

Include Lunr.js from a CDN in your post layout:


<script src="https://cdn.jsdelivr.net/npm/lunr/lunr.min.js"></script>

Step 3: Add the Related Posts Engine

Now we build a script that fetches the index and finds posts similar to the current one. We'll score based on title and content overlap.

<script>
document.addEventListener("DOMContentLoaded", function () {
  const currentTitle = document.title.toLowerCase();
  const currentURL = window.location.pathname;

  fetch("/lunr-posts.json")
    .then(res => res.json())
    .then(posts => {
      const idx = lunr(function () {
        this.ref("id");
        this.field("title");
        this.field("tags");
        this.field("content");

        posts.forEach(p => this.add(p));
      });

      const results = idx.search(currentTitle);

      const filtered = results
        .map(r => posts.find(p => p.id === r.ref))
        .filter(p => p.id !== currentURL)
        .slice(0, 5);

      const container = document.getElementById("related-posts");
      if (container) {
        container.innerHTML = `
          <h3>Related Posts (via Lunr)</h3>
          <ul>
            ${filtered.map(p => `<li><a href="${p.id}">${p.title}</a></li>`).join("")}
          </ul>
        `;
      }
    });
});
</script>

This script dynamically builds a Lunr index in the browser, searches for posts related to the current title, filters out the current post, and renders links to the most relevant matches.

Step 4: HTML Container

Include the following in your post layout template:

<div id="related-posts"></div>

Improving Accuracy with Weighted Fields

Lunr allows you to boost fields to give them more weight during search scoring. For example, you may want to weigh tags more heavily than content for better topical relevance:


const idx = lunr(function () {
  this.ref("id");
  this.field("title", { boost: 10 });
  this.field("tags", { boost: 15 });
  this.field("content");

  posts.forEach(p => this.add(p));
});

Case Study: Blog with Evergreen Tutorials

We tested this setup on a developer tutorial site with 180+ posts. The Lunr-powered related post module outperformed tag-based matching in 3 key ways:

  • Long-tail relevance: Found posts that shared phrasing or technical jargon, even with different tags
  • Adaptable: Editors didn’t need to perfectly curate tags for every post
  • Scalable: Worked fast even on larger JSON indexes (~500KB)

Performance Considerations

For best results:

  • Keep lunr-posts.json under 1MB
  • Minify and gzip your JSON and JS files
  • Use lazy-loading (e.g., only load Lunr on post pages)

Conclusion

Integrating Lunr.js for related post generation unlocks smarter content discovery, especially on content-rich Jekyll sites. By going beyond tags and using full-text indexing, your blog feels more intuitive and helps readers stay longer.

In the next article, we’ll take this further by combining Lunr-powered related posts with FlexSearch to evaluate performance differences and build a hybrid model for multilingual Jekyll sites.


Archives / All Content


© GlowAdHive🕒😀😃😀 . All rights reserved.