How I migrated my blog from Wordpress to Hugo

When I decided to migrate my old Wordpress blog to a new, Hugo-based website, I thought I’d write down my notes along the way and make a detailed migration guide. Unfortunately, best laid plans go awry and by the time I was done, I only had a few notes and didn’t remember all the context.

Nevertheless, I’m sharing what notes I do have, so that even if it’s not a “detailed” guide, I can at least give some pointers to someone else attempting the same thing.

N.B. I had long ago turned off new comments to my posts and have no plans to provide them on the new site, so I didn’t care about losing legacy comments from my posts during the migration. YMMV.

  1. I chose to use the wordpress-to-jekyll exporter because it seemed a little more stable/robust; I found its command line mode easier since I didn’t have to divine the path to the generated tarball.
  2. I ran Hugo’s jekyll import command to generate a Hugo site from the Jekyll one.
  3. I put new site under version control before I started hacking at it.
  4. I picked a theme from the Hugo Themes site and started customizing it. This process continued in parallel throughout other work. I found, in particular, getting old-style and new-style syntax highlighting to look similar was a long exercise in CSS hackery.
  5. I customized the config.yml. In particular, I set up a permalink style that I knew I could later remap from the old site to the new.
  6. I renamed ‘post’ to ‘blog’, and added a ‘talks’ permalink. On the old site, I had talks on a single Wordpress page. On the new site, I want each talk to have its own page in a talks section.
  7. I updated the ‘url’ field in front matter to keep the final URL part so I can redirect it cleanly later; I won’t use that field for new posts, though.
  8. I wrote a program to clean up the rest of front matter, such as deleting fields I didn’t need/want like ‘guid’, ‘openid_comments’, etc. I also merged categories into tags and added tags based on file name substring matches.
  9. I wrote a program to replace all references to old site URLs with new site URLs; I didn’t replace them with Hugo reference shortcodes because it seemed like too much work at the time.
  10. I added an .htaccess that enabled compression and caching.
  11. I had my ISP turn on Let’s Encrypt TLS support for the site and amended the .htaccess file to redirect all ‘http’ scheme URLs to ‘https’. I wrote another program to fix up all URLs accordingly (image src fields in particular needed changing).
  12. For all the old talks I had listed, I created a new page. Since I was doing all this work anyway, I tracked down video links and uploaded slides to SlideShare and wrote a custom template to render them if links were in the front-matter. This was a lot of work and is probably the main reason I fell off the wagon taking notes on my process. I’m pretty happy with how the new section turned out, though!
  13. When browsing old posts, I realized that some of the converted Markdown was corrupt. What should have been **Some pseudo-header** on a line by itself was converted with the trailing ** on a separate line. The same was true for _foo bar_ lines. I edited by hand all files with that pattern.
  14. For the old site, I wrote an .htaccess file to redirect old permalinks to the new ones on the new site and return 410 (Gone) for all other pages.

There are probably other small tweaks I did that I didn’t write down. Hacking at the theme and design has been an ongoing effort, but I think it’s pretty close to what I want for launching version 1 of the new site.

If you need to convert your Wordpress site to Hugo, I hope you find these notes useful. Good luck!