/ BLOG, THEME, GHOST, BASH, SCRIPT

Changing blog theme, the wrong way

I was working on all the blog updates and posts for the new year when I was thinking about a possible restyle. Read this all the way through, because I promise there is some code, too.

Let’s start saying that finding a new theme wouldn’t have been an easy task. At the moment I was using Minimal Mistakes, which is great since it offers support for Disqus, Google Analytics and keeps the blogger in the center of the scene with their bio and social network links.

What I didn’t like, though, was that it was too… Giant. What I mean is mainly “big fonts”. In addition to this, I did my own tweaks to the theme and keeping it updated was a huge pain, since I had to check each file and correct the changes.

In this post, I’ll cover the entire story behind the new theme, and I’ll share with you my setup to make it work and self-update.

Searching for a theme

Before continuing let me say that to serve my blog I’m using Jekyll on GitHub Pages.

To find the right theme I dove into those websites like jekyllthemes.org, which are nothing but a collection of Jekyll themes. However, nothing was perfectly suiting my style or offered everything I needed. I started feeling defeated almost immediately, but at some point I came across Ghost and I instantly fell in love with its default theme, Casper. I felt the urgent need to have it.

Ghost is a sort of open source CMS for blogs. It is used by DuckDuckGo, Tinder, Mozilla and many other companies which prove nothing but how good that is.

Being open source means that it’s free, but being a CMS also means that it is a back-end service, which GitHub Pages, that hosts static websites, does not support.

What I tried at first was hosting Ghost locally, scraping the static website and uploading that on GitHub. I spent hours doing the porting and, you won’t believe that, it turned out a mess. Scraping is just a terrible idea, but, in my defense, I must say I was just following the instructions from many different tutorials.

I was going to keep Minimal Mistakes, trying not to think about the beauty of Casper. But then… a thought… how is that possible that no one did a Casper theme for Jekyll?!? And in fact… someone did.

Problem solving

Download the theme: done. Configure the theme: done. Copy all the posts: done. Publish on GitHub: error.

Nothing can be perfect, right? So.. what is the problem now? Actually, the README file of Jasper2 has a very clear Deployment section which says that for security reasons GitHub does not allow plugins in the _plugins/ folder and because of that you need another way to deploy the blog.

The simple version is that the website needs to be compiled by Jekyll and then the generated static folder needs to be uploaded to GitHub. The README talks about different ways to achieve that, but I used my own.

First of all, I created a new private repository, named blog-backend which contains the Jekyll project. In the .gitignore file I put the _site folder, which contains the generated website. Instead, I cloned the blog repo into this _site folder, allowing me to directly push the built blog.

My very first idea was to do all the edits, run jekyll build and push the updated blog. But then I realized there was a huge problem in doing that: scheduling. The way Jekyll works (if told so) is that “future” posts are not compiled and displayed. Every time the website is built every post is checked and, if set in the past (or present), generated.

With my previous theme, the setup was quite simple: I had set a cronjob on my Raspberry Pi (which runs 24/7) that used the GitHub API to request a fresh build every day at 1 pm. Everything was automatic. But now this isn’t possible because GitHub can’t build the blog for me.

This is my workaround:

  • configure all the ssh deploy keys needed (id_rsa linked to blog-backend and github linked to lorenzoleonardini.github.io)
  • clone my blog-backend repo in the /home/pi/blog folder and, inside that, clone the lorenzoleonardini.github.io into the _site folder
  • install Jekyll, bundler and all the Gems required to run bundler exec jekyll build (sounds easier than it was)
  • set up a cronjob to execute a bash script that:
    • pulls all the updates for the back-end
    • builds the blog
    • commits the changes to the front-end
    • pushes the updated blog

And this is the bash script (let me add that I cannot really code in bash and therefore this could definitely be improved. But it works just fine):

#!/bin/bash
echo "Pulling updates..."
(eval $(ssh-agent -s); ssh-agent $(cd /home/pi/blog; ssh-add /home/pi/.ssh/id_rsa; git pull))
echo "Building blog..."
(cd /home/pi/blog; bundler exec /usr/local/bin/jekyll build)
echo "Pushing..."
DATE=`date '+%Y-%m-%d %H:%M'`
(eval $(ssh-agent -s); ssh-agent $(cd /home/pi/blog/_site; ssh-add /home/pi/.ssh/github; git add -A; git commit -m "$DATE update (pi)"; git push))

Is this perfect?

Absolutely not. The Jasper2 theme generates xml files containing the date and time of build, that means that even if there is no real update there are changes to be commited and my repo is now spammed with commits. Just imagine one commit per day (just from the Pi). This is crap.

I could (and should) fix this by checking if there are actual post updates, but I’m lazy and for the moment this is functioning.

EDIT

I’ve finally fixed the script to only commit changes if there are actually changes. To be more clear: jekyll updates every feeds.xml file with the date and time of the last blog build. That is useless if there are no changes in the posts, but until now that was pushed every day since git sees that as an update.

The new script (apart from small stylish modifications) checks the output of the git status command to check if there is some non-feed-file involved in the changes. If so it commits. If you know bash it is probably easier to just look at the code.

#!/bin/bash

bold=$(tput bold)$(tput setaf 141)
normal=$(tput sgr0)

echo "${bold}Pulling updates...${normal}"
(eval $(ssh-agent -s); ssh-agent $(cd /home/pi/blog; ssh-add /home/pi/.ssh/id_rsa; git pull))
echo ""; echo "${bold}Building blog...${normal}"
(cd /home/pi/blog; /usr/local/bin/bundle exec /usr/local/bin/jekyll build)

echo ""; echo "${bold}Checking if there are changes to be pushed...${normal}"
cd /home/pi/blog/_site;
git status --porcelain | while read -r line; do
	if [[ "$line" != *feed.xml ]]
	then
		echo "${bold}Pushing...${normal}"
		DATE=`date '+%Y-%m-%d %H:%M'`
		(eval $(ssh-agent -s); ssh-agent $(cd /home/pi/blog/_site; ssh-add /home/pi/.ssh/github; git add -A; git commit -m "$DATE update (pi)"; git push))
		exit
	fi
done
echo "${bold}No change to be pushed${normal}"

If you have questions or suggestions remember that down below there is a “comment” area. (Oh yeah you can share, too).