In my previous post, I have demonstrated how we can easily setup a Jekyll blog hosted in GitHub Pages. I will explain how I implemented the automatic tag and archive page generation within the constraints imposed by GitHub Pages. Also, I will show how I ended up using GitHub to store and serve my blog comments as well.
But, before I explain the automatic “way” of doing it, I should probably mention the end goal. In other words, the manual way of doing the whole thing. From there, we will see how much of we can automate.
As a very first thing, I need to store the mapping between url friendly tag name and display text of a tag. Example-
tagging a content with
github-pages will display as
GitHub Pages to the user. Similarly, tagging with
di will display
Dependency Injection. You have probably guessed that I will be using the url friendly tag names in my URL.
Jekyll provides a special folder called
_data for storing data. If it does not exist, you can obviously create one.
I simply created a file in that folder called
tags.yml. Content of this file is a static mapping between a tag’s url friendly name and
display text. Here is a snippet of this file:
This is the convention I chose. You may come up with your own way of storing the information- it really doesn’t matter.
After completing my mapping inside
data/tags.yml file, I created a folder in the root directory called
Inside this folder, I have a file called
index.html which contains the following html code (technically, this is not just html, rather
a liquid template code with front-matter yml):
This simple code snippet will handle the request to URL
http://mysite.com/tags/ and will list all the tags available in the site
with post count beside each tag. I am also generating URL like
http://mysite.com/tags/<url-friendly-tag-name> for all the tags.
However, these pages do not exist. I need to create the pages inside
/tags/ folder for each tag that I have on my site. This does
sound like a repetitive task and hence, I am going to automate it. Before I do that, I realize that all the tag pages I am about to generate
will have basically same functionality. That is- display the posts tagged with this tag. So, I can even move this whole logic inside a layout
file and keep only the varying part inside the tag files. Sounds like a good plan and I will have more centralized control over the tag pages
content. So, I ended up creating a layout file named
/_layouts folder. This layout file contains the following code:
Now, all that is left is to generate files for each tag in the site that uses this layout. Having a layout file to handle most of the rendering logic
simplifies individual files to a great deal. For example- to handle URL
http://mysite.com/tags/github-pages, I need to create a file
/tags/github-pages.md with the content:
But, I am not going to create all the tag files by hand. In fact, I am not going to create any of them. Instead, I wrote a small NodeJS script to do that for me. Here is a quick and dirty script for generating all the tag files that you need:
The above function returns a promise, which you can either wait for being resolved or chain with other tasks that you may have. You can run this above NodeJS script using from your local machine to generate all the tag files you will need. However, if you want to go really pro, you can have Travis-CI looking into your GitHub repository after every push to the repository have it run the above NodeJS script to create the tag files and push it back to your repository. Guess what? That’s what I did. Please go ahead and have a look at the github repository for this blog to see how everything fit together.
One small thing, I also wanted to display the tags for a post in the home page under the tile of each post and also at the bottom of each
post page. In both cases, I need to generate almost exactly same html. So, I create an html file named
post_tags.html inside another
special jekyll directory
/_includes/. Content of
Now, wherever I want to display the tags associated with a post, I just need to add the following code:
One word of caution, the
post_tags.html assumes that the post is actually available in a variable named
post. This assumtion may be true for the
home page. However, in the post detail page (rendered by
/_layouts/post.html) the variable named
page holds all the information for that post.
Here is how I modified my
/_layouts/post.html to overcome this problem:
That’s about all. This should work fine as long as you keep your
_data/tags.yml file updated whenever you add a new tag and put your tags
properly in your post front-matter. Like, this post that you are reading now has the front-matter:
Once we have a good understanding of the tags are generated, generating archive will seem very easy. First of all, I needed to create a folder named
index.html inside it. It contains:
There is nothing much going on. It appears the actual logic is inside
archive.html file. This file (i.e.
/_includes/archive.html) will actually
iterate through all the posts in the site categorize them in year and month they were created on. Based on that information, it will display
some html similar to:
- Month Name-1 (# posts in this month)
- Month Name-2 (# post in this month)
- Month Name-3 (# posts in this month)
- Month Name-4 (# post in this month)
Moreover, each month name will be a link to a page (
http://mysite.com/archive/<year>/<month>) where all posts created on the particular month will
be displayed as a list. I think it is quite simple requirement. Here is a brute-force implementation of the above requirement found in
It is pretty messy and straight-forward implementation. But, it works. You may try to come up with a better implementation. Feel free to let me know then. I will update my code.
With all these in place, I now need to create the pages for each month and year I have at least a post in. I will be creating a directory structure like:
- 4-digit year
- 2-digit month
- 2-digit month
inside archive directory. Similar to tag files, these
index.html will have almost nothing and rendering logic will be inside a layout file
/_layouts/archive.html. So, my layout file for archive contains:
Quite simple. However, the
index.html files within the
archive/<year>/<month> folders are even simpler. An example of such a file is:
It is evident that this
index.html file is placed in
/archive/2014/06/index.html location. It will handle the URL
http://mysite.com/archive/2014/06 and will list out all the post created in June 2014.
Now, all that is left is to create the year/month folders with the proper
index.html within them with a script as before.
Here is another quick and dirty script for that task:
Once again, you can run this NodeJS script (
createArchiveFiles() function) from your local machine to generate the archive directory structure with
index.html files, or you can be a pro and have Travis-CI do that for your automatically.
For comment integration with static blog generated using Jekyll (or, any blog in general), Disqus is pretty popular. However, I wanted to keep every under the same umbrella. As an experiment, I tried to use GitHub issues as the host for my blog comments. In that case, I can simply use GitHub API to load the comments and display in my blog easily. There are few problems I needed to solve first.
- Create GitHub issue for every blog post I have and whenever I write a new one
- Link that issue somehow with the blog post so that comments can be loaded for a specific post
- I don’t want to do it manually :(
So, after a careful inspection of the generated issues, it becomes clear that each issue created in a repository has a unique id (a number). I also
have something unique for every post, which is the
permalink. I just need to store the mapping between
permalink of a post and related GitHub
Issue ID somewhere. Again,
/_data folder to the rescue. I have created a file
/_data/commentrefs.yml which contains a simple map between
permalink and GitHub Issue ID. If any
permalink is not present in that file, that means it is a new post and I need to create a GitHub Issue
for this post. After that, I need to add the mapping in the
commentrefs.yml file for the new post. That pretty much takes care of the linking part.
Displaying comments are least of my problems. I have written a simple angular code
to fetch and render comments from GitHub issues using GitHub API. There is also a very basic css
to give the contents a “commety” look. Also, I have to make sure that angular is available to me by modifying the
Now, the final and most important part. I need to generate issues in GitHub for every post that I have if it isn’t generated already.
And yes, you guessed it correct. I ended up automating that part as well. I created another NodeJS script which takes care of this linking and updating
commentrefs.yml file if needed. The script is too big to be copied here. You can always read it from the GitHub repository.
It will need you GITHUB_TOKEN to authenticate. Please do not put your GITHUB_TOKEN in the code. Instead, pass it to the code as a parameter. That is what
I am doing using Travis-CI.
My goal was to have a structure which I can modify myself within GitHub only for tags, archive, and comments. Then, I went ahead and automated
the manual labor using Travis-CI. All the automation scripts needed for this blog is located in
/_scripts/ folder. The execution starts from
/_scripts/main.js file. These scripts were written for this blog only, so they may not work just by copying into your blog. You may need to
modify some content (hard coded URL and path) to match your environment.
I hope this (really) long post helps if you have a blog hosted in GitHub Pages. I am sure you can come up with other cool feature implementations too using similar approaches. Feel free add a comment about the cool feature you have implemented for a Jekyll blog hosted in GitHub Pages. Happy (static) blogging. :)