Skip to content

Instantly share code, notes, and snippets.

@robweychert
Last active July 25, 2024 16:40
Show Gist options
  • Save robweychert/98cd6ddd8675c9ff645c311bd636c604 to your computer and use it in GitHub Desktop.
Save robweychert/98cd6ddd8675c9ff645c311bd636c604 to your computer and use it in GitHub Desktop.
Custom collections in Eleventy based on your posts’ front matter
module.exports = function(eleventyConfig) {
// Make a custom collection based on a key in your posts' front matter
function addCollectionByKey(collectionName, postKey, paginate=true, postsPerPage=100) {
eleventyConfig.addCollection(collectionName, function(collectionApi) {
const collectionObjects = {};
let collectionFinal = [];
// Filter the posts that have the chosen key in their metadata
let collectionPosts = collectionApi.getAll().filter(function(post) {
return postKey in post.data;
});
// Sort the posts in descending order by date
// (Comment this part out if date is unavailable or irrelevant)
collectionPosts = collectionPosts.sort(function(a, b) {
return b.date - a.date;
});
// Loop through the posts
collectionPosts.forEach(function(post) {
let postValue = post.data[postKey]; // The chosen key's value in the current post
// If the chosen key is `date`, the value needs some manipulation
if (postKey === "date") {
const postDate = new Date(post.data.date);
// postValue = "YYYY/MM";
postValue = postDate.getFullYear().toString() + "/" + (postDate.getMonth() + 1).toString().padStart(2, "0");
}
// This function finds every unique value (tag) associated with the chosen key
function collectionizeTag(tag) {
// If the tag isn't represented in collectionObjects,
// make it a key in collectionObjects with an empty array value
if (!collectionObjects.hasOwnProperty(tag)) {
collectionObjects[tag] = [];
}
// Add the current post to the array associated with this tag
collectionObjects[tag].push(post);
}
// If the chosen key has multiple tags
if (typeof postValue === "object") {
// Loop through the tags and run collectionizeTag on each tag
for (let i = 0; i < postValue.length; i++) {
collectionizeTag(post.data[postKey][i]);
}
// Otherwise run collectionizeTag on the key's single tag
} else {
collectionizeTag(postValue);
}
});
/*
collectionObjects now looks something like this:
{
"tag1": [ {post2}, {post1} ],
"tag2": [ {post2}, {post1} ]
}
*/
// If you want each tag archive to be paginated, the contents of
// collectionObjects need to be reformatted
if (paginate) {
// Loop through the tags
for (const tag in collectionObjects) {
let page = 0;
// Loop through the posts associated with the tag
for (let i = 0; i < collectionObjects[tag].length; i++) {
// Determine how many total pages there will be based on
// the number of posts and postsPerPage
let pageTotal = Math.ceil(collectionObjects[tag].length / postsPerPage);
// If this is the first post, or the current page is at capacity, add a new page
if (page === 0 || collectionFinal[collectionFinal.length - 1]["pageData"].length === postsPerPage) {
page++;
collectionFinal.push({"name": tag, "pageNumber": page, "pageTotal": pageTotal, "pageData": []});
}
// Add this post to the latest page
collectionFinal[collectionFinal.length - 1]["pageData"].push(collectionObjects[tag][i]);
}
// Reset the page count for each tag
page = 0;
}
/*
collectionFinal now looks something like this:
[
{ "name": "tag1", "pageNumber": 1, "pageTotal": 2, "pageData": [ {post4}, {post3} ] },
{ "name": "tag1", "pageNumber": 2, "pageTotal": 2, "pageData": [ {post2}, {post1} ] },
{ "name": "tag2", "pageNumber": 1, "pageTotal": 2, "pageData": [ {post4}, {post3} ] },
{ "name": "tag2", "pageNumber": 2, "pageTotal": 2, "pageData": [ {post2}, {post1} ] }
]
*/
// If each tag archive doesn't need to be paginated,
// no reformatting is necessary
} else {
collectionFinal = collectionObjects;
}
return collectionFinal;
});
};
addCollectionByKey("postsByMonth", "date");
addCollectionByKey("postsByTopic", "topic", false);
---
pagination:
data: collections.postsByMonth
size: 1
alias: month
permalink: "/blog/{{ month.name }}/{% if month.pageNumber %}{{ month.pageNumber }}/{% endif %}"
layout: layouts/base.njk
---
<h1>Month: “{{ month.name }}” {% if month.pageNumber %}({{ month.pageNumber }} of {{ month.pageTotal }}){% endif %}</h1>
{% set monthArchives = month.pageData %}
<ul>
{% for post in monthArchives %}
<li>{{ post.fileSlug }}</li>
{% endfor %}
</ul>
---
pagination:
data: collections.postsByTopic
size: 1
alias: topic
permalink: "/blog/topic/{{ topic | slugify }}/ %}"
layout: layouts/base.njk
---
<h1>Topic: “{{ topic }}”</h1>
{% set topicArchives = collections[postsByTopic][topic] %}
<ul>
{% for post in topicArchives %}
<li>{{ post.data.title }}</li>
{% endfor %}
</ul>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment