jekyll-collection-pages adds automated index pages, layout selection, and optional pagination for any Jekyll collection. In a few minutes you can stand up front-matter key based landing pages like “tags” or “categories” that stay in sync with your content.
Add the gem to your site’s Gemfile:
gem 'jekyll-collection-pages'
Enable the plugin in _config.yml:
plugins:
- jekyll-collection-pages
Ensure the collections you plan to index have output: true so the generated pages can link to the documents.
Add a collection_pages entry for each collection/field combination you want to index:
collections:
docs:
output: true
collection_pages:
- collection: docs
field: category
path: docs/category
layout: category_layout.html
paginate: 6
Key options:
collection: collection label (matches collections config).field: front-matter key to group documents (string or list values).path: base folder for generated pages (relative to site root).layout: layout in _layouts/ (defaults to collection_layout.html).paginate: optional integer for per-page pagination.You can declare multiple entries—single collection with many fields, or multiple collections:
collection_pages:
- collection: docs
field: category
path: docs/category
layout: category_layout.html
paginate: 6
- collection: articles
field: tags
path: articles/tags
layout: tags_layout.html
paginate: 10
Run bundle exec jekyll serve and visit the generated paths, e.g. /docs/category/getting-started/. The plugin injects these variables into layouts:
page.tag: value of the current field.page.posts: documents in that field bucket.page.paginator: pagination data when paginate is set (same shape as Jekyll paginator).
---
layout: default
---
<h1>{{ page.tag }}</h1>
<ul>
{% for doc in page.posts %}
<li><a href="{{ doc.url | relative_url }}">{{ doc.data.title }}</a></li>
{% endfor %}
</ul>
Every build populates a hash at site.data.collection_pages[collection][field] that contains:
template → the sanitized template the generator used (/docs/category/:field/index.html for unpaginated configs, /docs/category/:field/page:num/index.html when paginate is positive).permalink → the sanitized template for the index with placeholders intact (:num never appears here because it always points to page 1, e.g. /docs/category/:field/)pages → documents grouped by label ({ label => [documents...] })labels: metadata describing the generated index pagesIterate through the documents for a field:
{% assign docs_info = site.data.collection_pages.docs.category %}
{% for entry in docs_info.pages %}
{% assign label = entry | first %}
{% assign documents = entry | last %}
<h2>{{ label }}</h2>
<p>{{ documents.size }} docs</p>
{% endfor %}
Pair the documents with their metadata when you need generated URLs or pagination helpers:
{%- assign info = site.data.collection_pages.articles.tags %}
{% for entry in info.pages %}
{% assign label = entry | first %}
{% assign documents = entry | last %}
{% assign meta = info.labels[label] %}
<h2> <a href="{{ meta.index.url | relative_url }}">{{ label }}</a> ({{ documents.size }})</h2>
<ul>
{% for entry in documents %}
<li><a href="{{ entry.url }}">{{ entry.title }}</a></li>
{% endfor %}
</ul>
{% endfor %}
Or create the links to the generated documents by subsituting the path:
{%- assign info = site.data.collection_pages.articles.tags %}
{%- assign index_permalink = site.data.collection_pages.articles.tags.permalink %}
{% for entry in info.pages %}
{% assign label = entry | first %}
{% assign documents = entry | last %}
{% assign tag_url = index_permalink | replace: ':field', label %}
<h2> <a href="{{ tag_url | relative_url }}">{{ label }}</a> ({{ documents.size }})</h2>
<ul>
{% for entry in documents %}
<li><a href="{{ entry.url }}">{{ entry.title }}</a></li>
{% endfor %}
</ul>
{% endfor %}