After several months of effort (not daily – I took my sweet time) I have converted this blog from WordPress to Hugo. That conversion has brought a modernized look and feel, and a lot of updates of old content. I moved away from plugins and short codes that WordPress used to theme modifications to support the short codes of Hugo. It’s forced me to learn a new template engine, platform, and web site paradigm. It’s been a bit of a journey to get here, so I figured I’d explain why I bothered and the work that went into the change.

Why the Switch

When I started this blog in 2016 I selected WordPress because it was easy to get setup and run on my own. I was working full-time on Drupal, and while Drupal is a great platform it’s not ideal for running a simple personal blog – but that is Wordpress’s core purpose. Since then I realized that running WordPress on my own server has required attention I don’t want to give it, and WordPress itself has required care and feeding to keep secure. What’s more updates to WordPress themes to modernize looks always required a lot of content revisions.

As a full-time web developer 8 years ago that attention and time was easy. I worked with servers all the time. I was used to the joys and pains of Linux server updates, PHP versions, and a bunch of other things I don’t regularly do anymore.

Yes, all of those things could have been addressed without leaving WordPress.

Ever since I started the blog I’ve pondered switching to a site generator instead of a PHP-driven CMS. That was partially because I was working with a PHP-driven CMS all day, and I knew I was going to need to better understand the competition the generators posed. More recently I craved the simplicity and security that provide by removing the PHP layer from consideration.

When the drama in the WordPress community broke out last fall, and it looked like more attention was going to be needed (that hasn’t really come to pass) I started to look for alternatives. And quickly that brought me back to the idea of using a site generator.

Why Hugo

There are a lot of site generators to pick from. I played with Jekyll, Gatsby, Hexo, and even started writing my own before finally settling on Hugo.

Hugo presented several benefits, and a few draw backs, that impacted my selection.

Hugo has an overall simple design: you select and modify your theme, then create the content and provide the assets any way you like. Hugo then generates your final web site by running that content through your theme. There is no plugin or module system. There is no complex philosophy about content vs other kinds of data. There is just a theme and content.

Hugo is written in Go where most of the others I looked at are written in Node.Js. That helps Hugo be fast, combine that with the simple design and it’s really fast. When I ran head-to-head tests it wasn’t even close enough to be worth measuring. This site currently has more than 4,000 images – all of which need preprocessing for a full rebuild – which makes that performance nice to have. And once I got used to how the theme works, the simple nature of how to handles content is elegant.

Hugo has guidance for how to do all the things, but does not do all the things. Instead you have to create templates and processes to handle what you need. For lots of people that would be a draw back (kinda is for me honestly), but it forced me to learn more about how it works than it would have otherwise.

Finally, Hugo is designed to be developer friendly – it’s not really non-developer friendly. For me, that’s great. And to be fair, if a developer sets up the site, and teaches a non-developer how to use it, it will work just fine. But it makes a lot of assumptions about using Git and CLI tools which are not common outside the world of developers. It also required me to tweak and adjust the theme to get exactly what I wanted from the site.

I don’t know if I’ll keep hugo forever, probably not – 9 years on one platform was a long time in web terms. But now that all the base content has been converted to Markdown I am hopeful any future conversion will be easier than this one was.

How Did Convert Content

This part was entirely too hard for a site with several hundred pages and several thousand images. There are several migration tools available, and they all failed me to some extent or another. I completed the main migration with wp2hugo, and it did an okay job but left me with a bunch of clean up to do.

In retrospect I should have expected this to be hard no matter where I was going. I have done enough site and data migrations in my life to understand why this is hard. Any given WordPress site can have lots of plugins. The target tool will not have all matching features. Worse yet, SpinningCode.org has been around long enough I changed plugins there once or twice so there were artifacts from previous plugins kicking around. That’s extremely common for projects like this, and always makes them messy.

I used wp2hugo to extract all the content from the standard WordPress site export xml file. I then crafted a bunch of scripts to do other tweaks and conversion. I also had to update the behavior of my theme in places to help make sure it had the features I wanted and was behaving the way I wanted. Again, no conversion tool was going to deal with that for me (at least not given the current state of technology).

At first I wrote those scripts by hand, but over time I started to use Copilot to help me complete tasks faster (I had mixed results here). In all I have 10 scripts I created to fix posts. Most of that had to do with changing how I handled images. A few were created to update other embeds like Gist and SlideShare.

Pain Points

I had three major pain points when setting up Hugo the way I want:

  1. Picking a theme
  2. Images
  3. Content clean up

All three were choose your own adventure games.

My Theme: A Knock-Off PaperMod

I based my theme on PaperMod. Hugo has a somewhat complicated set of assumptions about how you setup your theme. My biggest pet-peeve here is that it assumes you use submodules in Git, which I passionately dislike – mostly because I’ve used them before.

So instead of handling things that way I made the choice to just clone the PaperMod theme and start my own fork in my site’s repo. That means I’m cut off from improvements they make up stream, but it also made it easier for me to layer my changes – and I made a lot of changes.

Hugo Images

Hugo has powerful image handling available, but the theme I picked didn’t handle images carefully (at least not when I forked). The assumption of that theme is that the content creator is doing most of the image prep ahead of time, and also that we don’t need to serve up responsive image sets on the fly.

Since I have several photo galleries, and I care about how images look and are optimized, I hunted around until I found someone with a similar obsession who was running ahead of me. And then I modified, researched, edited, and tweaked my way to a set of templates I kinda like. As of this writing I have room for improvement in my theme, but the current behavior is much better than where I started.

I also had to convert a bunch of different image gallery systems I’d had in WordPress to a consistent new system. Most of my scripting went into those efforts. I also had to tweak the assumptions in the lightbox solution for Hugo. Cover images still aren’t quite behaving as I’d like. Some of my responsive image sets are missing sizes. There isn’t a simple mechanism to crop to fixed aspect ratios. I have no easy way to browse existing images because of how WordPress organized them (and I haven’t changed that yet).

Basically, migrating a site with 4000+ actively served images was a mess. But they work for now, and I will probably poke at slowly improving them over time.

Content Clean Up

Getting all the pages working effectively has been a labor of love.

Once I realized that part of the problem was all the various old plugins and content helpers I’d used in WordPress, I knew any other platform was going to have them same problem. So I marched forward using a blend of scripting, hand editing, and AI edits. The rule of thumb I used was: if I knew several posts had the same pattern, I created a script in partnership with the AI, if just one post needed updating I asked Copilot to make the edits directly.

One of the upsides of Markdown-based content, instead of a database, is that I could use text editing tools to manipulate the outcomes directly. There were a lot of quick-and-dirty one off solutions. And eventually I just walked through every single post looking for errors, missing content, broken images, and other mistakes. Some of those turned out to be broken in the old site too.

Lost Features

I said above that features never fully align, and moving to a static site generator meant that dynamic data driven features weren’t an easy option. The biggest feature on this site worth recognizing was loosing the ability to accept comments.

Without PHP and a database, there isn’t a good way to securely take comments. Honestly, with one or two exceptions I don’t get comments on posts here anyway. Most people who want to discuss the content do so on LinkedIn, Slack, or some other channel. So in my mind, it’s not a big lose. If you have something you want me to know, ping me in someplace like LinkedIn.

Was it Worth It?

I hope so, I put in a bunch of time to make this happen.

Honestly, I’m not too worried about that question. I have a working site. It lets me continue to practice my writing and grow my technical skills. It’s not a matter of changing my financial fortunes, it’s about learning, growing, and having more time to worry about the writing and spending less time worried about the state of my server.