Lesson 5 - Related Posts
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.
By default, the Eleventy base blog comes with pagination between posts. Post 2 can take you to posts 1 and 3, etc.
While that is useful for this site, when building another site I wanted to see a couple randomly-suggested posts that shared 1 or more tags.
I started by referring to this GitHub issue about related posts. I had to fix a few errors that arose from the suggested code.
I also wanted to make two changes:
- I didn't want to just see posts that shared all tags, but rather posts that shared any tag
- I wanted to randomly add a few posts instead of just getting whatever was first (with a shared tag) in the post order
filters.js
After adjusting for those needs, I had the following in filters.js:
eleventyConfig.addNunjucksFilter("excludeFromCollection", function (collection=[], pageUrl=this.ctx.page.url) {
return collection.filter(post => post.url !== pageUrl);
});
eleventyConfig.addFilter("filterByTags", function(collection=[], ...requiredTags) {
return collection.filter(post => {
return requiredTags.flat().some(tag => post.data.tags.includes(tag));
});
});
eleventyConfig.addFilter("randomize", function(array) {
// Create a copy of the array to avoid modifying the original
let shuffledArray = array.slice();
// Fisher-Yates shuffle algorithm
for (let i = shuffledArray.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffledArray[i], shuffledArray[j]] = [shuffledArray[j], shuffledArray[i]];
}
return shuffledArray;
});
post.njk
I used this in my post layout. filterTagList comes with the base blog by default, and removes the tags "posts" and "all." head is also a built in.
% set relevantTags = tags | filterTagList %
% set postlist = collections.posts | filterByTags(relevantTags) | excludeFromCollection(page.url) | randomize | head(2) %
% if postlist.length %
<section class="related-posts">
<h2>related posts</h2>
% include "postlist.njk" %
</section>
% endif %
Lesson 7 - Pagination
Lesson 0 - Front Matter and URLs