Lesson 7 - Pagination
There appears to be a bug where the Nunjucks templating language can't be rendered properly in
<pre>blocks. Because of this, I will be excerpting the curly bracket-percent sign combos and replacing them with only percent signs. Wherever you see a percent sign in .njk code, add the relevant opening or closing curly bracket. I will also be replacing the double curly brackets with single curly brackets.
Simple pagination
Post pagination in Eleventy is pretty straightforward, mostly requiring some specific front matter.
The home page pagination I have set up here looks like the following (in index.njk):
---
pagination:
data: collections.posts
size: 6
alias: posts
reverse: true
---
6 posts per page, paginate data from collections.posts which we'll call just posts for short, and do it in reverse (aka, most recent posts show first).
You'll also likely want previous and next buttons. I did. Here's what I have:
% if pagination.href.previous or pagination.href.next %
<nav aria-label="pagination">
<ol class="pagination">
<li>
% if pagination.href.previous %
<a href="{ pagination.href.previous }"><< Previous</a>
% else %
<< Previous
% endif %
</li>
<li>
% if pagination.href.next %
<a href="{ pagination.href.next }">Next >></a>
% else %
Next >>
% endif %
</li>
</ol>
</nav>
% endif %
Complex pagination
However, there's a catch. Tag pages are created via pagination! It's a lot harder to paginate those - you can't just use the front matter to set it up.
I untangled this GitHub issue about double-layered pagination and came to the following solution...
eleventy.config.js
In eleventy.config.js:
// note that this uses the lodash.chunk method, so you’ll have to require that
eleventyConfig.addCollection("doublePagination", function(collection) {
// Get unique list of tags
let tagSet = new Set(collection.getAllSorted().flatMap((post) => post.data.tags || []));
// Get each item that matches the tag
let paginationSize = 6;
let tagMap = [];
let tagArray = [...tagSet];
for( let tagName of tagArray) {
let tagItems = collection.getFilteredByTag(tagName);
let pagedItems = lodashChunk(tagItems.reverse(), paginationSize); // console.log( tagName, tagItems.length, pagedItems.length );
for( let pageNumber = 0, max = pagedItems.length; pageNumber < max; pageNumber++) {
tagMap.push({
tagName: tagName,
pageNumber: pageNumber,
pageSize: pagedItems.length,
pageData: pagedItems[pageNumber]
});
}
}
//console.log( tagMap );
return tagMap;
});
tag-pages.njk
In my tag-pages.njk file (or whatever you use to template out your tag pages):
---
pagination:
data: collections.doublePagination
size: 1
alias: tag
eleventyComputed:
permalink: /tags/{ tag.tagName | slugify }/% if tag.pageNumber %{ tag.pageNumber + 1 }/% endif %
title: "Posts tagged { tag.tagName }"
eleventyExcludeFromCollections: true
---
<h1>Posts tagged “{ tag.tagName }”</h1>
% set postlist = tag.pageData %
% include "postlist.njk" %
<nav aria-label="pagination">
<ol class="pagination">
<li>
% if tag.pageNumber > 0 %
<a href="{ pagination.href.previous }">Previous</a>
% else %
Previous
% endif %
</li>
<li>
% if tag.pageNumber < tag.pageSize - 1 %
<a href="{ pagination.href.next }">Next</a>
% else %
Next
% endif %
</li>
</ol>
</nav>
Note the pagination checking tag.pageNumber against tag.PageSize - the original suggested solution in the GitHub post creates an issue where the pagination loops through all of the tag pages bit-by-bit. This sorts that - hat tip to TheReyzar who mentioned the issue and showed part of their solution.
filters.js
Finally, in my filters.js file, I add the doublePagination tag to the tags that get filtered using filterTagList:
eleventyConfig.addFilter("filterTagList", function filterTagList(tags) {
return (tags || []).filter(tag => ["all", "posts", "doublePagination"].indexOf(tag) === -1);
});
Lesson 5 - Related Posts
Lesson 0 - Front Matter and URLs