Switching to Hugo
I’m finally free of WordPress!
Don’t get me wrong. WordPress is an incredibly powerful platform for blogging. It was reasonably easy to set up, use, and update, and I only used a fraction of its capabilities for this blog. It served me well for the past decade.
My issues with WordPress boiled down to:
- My blog was literally the only thing left on my server using PHP and MySQL. The rest of my site uses a .NET Core web service and PostgreSQL database for dynamic content.
- I got really tired of server logs filling with script-kiddie WP attacks and having to update WordPress constantly to plug new holes.
- While there are a bazillion themes, I wasn’t really happy with the ones I found, both in terms of DOM complexity and aesthetics.
I originally tried Jekyll, but ran into an issue with the WordPress export plugin. I submitted a patch recently, but between the staleness of that bug and having to fight to get Ruby installed correctly (I don’t use Ruby), I started looking for alternatives.
Enter Hugo. While it is newer, the docs were clear, and the community’s WordPress importer worked reasonably well (code blocks were not imported well, and I found an issue because I didn’t have a wp-content/uploads
folder). The Bootstrap 4 theme looks nice, and Hugo’s performance for generating the site is stellar.
I was using the default URL scheme in WordPress, e.g., “blog.tallent.us/?p=123”. Static files can’t include the query string “?” marker, so I had to come up with rewrite rules to redirect my old WordPress posts to the new canonical posts.
Fortunately, the WordPress export plugin generated my post files with the original “p=X” query in the url
setting of the front matter. Since the url
basically overrides what would normally be the URL for the post, this actually broke Hugo’s ability to create links to the new posts, but it preserved the information I needed to redirect.
I used TextWrangler’s multi-file replace to change the url: /?p=
to originalurl: /?p=
in all of my posts. Since originalurl
is not a recognized setting, Hugo ignores it. I then created a little awk script (“forwards.awk”) to generate my .htaccess
file:
#!/usr/bin/awk -f
BEGIN {
print "RewriteEngine on"
}
{
if($1=="originalurl:") {
sub("content/post/", "/posts/", FILENAME)
sub(/\.md/, "/", FILENAME);
sub("/\\?p=", "", $2)
print "RewriteCond %{QUERY_STRING} ^p=" $2 "$"
print "RewriteRule \"\" \"" FILENAME "\?\" [R=301]\n"
}
}
END {
#forward RSS
print "RewriteCond %{QUERY_STRING} ^feed=rss2$"
print "RewriteRule \"\" \"index.xml?\""
}
The script starts by turning on Apache’s rewrite engine. Next, for each file I pass to it, it looks for the “originalurl” setting and generates a rewrite condition and rule to forward the old WordPress URL to the new canonical URL. (RewriteRule
doesn’t match query strings, so you have to use RewriteCondition
to match the query string and then RewriteRule
to rewrite the root URL.) The script finalizes by creating a rule to rewrite the old RSS feed (“?feed=rss2”) to the new auto-generated feed file (“index.xml”).
To tie it all together, I created a little script in my blog source folder called “publish.sh”:
#!/bin/bash
rm -rf public/
hugo
./forwards.awk content/post/*.md > public/.htaccess
rsync -a --delete --info=progress2 public/. /path-to-web-server-publish-folder/
If you have any problems using the new blog or getting the RSS feed, please let me know! I’m now hoping to be able to recover and re-publish some of my blogs going back a few years before I switched to WordPress.
I just enabled comments via Disqus, but please feel free to share via Twitter and mention me (@richardtallent) if you prefer dropping me a comment that way.