Skip to content

Instantly share code, notes, and snippets.

@solace
Last active September 23, 2023 08:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save solace/61685cfd85b0cd301ec9608610695b4c to your computer and use it in GitHub Desktop.
Save solace/61685cfd85b0cd301ec9608610695b4c to your computer and use it in GitHub Desktop.
Support categories and tags migrated from WordPress in Eleventy. See https://micheleong.com/2023/09/23/migrate-wordpress-eleventy-colocated-images
// File: lib/collections/categories.js
const slugify = require("slugify");
const getAllKeyValues = require("../utils/getAllKeyValues");
module.exports = (collection) => {
let allCategories = getAllKeyValues(
collection.getFilteredByGlob("src/posts/**/*.md"),
"categories"
);
return allCategories.map((category) => ({
title: category,
slug: slugify(category),
}));
};
---
layout: default
permalink: /category/index.html
---
<h1 class="text-3xl text-center font-bold leading-normal mt-0 mb-3">Categories</h1>
<div class="mt-3 text-center">
{% for category in collections.categories %}
<a href="{{ '/category/' | url }}{{ category.slug }}" class="inline-block bg-slate-200 rounded-full px-3 py-1 text-sm font-medium m-0.5">{{ category.title }}</a>
{% endfor %}
</div>
---
layout: default
eleventyExcludeFromCollections: true
pagination:
data: collections.pagedPostsByCategory
size: 1
alias: paged
permalink: "/category/{{ paged.category.slug }}/{% if paged.number > 1 %}{{ paged.number }}/{% endif %}index.html"
---
<h1 class="text-3xl text-center font-bold leading-normal mt-0 mb-3">Category: {{ paged.category.title }}</h1>
<div class="flex flex-wrap -mx-2">
{% include "partials/post-grid.njk" %}
</div>
{% if collections.pagedPostsByCategory[paged.category.slug].length > site.paginate %}
{% include "partials/paginator.njk" %}
{% endif %}
module.exports = eleventyConfig => {
...
// Add custom categories and hashtag collections
config.addCollection('categories', require('./lib/collections/categories'));
config.addCollection('pagedPostsByCategory', require('./lib/collections/pagedPostsByCategory'));
config.addCollection("hashtags", require('./lib/collections/hashtags'));
config.addCollection('pagedPostsByHashtag', require('./lib/collections/pagedPostsByHashtag'));
...
};
// File: lib/utils/getAllKeyValues.js
// Source: https://www.webstoemp.com/blog/basic-custom-taxonomies-with-eleventy/
const lodash = require("lodash");
/**
* Get all unique key values from a collection
*
* @param {Array} collectionArray - collection to loop through
* @param {String} key - key to get values from
*/
module.exports = function getAllKeyValues(collectionArray, key) {
// get all values from collection
let allValues = collectionArray.map((item) => {
return item.data[key] ? item.data[key] : [];
});
// flatten values array
allValues = lodash.flattenDeep(allValues);
// to lowercase
allValues = allValues.map((item) => item.toLowerCase());
// remove duplicates
allValues = [...new Set(allValues)];
// order alphabetically
allValues = allValues.sort(function (a, b) {
return a.localeCompare(b, "en", { sensitivity: "base" });
});
// return
return allValues;
};
// File: lib/collections/hashtags.js
const slugify = require("slugify");
const getAllKeyValues = require("../utils/getAllKeyValues");
module.exports = (collection) => {
let allHashtags = getAllKeyValues(
collection.getFilteredByGlob("src/posts/**/*.md"),
"hashtags"
);
return allHashtags.map((hashtag) => ({
title: hashtag,
slug: slugify(hashtag),
}));
};
// File: lib/filters/include.js
const lodash = require("lodash");
/**
* Select all objects in an array
* where the path includes the value to match
* capitalisation and diacritics are removed from compared values
*
* @param {Array} arr - array of objects to inspect
* @param {String} path - path to inspect for each object
* @param {String} value - value to match
* @return {Array} - new array
*/
module.exports = function (arr, path, value) {
value = lodash.deburr(value).toLowerCase();
return arr.filter((item) => {
let pathValue = lodash.get(item, path);
pathValue = Array.isArray(pathValue) ? pathValue : [pathValue];
pathValue = pathValue.map((v) => lodash.deburr(v).toLowerCase());
return pathValue.includes(value);
});
};
// File: lib/collections/pagedPostsByCategory.js
const siteData = require('../../src/_data/site');
const includes = require('../filters/include');
module.exports = (coll) => {
const allPosts = require('./posts')(coll);
const categoryList = require('./categories')(coll);
const maxPostsPerPage = siteData.paginate;
const pagedPosts = [];
categoryList.forEach((category) => {
const taggedPosts = includes(allPosts, "data.categories", category.title).reverse();
const numberOfPages = Math.ceil(taggedPosts.length / maxPostsPerPage);
for (let pageNum = 1; pageNum <= numberOfPages; pageNum++) {
const sliceFrom = (pageNum - 1) * maxPostsPerPage;
const sliceTo = sliceFrom + maxPostsPerPage;
pagedPosts.push({
category,
number: pageNum,
posts: taggedPosts.slice(sliceFrom, sliceTo),
first: pageNum === 1,
last: pageNum === numberOfPages
});
}
});
return pagedPosts;
};
// File: lib/collections/pagedPostsByHashtag.js
const siteData = require('../../src/_data/site');
const includes = require('../filters/include');
module.exports = (coll) => {
const allPosts = require('./posts')(coll);
const hashtagList = require('./hashtags')(coll);
const maxPostsPerPage = siteData.paginate;
const pagedPosts = [];
hashtagList.forEach((hashtag) => {
const taggedPosts = includes(allPosts, "data.hashtags", hashtag.title).reverse();
const numberOfPages = Math.ceil(taggedPosts.length / maxPostsPerPage);
for (let pageNum = 1; pageNum <= numberOfPages; pageNum++) {
const sliceFrom = (pageNum - 1) * maxPostsPerPage;
const sliceTo = sliceFrom + maxPostsPerPage;
pagedPosts.push({
hashtag,
number: pageNum,
posts: taggedPosts.slice(sliceFrom, sliceTo),
first: pageNum === 1,
last: pageNum === numberOfPages
});
}
});
return pagedPosts;
};
---
layout: default
eleventyExcludeFromCollections: true
pagination:
data: collections.pagedPostsByHashtag
size: 1
alias: paged
permalink: "/tag/{{ paged.hashtag.slug }}/{% if paged.number > 1 %}{{ paged.number }}/{% endif %}index.html"
---
<h1 class="text-3xl text-center font-bold leading-normal mt-0 mb-3">Tagged with: {{ paged.hashtag.title }}</h1>
<div class="flex flex-wrap -mx-2">
{% include "partials/post-grid.njk" %}
</div>
{% if collections.pagedPostsByHashtag[paged.hashtag.slug].length > site.paginate %}
{% include "partials/paginator.njk" %}
{% endif %}
---
layout: default
permalink: /tag/index.html
---
<h1 class="text-3xl text-center font-bold leading-normal mt-0 mb-3">Tags</h1>
<div class="mt-3 text-center">
{% for tag in collections.hashtags %}
<a href="{{ '/tag/' | url }}{{ tag.slug }}" class="inline-block bg-slate-200 rounded-full px-3 py-1 text-sm font-medium m-0.5">#{{ tag.title }}</a>
{% endfor %}
</div>
<ul>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment