After 7 years of serving my blog/website with WordPress, I thought it was time to try something else. One of my biggest gripes about WordPress (apart from having to hold my breath on each version update) is that writing posts through a web UI isn’t very handy: it’s slow, inconvenient for complicated posts (especially if you’re used to your favorite editor), you can’t write while offline, and the versioning is limited (compared to real versioning systems). So, I decided to give static blog generators a try, and ended up converting my blog to Nanoc (after a brief stopover at Jekyll). Result: I can now write my posts in VIM, use Markdown syntax for writing, preview my posts live using tools such as Marked and MarkdownPad, preview the site using Nanoc’s built-in HTTP server, easily customize my site with some Ruby code, and keep everything versioned with Git. And of course move it on Amazon S3 in case my blog really hits off and starts getting million hits a minute (which should be any day now).
In case you’re interested in the details of how I converted from WordPress to Nanoc (including code), read on.
Before settling on Nanoc, I first gave Jekyll a try. However, Jekyll always had a very ad-hoc feel to it, with filled with decisions that didn’t always work for me, and lots of untransparent magic going on behind the screen, which also didn’t always work for me. Nanoc is a lot cleaner, powerful, more extensible, and easier to understand what’s going on. Luckily, the post format of Jekyll is compatible with Nanoc, so the steps for migrating directly from WordPress to Nanoc should be the same.
Here’s roughly what I did:
- First of all, I got the posts out of the WordPress database using Vito Botta’s WordPress-to-Jekyll script (with some minor changes). This script pulls out the posts as HTML, with metadata prepended as YAML front matter (which is what both Jekyll and Nanoc use). (See an Example Post)
- Although WordPress posts use HTML for markup, the markup omits
<p>paragraph tags (as they are added automatically for empty lines), which means rendering them as HTML doesn’t look as it’s supposed to. Fortunately, if you treat the HTML files as Markdown (and use RDiscount as your posts filter), the result ends up as expected: the HTML markup is preserved, but paragraphs have been added in the right places.
- For the layout, I just reused the Twenty Ten theme I was using before. WordPress does
a good job at separating presentation and structure, so I just mimicked the
<div>structure in my layout files, copied the CSS files unaltered.
- One thing you can’t do with a static blog is serve comments, so I moved the comments to Disqus. Before getting rid of WordPress, I installed the Disqus Plugin to do a one-time import of all comments. Using the WordPress ID and URL (pulled by the script mentioned earlier, and put in the YAML front matter of the converted posts), you can reconstruct the right ID for keeping your comments intact on the new site. (See the Disqus Template)
- In order for the front page to show excerpts instead of full posts, I use a filter
(and a helper) to strip everything
up to the
<!-- more -->tag, put this into a separate nanoc representation, which in turn is used when populating the paginated blog pages.
- For the tags and categories, I use another helper to generate the list of categories and tags for each post, and to generate a page for each category/tag containing all the posts for that tag (and their RSS feeds)
That’s it for the basic functionality. Then, there’s some sugar coating and extra stuff, such as:
- A tag cloud in the sidebar, using a helper.
- Support for Twitter cards. I added a rule to make a ‘filtered_contents’ snapshot after applying the Markdown filter, and use this snapshot in the ‘head’ section of the layout, as you can see in this template.
- Embedded my Git repositories using CGit, by splitting up a rendered dummy page (again using a simple filter), and using these resulting pages as header/footer for CGit. It doesn’t look perfect yet though (diffs are too wide for the layout for example).
- Since the CGit integration isn’t perfect yet, I added a filter to rewrite all internal Git urls to point to my GitHub repositories. If I decide to switch back to my own (or another) public Git interface, I won’t need to touch my posts.
- Embedding image galleries using Galleriffic (although I dropped my galleries recently)
- An update_software task for auto-generating all
my Software project pages from the
READMEfiles in the project Git repositories.
For the nitty gritty details, you can have a look at the code (and some example content) in my Git repository.