Posts

Showing posts with the label static-sites

adding author bio to jekyll posts

Why Author Bios Matter

Author bios add credibility to your content, create a personal connection with readers, and build trust—especially for blogs focusing on education, expertise, or opinions. Jekyll gives you the flexibility to create author bios that are dynamic and easy to maintain.

Common Author Bio Challenges in Static Sites

Unlike CMS platforms with built-in user management, Jekyll doesn’t have a native concept of “users.” This means we need to implement authorship logic manually while keeping it reusable and efficient.

Step 1: Create a Data File for Authors

Create a new file under _data/authors.yml. This YAML file will contain author metadata such as name, avatar, bio, and social links.

john:
  name: John Doe
  bio: "John is a content strategist with a passion for open-source publishing."
  avatar: "/images/authors/john.jpg"
  twitter: "johndoe"
  website: "https://johndoe.dev"

sarah:
  name: Sarah Lee
  bio: "Sarah writes about SEO and digital workflows for creators and freelancers."
  avatar: "/images/authors/sarah.jpg"
  twitter: "sarahleewrites"
  website: "https://sarahlee.blog"

Step 2: Define Author in Front Matter

In each blog post, specify the author key in the front matter:

---
layout: post
title: "Using Jekyll with Netlify"
author: john
---

Step 3: Create an Include for the Bio Section

Now create a reusable component: _includes/author-bio.html

{% raw %}
{% assign author = site.data.authors[page.author] %}
<img src="{{ author.avatar }}" alt="{{ author.name }}" class="author-avatar"> <div class="author-info"> <h4>Written by {{ author.name }}</h4> <p>{{ author.bio }}</p> <p> {% if author.twitter %} <a href="https://twitter.com/{{ author.twitter }}">Twitter</a> {% endif %} {% if author.website %} <a href="{{ author.website }}">Website</a> {% endif %} </p> </div>
{% endraw %}

Step 4: Add CSS Styling

Style the bio section in your CSS file:

.author-bio {
  display: flex;
  gap: 1rem;
  margin-top: 2rem;
  padding-top: 1rem;
  border-top: 1px solid #eee;
}
.author-avatar {
  width: 64px;
  height: 64px;
  border-radius: 50%;
}
.author-info h4 {
  margin: 0;
}

Step 5: Display Bio at End of Each Post

Insert this include at the end of your post layout file (typically _layouts/post.html):

{% raw %}
{% include author-bio.html %}
{% endraw %}

Optional: Add Social Icons

Instead of plain text links, you can use icon libraries like FontAwesome or SVGs to show Twitter or website icons next to each link. This gives a more polished and professional feel.

Case Study: Personal Branding with Author Bios

A developer blog added custom author bios with images and links to GitHub and Twitter. Over 3 months, they saw a 22% increase in profile link clicks and higher time-on-page. Readers were more likely to explore related posts by the same author.

Best Practices for Author Bios

  • Use consistent formatting across posts
  • Keep the bio short but relevant
  • Update bios occasionally for accuracy
  • Add links to personal blogs, Twitter, or LinkedIn

Benefits for Multi-Author Blogs

If your Jekyll site has multiple contributors, this approach allows each author to have a unique bio shown on their posts without duplicating layout code. It also helps with branding and user trust.

Conclusion

Adding an author bio to Jekyll posts improves engagement and builds authority. By using data files and includes, you can scale this feature across hundreds of posts while maintaining a clean and consistent structure—making your Jekyll blog feel more dynamic and personal.

jekyll collections for scalable content types

What Are Jekyll Collections

Jekyll collections are a powerful way to organize and manage custom content types beyond regular blog posts and pages. They allow developers to structure content logically—for example, portfolios, documentation pages, team member profiles, or reusable data sections—while maintaining Jekyll's simple static site generation process.

Why Collections Matter in Scalable Static Sites

  • Enable clear separation of different content types
  • Support nested navigation and dynamic rendering
  • Allow custom output formats and URL patterns
  • Improve maintainability for larger or multi-author projects

How to Define a Collection

Collections are defined in the _config.yml file:

collections:
  tutorials:
    output: true
    permalink: /tutorials/:title/
  team:
    output: false

Each collection gets its own folder prefixed with an underscore:

  • _tutorials/ → output to HTML pages
  • _team/ → used for data, no HTML output

Structuring Content Inside a Collection

Each markdown or HTML file inside a collection folder must include front matter. For example, _tutorials/seo-basics.md:

---
title: SEO Basics for Beginners
level: beginner
category: on-page
layout: tutorial
---
Content of the tutorial goes here.

Collection Metadata in Front Matter

You can customize what data is available to each item through front matter, then access that in your templates or index pages.

Rendering Collection Pages

To loop through all items in a collection:

{% raw %}

{% endraw %}

Filtering and Sorting Collections

You can combine Liquid logic and filters to group or sort content:

{% raw %}
{% assign beginner_tutorials = site.tutorials | where: "level", "beginner" %}
{% for tutorial in beginner_tutorials %}
  

{{ tutorial.title }}

{% endfor %} {% endraw %}

Use Case 1: Team Members Listing

Define a _team collection with entries like _team/jane-doe.md:

---
name: Jane Doe
role: SEO Strategist
bio: Jane has 10 years of experience...
image: /assets/team/jane.jpg
layout: null
---

Then render them inside a page:

{% raw %}
{% for member in site.team %}
  
{{ member.name }}

{{ member.name }}

{{ member.role }}

{{ member.bio }}

{% endfor %} {% endraw %}

Use Case 2: Modular Documentation

Create a collection like _docs with nested folders for versioned or modular documentation:

_config.yml
collections:
  docs:
    output: true
    permalink: /docs/:path/

This allows version control by folder structure: _docs/v1/getting-started.md, _docs/v2/getting-started.md.

Customizing Layouts per Collection

Each collection item can specify its own layout, or you can define a default layout for that collection in its template:

{% raw %}
---
layout: tutorial
---
{% endraw %}

Then build custom layouts like _layouts/tutorial.html to reflect the structure or metadata of that collection.

Pagination for Collection Pages

Jekyll’s native pagination works only for posts. To paginate collections, you need third-party plugins or manual slicing using Liquid logic. For example:

{% raw %}
{% assign tutorials = site.tutorials | sort: "date" %}
{% for tutorial in tutorials offset:0 limit:5 %}
  

{{ tutorial.title }}

{% endfor %} {% endraw %}

Mixing Data Files and Collections

Collections can be enhanced with YAML/JSON data files to connect static data with dynamic content. For example, a tutorial can reference tools from _data/tools.yml and display them per item.

Managing Large Projects With Multiple Collections

  • _tutorials: for learning content
  • _products: for product listings
  • _clients: for testimonials
  • _resources: for downloadable assets

Each collection can be versioned, sorted, filtered, and styled independently, giving developers complete control over site structure.

Case Study: A Scalable SaaS Documentation Site

A SaaS company used Jekyll collections to build a developer documentation portal with the following features:

  • Separate folders per API version using collections like _v1_docs and _v2_docs
  • Sidebar navigation auto-generated from the collection's folder structure
  • Global variables injected from data files to avoid hardcoding URLs and labels

The result was a fully static site deployed on GitHub Pages, version-controlled and easy to maintain without a CMS.

Conclusion

Jekyll collections offer unmatched flexibility in structuring and scaling content. Whether you're building a documentation hub, multi-format blog, portfolio site, or directory, collections allow you to isolate concerns and organize your content like a CMS—without the complexity. Mastering collections is essential for any serious Jekyll developer aiming to create maintainable and professional-grade static sites.

using liquid filters for advanced content formatting

Understanding Liquid Filters in Jekyll

Liquid is the templating engine behind Jekyll, and filters are its powerful feature to manipulate content output. By applying filters, you can dynamically transform variables, format text, handle URLs, truncate content, and even perform logic-driven formatting directly inside your templates and posts.

Why Mastering Filters Matters

  • Enables cleaner and more efficient template structures
  • Reduces repetitive HTML and manual formatting
  • Improves maintainability and readability
  • Enhances SEO by controlling how metadata and content are rendered

Core Syntax of Liquid Filters

The basic syntax follows a pipe-style structure where a filter is applied after a variable:

{{ variable | filter }}

Multiple filters can be chained:

{{ variable | filter1 | filter2 }}

Commonly Used Liquid Filters

String Filters

  • capitalize: Capitalizes the first letter
  • upcase: Converts text to uppercase
  • downcase: Converts text to lowercase
  • replace: Replaces one string with another
  • strip_html: Removes all HTML tags
  • truncate: Shortens string to a specific length

Date and Time Filters

Dates in Jekyll are formatted using Liquid's date filter:

{{ page.date | date: "%B %d, %Y" }}

URL and Path Filters

  • relative_url: Resolves relative links
  • absolute_url: Converts to full URL based on site config

Math and Array Filters

  • size: Returns the length of an array or string
  • sort: Sorts arrays
  • join: Joins array elements into a string
  • uniq: Removes duplicates from arrays

Advanced Use Cases

Creating SEO-Friendly Excerpts

Use filters to generate clean summaries for meta descriptions:

{{ content | strip_html | truncatewords: 30 }}

Sanitizing Titles for URL Slugs

Convert post titles into clean, lowercase slugs:

{{ page.title | downcase | replace: ' ', '-' | replace: '.', '' }}

Highlighting Popular Tags

Sort and display most used tags using filter logic:

{% raw %}
{% assign sorted_tags = site.tags | sort: 'size' | reverse %}
    {% for tag in sorted_tags limit:5 %}
  • {{ tag[0] }}
  • {% endfor %}
{% endraw %}

Rendering Author Bios from Data Files

Combine filters to dynamically render authors:

{% raw %}
{% assign author = site.data.authors[page.author] %}

{{ author.name | upcase }}

{{ author.bio | truncate: 100 }}

{% endraw %}

Custom Filters in Jekyll Plugins

If you're using GitHub Pages, you’re limited to safe filters. But in standalone Jekyll builds, you can create your own filters:

Example: Custom Word Count Filter

Create _plugins/word_count_filter.rb:

module Jekyll
  module WordCount
    def wordcount(input)
      input.split.size
    end
  end
end

Liquid::Template.register_filter(Jekyll::WordCount)

Now in your template:

{{ page.content | wordcount }}

Combining Filters for Dynamic Layouts

You can mix filters and conditionals for flexible content control. Example: Display a custom notice only on long articles:

{% raw %}
{% assign word_count = content | strip_html | number_of_words %}
{% if word_count > 2000 %}
  

This article is long and detailed. Use the table of contents to navigate.

{% endif %} {% endraw %}

Liquid Filter Gotchas and Limitations

  • Filters cannot change variables permanently; use assign for that
  • You can’t pass complex logic into filters — they work on simple input
  • Some filters behave differently depending on data type (array vs. string)
  • Custom filters won’t work on GitHub Pages unless part of supported plugins

Case Study: Building a Dynamic Quote Component

A Jekyll site wanted to display rotating quotes in a hero section. Using Liquid filters, the developer built a JSON-driven loop with randomized output using sample and first filters. The final result delivered a fresh motivational message each page load without JavaScript.

Conclusion

Liquid filters are essential tools for anyone building with Jekyll. They allow advanced formatting, dynamic templating, and cleaner site logic — all while reducing redundancy. Mastering these filters unlocks powerful customization options for developers who want to create scalable, SEO-optimized, and easily maintainable sites.

jekyll seo optimization with structured data

Why Structured Data Matters in SEO

Structured data helps search engines understand the context of your content more effectively. By embedding schema markup in your Jekyll site, you give Google and other search engines explicit clues about your site's purpose, content types, and relationships. This increases the chance of rich snippets and better rankings.

What Is Structured Data

Structured data is a standardized format for providing information about a page and classifying its content. The most widely used format is JSON-LD (JavaScript Object Notation for Linked Data), and the most popular schema vocabulary is schema.org.

How Jekyll Sites Can Benefit from Structured Data

  • Increases visibility via enhanced search results (like star ratings, breadcrumbs, and FAQs)
  • Improves click-through rates by providing more information directly in SERPs
  • Ensures compliance with modern SEO standards and Google's requirements

Adding Structured Data to Jekyll Layouts

Step 1: Identify the Schema Type

Choose the appropriate schema type based on the page content. For a blog post, use BlogPosting; for an organization homepage, use Organization; for products, use Product, etc.

Step 2: Create a JSON-LD Block

Insert a JSON-LD script tag into your post or layout. Here’s an example for a blog post:

{% raw %}

{% endraw %}

Using Schema.org Types for Common Jekyll Pages

Homepage

Use WebSite and Organization types to define your brand and domain:

{% raw %}

{% endraw %}

Author Page

Use Person schema to define author bios on their profile pages.

Automating Structured Data with Includes

You can modularize JSON-LD generation using _includes/structured-data.html and load different schemas dynamically:

{% raw %}
{% include structured-data.html schema="blog_posting" %}
{% endraw %}

Inside structured-data.html, use conditionals to load different templates depending on the schema type.

Enhancing SEO Further with Breadcrumb Schema

Breadcrumb structured data improves how your pages appear in search results:

{% raw %}

{% endraw %}

Testing and Validating Structured Data

Before publishing, always validate your structured data using Google's tools:

Case Study: Blog with Featured Snippets

One Jekyll-based blog added BlogPosting and FAQ schema to selected articles. Within three weeks, Google began displaying rich snippets for these articles. This led to a 22% increase in CTR for those URLs and improved engagement from search-driven traffic.

Conclusion

Structured data is no longer optional for websites that aim for top-tier SEO performance. Jekyll makes it easy to add JSON-LD across layouts and posts using Liquid. By systematically implementing the right schema types, you position your content for better visibility, richer appearance in SERPs, and stronger SEO outcomes overall.

jekyll data files for global site control

What Are Jekyll Data Files

Jekyll data files are YAML, JSON, or CSV files stored in the _data folder that hold structured data. This data can be accessed globally across layouts, pages, posts, and includes. It’s a powerful feature for centralizing configuration, managing repeatable content, or generating dynamic content sections without duplicating code.

Why Use Data Files in Jekyll Projects

Data files provide a clean separation between content and logic. Instead of hardcoding information across multiple files, you define it once and reuse it. This improves maintainability, scalability, and reduces the chance of errors when updates are needed.

Setting Up Jekyll Data Files

Step 1: Create the _data Folder

By default, Jekyll looks for data files inside a directory named _data in the root of your project.

mkdir _data

Step 2: Add a YAML File

Let’s say you want to manage your site’s navigation. Create a file called navigation.yml in _data:

- title: Home
  url: /
- title: Blog
  url: /blog/
- title: Projects
  url: /projects/
- title: About
  url: /about/

Step 3: Load Data in a Layout or Include

Use Liquid to loop through the data in your layout:

{% raw %}

{% endraw %}

Use Cases for Jekyll Data Files

1. Navigation Menus

As shown above, you can manage primary and secondary menus from a single source of truth.

2. Team or Staff Directory

Create a team.yml file and loop through members on the about page or a custom staff page.

- name: Alice
  role: Lead Developer
  photo: /images/alice.jpg
- name: Bob
  role: UI Designer
  photo: /images/bob.jpg

3. Pricing Tables

Update pricing packages without touching HTML pages directly.

4. FAQs and Reusable Snippets

Maintain frequently asked questions or commonly used content blocks like product features.

Real-World Example: Multi-Language Site Navigation

A bilingual company site uses two files in _datanavigation_en.yml and navigation_fr.yml. Depending on the user’s language preference (detected via URL prefix), the site loads the appropriate navigation dynamically. This helped the team maintain consistency without duplicating layout logic.

Best Practices for Managing Data Files

  • Use YAML format for readability unless you need arrays or deeply nested structures, where JSON may be clearer.
  • Break large datasets into multiple files for modularity (e.g., separate navigation, team, pricing).
  • Use consistent keys across entries to simplify access and avoid errors.
  • Validate syntax before pushing changes—incorrect indentation can break your build.

Dynamic Includes Using Data

You can use includes that dynamically pull from data. For example, an include like feature-box.html might use values passed from a loop:

{% raw %}
{% for feature in site.data.features %}
  {% include feature-box.html title=feature.title icon=feature.icon %}
{% endfor %}
{% endraw %}

Combining Data Files with Collections

While collections define custom content types, data files can supplement them with external metadata. For example, a podcast collection can pull episode metadata from episodes.yml to enrich layouts.

Limitations to Be Aware Of

  • Data files are read-only at build time; they don’t change dynamically like a CMS.
  • Large or complex datasets can slow down the build process if not structured efficiently.
  • There is no native UI—editing is done directly in the file, requiring careful syntax.

Conclusion

Jekyll data files are essential for creating modular, scalable, and maintainable static websites. They reduce redundancy and offer developers a powerful way to manage content across pages. When used effectively, they make your Jekyll site more dynamic and easier to update—without ever touching your layout files.

custom category pages with jekyll

Why Category Pages Matter

Category pages are essential for content-heavy blogs. They help users explore posts by topic, improve site navigation, and support internal linking structures that benefit SEO. Jekyll doesn’t provide built-in category templates, but it’s flexible enough to let us create them manually or dynamically.

Understanding Categories in Jekyll

In Jekyll, you can assign categories to posts using the front matter. Each post can have one or more categories:

---
title: "Optimizing Images in Jekyll"
categories: [jekyll,performance,media]
---

Jekyll automatically adds category information to each post’s metadata, but it doesn't create category-specific index pages by default.

Option 1: Manual Category Pages

The simplest method is to create a markdown or HTML file for each category manually. For example, for a category called jekyll, create jekyll.html at your site’s root:

---
layout: category
title: "Jekyll Posts"
category: jekyll
permalink: /categories/jekyll/
---

Create a Layout for Category Pages

Create a new layout file _layouts/category.html to filter posts based on category:

{% raw %}

Posts in Category: {{ page.category }}

    {% for post in site.posts %} {% if post.categories contains page.category %}
  • {{ post.title }}
  • {% endif %} {% endfor %}
{% endraw %}

Option 2: Generate Category Pages Automatically

For blogs with many categories, generating category pages automatically is more efficient. Here’s how:

Step 1: Use a Plugin (If Allowed)

If you’re not using GitHub Pages or can run plugins, use jekyll-category-pages or build your own plugin to generate these pages dynamically.

Step 2: Or Use a Generator Script

Create a Ruby or shell script to scan all categories used in your posts and generate a static page for each category with appropriate front matter. Here’s a basic Ruby example:

require 'yaml'
categories = []

Dir.glob("_posts/*") do |file|
  data = YAML.load_file(file)
  categories.concat(data["categories"]) if data["categories"]
end

categories.uniq.each do |category|
  filename = "categories/#{category}.html"
  content = <<~HTML
  ---
  layout: category
  title: "#{category.capitalize} Posts"
  category: #{category}
  permalink: /categories/#{category}/
  ---
  HTML

  File.write(filename, content)
end

Step 3: Link to Category Pages

Once the category pages exist, you can link to them from your posts, sidebar, or footer. You can also list categories dynamically with:

{% raw %}
    {% assign cats = site.categories %} {% for cat in cats %}
  • {{ cat[0] }} ({{ cat[1].size }})
  • {% endfor %}
{% endraw %}

Case Study: Small Blog with Niche Categories

A solo blogger with a library of 200+ posts used dynamic category pages to organize content by topic. Bounce rates dropped by 18%, and users viewed more pages per session. The clarity of site structure made a noticeable impact.

Best Practices for Jekyll Category Pages

  • Use consistent category naming (avoid both singular and plural)
  • Limit the number of categories per post to 1–3 max
  • Add introductory content or SEO text on each category page
  • Generate a sitemap that includes all category pages

Improving SEO with Category Pages

Category pages give you a great opportunity to rank for mid-tail and long-tail keywords. You can include a paragraph or two of keyword-rich content at the top of each category layout before the post list starts.

Conclusion

Creating custom category pages in Jekyll makes your blog easier to explore, supports topic clustering, and helps your SEO efforts. Whether done manually or automatically, they provide structure and context that readers—and search engines—love.

building author archive pages with front matter only

Why Author Archives Matter

Author archive pages give readers a way to explore content from a specific contributor. They’re especially useful for multi-author blogs, collaborative projects, or publications where author voice plays a significant role in content branding.

Jekyll's Challenge with Author Archives

By default, Jekyll does not generate dynamic author pages like WordPress. Plugin-based solutions exist, but on GitHub Pages, plugin usage is limited. So we use front matter fields and Liquid templates to manually define and filter posts by author.

Step 1: Add Author Metadata to Posts

First, ensure every post includes an author field in its front matter. Use a consistent naming convention (e.g., slug or lowercase names):

---
title: "How to Optimize Content for Keywords"
date: 2025-05-10
author: "john-doe"
---

Repeat this for all relevant posts using their respective author identifiers.

Step 2: Create an Author Layout

Create a new layout file in your _layouts directory, for example: _layouts/author.html

Sample author.html layout:

{% raw %}
<h2>Posts by {{ page.author_name }}</h2>
<ul>
  {% assign author = page.author_slug %}
  {% for post in site.posts %}
    {% if post.author == author %}
      <li><a href="{{ post.url }}">{{ post.title }}</a></li>
    {% endif %}
  {% endfor %}
</ul>
{% endraw %}

Step 3: Create Author Pages

In your project root or inside a folder like authors, create separate HTML or Markdown files for each author. For example: john-doe.md

---
layout: author
title: "John Doe"
permalink: /authors/john-doe/
author_slug: "john-doe"
author_name: "John Doe"
---

This setup filters posts by the author field matching author_slug.

Optional: Add Author Bios and Avatars

To personalize author pages further, define a new data file: _data/authors.yml

john-doe:
  name: "John Doe"
  bio: "A technical writer passionate about performance SEO."
  avatar: "/assets/img/john.jpg"

jane-smith:
  name: "Jane Smith"
  bio: "Writes about digital trends and content strategy."
  avatar: "/assets/img/jane.jpg"

Update author layout to pull this info:

{% raw %}
{% assign author_data = site.data.authors[page.author_slug] %}
<div class="author-profile">
  <img src="{{ author_data.avatar }}" alt="{{ author_data.name }}" />
  <p><strong>{{ author_data.name }}</strong></p>
  <p>{{ author_data.bio }}</p>
</div>
{% endraw %}

Step 4: Link to Author Pages from Posts

At the bottom of each post layout, add a link to the author's archive:

{% raw %}
<p>Written by <a href="/authors/{{ page.author }}">{{ page.author }}</a></p>
{% endraw %}

If you’re using a data file for names, you can reference the full name from the author database using:

{% raw %}
{% assign author_info = site.data.authors[page.author] %}
<p>Written by <a href="/authors/{{ page.author }}">{{ author_info.name }}</a></p>
{% endraw %}

Case Study: A Jekyll-Powered Magazine

An online magazine with five recurring contributors used this approach to highlight authors. Each writer had their own archive and bio. They even integrated social media handles into the author profiles for increased engagement. By manually creating these pages, the team avoided plugin dependency and retained GitHub Pages compatibility.

Benefits of Manual Author Pages

  • Plugin-free, works on GitHub Pages
  • Fully customizable layout and style
  • Supports author bios and images

Limitations

  • Requires manual creation of author pages
  • Needs consistent metadata in posts

Best Practices

  • Use slugs for authors instead of full names to avoid URL issues
  • Use a central data file for all author metadata
  • Keep author pages updated as contributors grow

Conclusion

Even without dynamic page generation or plugins, Jekyll allows for robust author archives through smart use of front matter and Liquid logic. It’s a lightweight, future-proof solution ideal for static blogs and multi-author platforms hosted on GitHub Pages or similar environments.

adding related posts section in jekyll

Why Related Posts Boost Engagement

Related posts help retain readers by offering them more content relevant to what they’ve just read. This keeps your bounce rate low and improves session duration—both important behavioral metrics for SEO and audience trust.

How Jekyll Handles Related Posts

Jekyll includes a basic site.related_posts feature, but it only works if you have a _config.yml file with lsi: true and are using certain plugins. This isn't viable on GitHub Pages due to plugin limitations. Instead, you can manually filter related content based on tags or categories using Liquid.

Step 1: Ensure Tags or Categories Exist

To identify related posts, your posts should include consistent tags or categories. Here's an example of proper front matter:

---
title: "How to Start with On-Page SEO"
date: 2025-05-05
categories: [seo,on-page]
tags: [seo,optimization,keywords]
---

Repeat this pattern for all your posts. Tags and categories form the basis for matching.

Step 2: Add Logic to Your Post Layout

Edit your _layouts/post.html (or whatever layout you use for blog posts) and insert this below the post content:

{% raw %}
<h3>Related Posts</h3>
<ul>
{% assign current_tags = page.tags %}
{% for post in site.posts %}
  {% if post.url != page.url %}
    {% assign shared_tags = 0 %}
    {% for tag in post.tags %}
      {% if current_tags contains tag %}
        {% assign shared_tags = shared_tags | plus: 1 %}
      {% endif %}
    {% endfor %}
    {% if shared_tags > 0 %}
      <li><a href="{{ post.url }}">{{ post.title }}</a></li>
    {% endif %}
  {% endif %}
{% endfor %}
</ul>
{% endraw %}

This logic compares the tags of the current post with all other posts and lists those with shared tags. It avoids showing the current post itself.

Step 3: Limit the Number of Related Posts

To avoid overwhelming readers, show only a handful of related posts. Add a counter to limit output:

{% raw %}
{% assign max = 4 %}
{% assign count = 0 %}
<ul>
{% for post in site.posts %}
  {% if post.url != page.url and count < max %}
    {% assign shared = false %}
    {% for tag in post.tags %}
      {% if page.tags contains tag %}
        {% assign shared = true %}
      {% endif %}
    {% endfor %}
    {% if shared %}
      <li><a href="{{ post.url }}">{{ post.title }}</a></li>
      {% assign count = count | plus: 1 %}
    {% endif %}
  {% endif %}
{% endfor %}
</ul>
{% endraw %}

Step 4: Style Your Section

Enhance readability with CSS:

.related-posts {
  margin-top: 2rem;
  border-top: 1px solid #ddd;
  padding-top: 1rem;
}

.related-posts h3 {
  font-size: 1.2rem;
  margin-bottom: 0.5rem;
}

.related-posts ul {
  list-style: none;
  padding-left: 0;
}

.related-posts li {
  margin-bottom: 0.3rem;
}

Apply the related-posts class to the <div> or section surrounding your list.

Case Study: A SEO Blog's Bounce Rate Drop

A niche SEO blog implemented this tag-based related post logic and noticed bounce rates decreased by 17% within 30 days. Readers clicked into more articles, particularly when the related post titles aligned closely with user intent.

Advanced: Use Categories Instead of Tags

If your content is well categorized but not heavily tagged, you can apply the same logic using categories:

{% raw %}
{% for post in site.posts %}
  {% if post.url != page.url and post.categories contains page.categories[0] %}
    <li><a href="{{ post.url }}">{{ post.title }}</a></li>
  {% endif %}
{% endfor %}
{% endraw %}

Best Practices

  • Use clear and consistent tags across all posts
  • Position related posts after content or above comments section
  • Keep link titles short but enticing

Conclusion

Even without dynamic engines or plugins, Jekyll enables useful related post functionality using Liquid alone. This manual approach gives full control over what readers see next, improving engagement and supporting deeper browsing paths throughout your site.

jekyll collections for structured content types

What Are Jekyll Collections

Jekyll collections are a powerful feature that let you define custom content types beyond posts and pages. This is useful when your site needs structured content like documentation, team members, case studies, tutorials, or portfolios—each with its own layout and logic.

Why Use Collections Instead of Posts

Using collections helps separate content logically and provides better maintainability. For example, a blog that also showcases products or tutorials can place these in separate folders with different formatting needs, making the site more organized and scalable.

How to Set Up a Collection in Jekyll

Step 1: Define the Collection in _config.yml

To define a new collection called tutorials, add the following to your config file:

collections:
  tutorials:
    output: true
    permalink: /tutorials/:path/

The output: true option ensures that Jekyll builds HTML pages from your collection items.

Step 2: Create a Directory

Inside your Jekyll root, create a folder named _tutorials. This naming convention is required for Jekyll to recognize it as a collection folder.

mkdir _tutorials

Step 3: Add Markdown or HTML Files

Each file represents one item in the collection:

---
title: "Getting Started with Jekyll"
difficulty: beginner
layout: tutorial
---
Learn how to install Jekyll and create your first site.

Creating a Layout for Collection Items

Create a layout like _layouts/tutorial.html that renders your collection content. It might look like this:

{% raw %}

{{ page.title }}

Difficulty: {{ page.difficulty }}

{{ content }}
{% endraw %}

Displaying Collection Items

You can display all tutorials on an index page with:

{% raw %}
    {% for tutorial in site.tutorials %}
  • {{ tutorial.title }} - {{ tutorial.difficulty }}
  • {% endfor %}
{% endraw %}

Example Use Cases for Jekyll Collections

1. Product Pages

List product specs, reviews, and downloads with different layouts than blog posts.

2. Documentation Sections

Break up user guides into separate collection files that follow a specific structure.

3. Portfolio Projects

Showcase your design or development work with detailed project pages.

Case Study: Developer Portfolio Site

A freelance developer created a Jekyll site with three collections: _projects, _clients, and _snippets. This setup helped separate personal projects from paid work and allowed custom filters and category pages per type. The site felt more structured and increased time-on-site metrics by 40%.

Managing Complex Data with Front Matter

Collections support rich front matter. You can include nested data like arrays or objects to store FAQs, technologies used, or metadata:

---
title: "REST API Tutorial"
tags: [api,backend,web]
tools:
  - name: Postman
    use: Testing
  - name: Express
    use: Server
---

Pagination and Collections

Jekyll does not support native pagination for collections, but you can use the jekyll-paginate-v2 plugin to add pagination functionality to collections.

Best Practices for Collections

  • Use collections to group similar content types that don’t belong in blog posts.
  • Always give collections their own layout to keep templates clean.
  • Use rich front matter to make filtering and displaying items easier.
  • Combine with data files or Liquid logic for powerful display options.

Conclusion

Jekyll collections are essential for building more advanced, structured sites. Whether you're building a portfolio, documentation site, or something entirely custom, collections help you organize your content clearly, enabling better design, readability, and SEO.

adding estimated reading time to blog posts

Why Display Reading Time Matters

Readers appreciate knowing how long a post will take to read. It's a simple UX improvement that builds trust, encourages time commitment, and increases the likelihood of someone reading through to the end.

How to Calculate Reading Time in Jekyll

Since Jekyll is a static site generator, we don’t have JavaScript or server-side logic by default. However, we can use Liquid to calculate the number of words and estimate reading time during build.

Step 1: Estimate Words per Minute

The average reading speed is 200–250 words per minute. For simplicity, we’ll assume 200 words per minute (wpm).

Step 2: Add Reading Time Logic in Post Layout

Open your _layouts/post.html and insert the following block wherever you want the reading time to appear—commonly below the post title or date.

{% raw %}
{% assign words = page.content | number_of_words %}
{% assign minutes = words | divided_by:200 %}
{% if minutes == 0 %}
  <p>Estimated reading time: less than 1 min</p>
{% else %}
  <p>Estimated reading time: {{ minutes }} min</p>
{% endif %}
{% endraw %}

This uses a built-in Jekyll filter number_of_words to count words and then divides by 200.

Step 3: Alternative Manual Word Count Filter

Some older versions of Jekyll or custom builds may not support number_of_words. Here’s a workaround using size and split:

{% raw %}
{% assign words = page.content | strip_html | strip_newlines | split: ' ' %}
{% assign minutes = words | size | divided_by:200 %}
{% if minutes == 0 %}
  <p>Estimated reading time: less than 1 min</p>
{% else %}
  <p>Estimated reading time: {{ minutes }} min</p>
{% endif %}
{% endraw %}

This approach is more reliable across Jekyll versions and doesn’t require plugins.

Step 4: Make the Design Subtle

Place reading time information within a muted style to avoid overpowering your title or metadata. Here’s a simple CSS suggestion:

.reading-time {
  font-size: 0.9rem;
  color: #777;
  margin-bottom: 1rem;
}

Wrap your reading time block in a <div class="reading-time"> to apply this styling cleanly.

Case Study: UX Improvements on a Tech Blog

A technical blog that added reading time below titles observed a 12% improvement in scroll depth and 8% reduction in bounce rate. Readers were more willing to start articles when they knew what to expect, especially on mobile devices.

Best Practices

  • Keep estimates consistent with your average post length
  • Round up reading time to the nearest minute for simplicity
  • Don’t distract the reader—keep it subtle and brief

Optional: Show Word Count Too

If you think your audience is interested in content size (e.g., developers or academics), you might also display total word count:

{% raw %}
<p>{{ words | size }} words, approx. {{ minutes }} min read</p>
{% endraw %}

Conclusion

Estimated reading time is a small feature with a significant payoff. With a few lines of Liquid, you can set expectations and subtly encourage users to commit to reading your content—leading to higher engagement and retention on your Jekyll site.