Layout recipes

Practical Liquid patterns for rendering collection indexes, pagination, and integrations.

Use these recipes to tailor the generated pages, hook into pagination, or integrate with other plugins.

Category/tag layout template


---
layout: default
---
<header class="collection-header">
  <h1>{{ page.tag }}</h1>
  <p>{{ page.posts | size }} items</p>
</header>

<section class="collection-grid">
  {% for doc in page.posts %}
    <article class="collection-card">
      <h2><a href="{{ doc.url | relative_url }}">{{ doc.data.title }}</a></h2>
      <p>{{ doc.data.excerpt }}</p>
    </article>
  {% endfor %}
</section>

{% if page.paginator %}
  <nav class="collection-pagination">
    {% if page.paginator.previous_page_path %}
      <a href="{{ page.paginator.previous_page_path | relative_url }}">Previous</a>
    {% endif %}
    <span>Page {{ page.paginator.page }} of {{ page.paginator.total_pages }}</span>
    {% if page.paginator.next_page_path %}
      <a href="{{ page.paginator.next_page_path | relative_url }}">Next</a>
    {% endif %}
  </nav>
{% endif %}

previous_page_path and next_page_path already include the generated tag directory, so | relative_url expands to the correct absolute link no matter how deeply nested the index lives.


{% assign info = site.data.collection_pages.docs.category %}

{% for entry in info.pages %}
  {% assign label = entry | first %}
  {% assign documents = entry | last %}
  {% assign meta = info.labels[label] %}
  <div class="category-summary">
    <h2>{{ label }}</h2>
    <p>{{ documents.size }} docs</p>
    <a href="{{ meta.index.url | relative_url }}">View all</a>
  </div>
{% endfor %}

Dynamic includes

If you already have a post-index.html include that expects site.tags-style input, the plugin’s data map just works. Pass the metadata map when you want each section to know its generated URL:


{% include post-index.html
   collection=site.data.collection_pages.articles.tags.pages
   collection_permalink=site.data.collection_pages.articles.tags.permalink
   replace_value=":field"
   meta=site.data.collection_pages.articles.tags.labels %}

SEO & sitemap integration

jekyll-seo-tag reads page.title, so set it for nicer previews:


---
layout: default
title: "{{ page.tag }} – {{ site.title }}"
---
{% seo title=false %}

jekyll-sitemap includes generated pages automatically. To exclude a path:

defaults:
  - scope:
      path: "docs/category"
    values:
      sitemap: false

Multilingual layouts

When you maintain per-language collections, add a language code to your layouts:


{% assign fr_info = site.data.collection_pages.docs_fr.category %}
{% assign fr_page = fr_info.labels[page.tag] %}
{% if fr_page %}
  <link rel="alternate" hreflang="fr" href="{{ fr_page.index.url | relative_url }}">
{% endif %}

Performance hints

  • Use the exported data maps instead of iterating over site.pages to find generated pages.
  • When rendering large grids, pre-sort with Liquid filters.
  • Cache expensive loops in includes using capture if they are reused in multiple sections.