Generate Pages For Your Categories In Jekyll Automatically
My goal here is to dynamically generate pages like /categories/code/, that would list all articles categorized in code
. As far as I can tell, there’s no standard way. I found a few articles explaining how to create such pages for a given category, but none regarding how to auto-generate them for all your categories.
For this purpose, I resorted to some scripting, which through the power of CI, is completely transparent.
The process is:
- Create layout for category page
- Generate a JSON file containing the list of categories.
- Generate a page for each category using the layout in 1.
- jekyll build
Layout
The layout I used ressembles a lot the layout of the home page. In the _layouts
folder of Jekyll, I created this file:
---
layout: default
---
<div class="home">
{{ content }}
<h2>About "{{page.category}}"</h2>
<ul class="post-list">
&lcur;% for post in site.categories.&lbra;page.category] %}
<li>
<a href=""><span class="post-title">{{ post.title | escape }}</span><br/>
<span class="post-meta">{{ post.date | date: "%Y-%b-%-d" }} | {{ post.categories | array_to_sentence_string }}</span>
</a>
</li>
{% endfor %}
</ul>
</div>
This basically iterates through the posts of a category contained in property category
of a given page using this layout.
Category list
In my assets
folder, I created an assets.json
file with the following contents:
---
---
{
"categories": [
"Personal development",
"Continuous improvement",
"Sport",
"Career",
"Psychology",
"Code",
"Reading notes",
"Business",
"Delivery",
"Process",
"Code like a monkey",
"Hiring",
"Design patterns",
"Organization",
"Self improvement",
"Management",
"Source control",
"Devops",
"Coffee script",
"Functional programming",
"Node.js",
"Slack",
"WIP",
"Azure",
"Bot",
"Security",
"Flow",
"Small batches",
"Product management",
"CI",
"AWS",
"Physics",
"KSP",
"Azure functions",
"Space",
"Lambda",
"Git",
".Net",
"Jekyll",
"Webapps",
"Speed",
"Agile",
"DevOps",
"Smells",
"Memo",
"Architecture",
"VSTS",
"Quick note",
"Software",
"Coding",
"Geek",
"Linux",
"Windows",
"Development",
"Authentication and authorization",
"App Services",
"Cloud",
"Other",
"API Management",
"Tools",
"Self organization",
"Performance",
"expload",
"Engineering",
"Microservices",
"Modernization",
"Refactoring",
"Rearchitecting",
"Quick post",
"Systems",
"Game",
"Kubernetes",
"Containers",
"Patterns",
"Docker",
"AKS",
"StuffIBuilt",
"Random",
"Automation",
"Social sciences",
"Documentation",
"LogicApps",
"Lean",
"Product Flow",
"Product Management",
"Marketing",
"Build",
"Sociology",
"History",
"SOPs",
"Opinion",
"Training",
"business",
"priorities",
"meetings",
"Productivity",
"biology",
"code",
"Goals",
"Communication",
"GTD",
"organization",
"workflow",
"Continuous Improvement",
"Peculiar Ways",
"Work",
"Happiness",
"development tools",
"goals",
"principles",
"leadership",
"management",
"sociology",
"common sense",
"bias",
"psychology",
"engineering",
"I am a pedantic ass",
"semantics",
"machine learning",
"hide",
"pattern",
"law",
"Shit post",
"Statistics",
"Interviewing",
"Human Management",
"Planning",
"delivery",
"process",
"product management",
"Human management",
"Philosophy",
"Time management",
"Policy",
""
]
}
The ---
tell Jekyll to build the file. The rest is just simple liquid. When building, the result looks like this.
Generate a page for each category
The page is plain and simple:
---
layout: category
category: Code
---
We just need to generate one for each in a categories
folder, so that they can be accessed through /categories/code/
.
Let’s start with a simple node script running through the categories.json
:
const path = require("path");
const fs = require("fs");
const categoryFile = path.join("_site", "assets", "categories.json");
const categoryFolder = path.join("categories");
const categoryContent = fs.readFileSync(categoryFile).toString();
const deserializedCategories = JSON.parse(categoryContent);
const categories = deserializedCategories.categories;
categories.forEach(function(category) {
if (category === "")
return;
const content = "---\nlayout: category\ncategory: " + category + "\n---";
const file = path.join(categoryFolder, category + ".md");
fs.writeFileSync(file, content);
});
I then invoke that in my build script:
#!/usr/bin/env bash
function build {
if [ "$1" != "--refresh" ]; then
jekyll build --incremental
else
jekyll build
fi
}
function updateCategoryPages {
if [ -d "categories" ]; then
rm -rf categories
fi
mkdir categories
node build/updateCategories.js
}
build
updateCategoryPages
build
The first build is going to generate the categories.json
file. Then we iterate through it and generate files. Then we build again.
Having my build done on Codeship, all I need to do is push and this is done automagically.