Having merrily sunk about a year now into my experiment with prolonging adolescence making a game, I’ve wanted to get back into blogging some of what I’ve learned. But I’ve thoroughly fallen out of love with wordpress - updates, permissions, themes, etc. So I decided to nuke it and switch to an SSG
(static site generator), which are apparently all the rage right now. Here, for your reference and mine, is what I did and how it went.
Step 1: Pick an SSG
Difficulty rating: painless - thanks to StaticGen, a site that lists loads of SSGs and their details. In my case I filtered by javascript and tried out the top 5-6 options, and eventually settled on hexo.
Step 2: Get all your data out of WordPress
Difficulty rating: painless.
- Posts, pages, comments:
Dashboard > Tools > Export
- Attachments: grab the contents of
wp-content/uploads
The built-in wordpress export gets you a big XML blob of blog data, and several of the blog-centric SSGs know how to import it directly. If yours doesn’t, install Hexo just long enough to use its migrate feature. This will get you a folder full of converted markdown files for all your pages/posts, suitable for further conversion.
Step 3: Fix everything that’s broken
Difficulty rating: tedious and painful. The details will depend on your before/after setups, but inevitably there will be a bunch of stuff to fix - changing hard URLs, image tags, code tags, and so forth.
My solution here was to write a simple node-js script that goes through a file applying regexes to each line. Then I started fixing my posts one by one, adding a regex to the conversion script for each problem that occurred more than once. This took a lot of finagling initally, but after a few hours the conversions had become largely automatic. The script wound up looking like this:
function work(line) { |
Step 4: Customize themes and whatnot
Difficulty rating: being a web developer. This part is just front end development. In my case it took quite a while, because it mostly meant (re)acquainting myself with stuff like EJS/jade and stylus, and putting hexo in a headlock until it agreed to a pipeline (minification, etc) that I could live with. But if your SSG has themes and you’re willing to use one as-is, you might be done in five minutes.
Step 5: Migrate comments to Disqus
Difficulty rating: painless. I was worried about this step but it was over before I started.
- Sign up for Disqus, create a message board
- Disqus > Import > Upload your wordpress XML
- Add Disqus’ universal include code to your theme (many blog-like themes have this built in)
Boom, worked perfectly, no pain whatsoever. If you have a massive blog with massive numbers of comments like Ray Camden, you might need to do things in batches.
Step 6: Spin up a static server
Enter the devops. I initially wanted to serve from a container, and spent several days playing with running nginx via Docker. This works great locally, but when I tried to deploy it on google cloud, ultimately there were too many fiddly bits, so I rolled a tiny boring nginx server. Assuming one already has google cloud’s CLI set up, this amounts to:
# provision the server |
Easy as that. An f1-micro server and 10MB of disk runs a bit less than $5/month. For a real site, apart from the CLI above, you’ll want to promote the instance’s IP from ephemeral
to static
, and later of course point your domain at it.
Step 7: DEPLOY
Google docs will tell you to copy files to your server with gcloud compute copy-files
, but don’t do that - it’s dog-slow and it overwrites every file, every time. Instead, use rsync
. If you’re using google compute, here’s my deploy script:
rsync -avz -e "ssh -i ~/.ssh/google_compute_engine -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes -o CheckHostIP=no -o StrictHostKeyChecking=no" \ |
Many Bothans died to bring us that script, please use it wisely.
Step 8: (Optional) Fix broken /?p=123
style links
Depending on your initial wordpress setup, your site may have incoming links of the form example.com/?p=123
where 123
is the post ID. To avoid breaking such links, I configured nginx to catch them and serve up permanent redirects to fixed URLs.
map $arg_p $wordpress_link_redirect { |
The first bit maps any incoming p
query parameter to a URL string. The second bit is invoked for root /
requests, and serves up a 301 permanent redirect if the p
parameter got mapped, allowing links like this to work normally.
And there you have it. It took me a few weeks, all told, but the large majority of that was regular front-end development (i.e. hammering on the templates and CSS in hexo’s default theme until I was happy with the output). The actual “conversion” could easily be knocked out in a weekend, or even a few hours if you’re already very familiar with your SSG of choice.