Migrating my blog from WordPress to Ghost

I've just completed migrating my blog, jussiroine.com, from WordPress to Ghost. This post aims to share the thinking, the approach, and lessons learned from this little exercise.

Migrating my blog from WordPress to Ghost
Photo by Gareth Davies / Unsplash

Background

I've hosted my blog on WordPress for 10 years. Before that, I used several different platforms. I didn't write much during the first few years, but I did write something like this blog article about my IKEA adjustable standing desk. I still have that desk, by the way.

Initially, I self-hosted WordPress on a Virtual Machine. That quickly grew too error-prone and time-consuming. Patching MySQL, WordPress, plugins, PHP, Apache or IIS, and other services was a chore. For several years now, I've used a local service provider for my WordPress. It's been great, and I wholeheartedly recommend Cloud City to anyone wanting to use WordPress.

With each month, when my content grew, WordPress became slower and slower. At times, editing content with Grammarly was insanely slow. I could type a complete sentence before the cursor started moving within the WordPress editor. Perhaps it was a problematic combination of a custom theme, customizations on the theme, a few plugins, Grammarly, and WordPress in general.

Tweaking the theme was also burdensome. I wanted to add something, only to find the theme auto-updated and broke everything later.

Finally, I wanted to eliminate HTML and CSS for my content. I've used Markdown for quite some time now for my notes with Obsidian, so I hoped I could benefit from that. Somehow.

Alternatives to WordPress

Many of my friends use static site generators to serve their content. You'd somehow produce content in a dynamic content management system and then produce static (HTML) files to serve out. I'm guilty of that, too, with WordPress: For a year or so, I generated static HTML content from my WordPress content. It took about 10-20 minutes to generate each day. I'm not sure how I had the patience for that back then.

I looked at all the available static site generators, such as Hugo, Jekyll, Next, Nuxt, Astro, and I forgot 10 others already. I spun up prototypes a dozen times. It mostly went like this:

  1. Open Windows Terminal on a localhost
  2. Get two or three esoteric command-line tools from GitHub
  3. Realize they don't work in Windows at all
  4. Find out there are other tools, with numerous dependencies
  5. Try to compile/fix the tools
  6. Produce a skeleton blog with the static site generator
  7. It looks like crap and is missing a lot of core features, such as responsive layouts or the ability to inject a simple plugin for comments.
  8. Try to learn the esoteric scripting model for said generator
  9. Give up and move on to the next one

I wanted to focus on CONTENT, not on code. I then also looked at hosted content services such as Medium and Substack. But I also want to OWN my content. Giving my content to a third party forbids me from seeing how my content is attracting readers, and exporting content elsewhere might become impossible. This is not to say platforms such as Medium are not great - they are - but not the best for me.

And then I had a closer look at Ghost

I'd heard of Ghost several times. Some of my friends use it extensively - check out Tobias Zimmergren's blog at zimmergren.net, for example. I enrolled in a trial setup some years ago, but it was too cumbersome. Any customizations seemed to require a tiresome exercise in downloading a cryptic script to localhost, modifying that, and uploading it back - while hoping it doesn't break everything.

But I gave it a few years to mature, and here we are. If you're unfamiliar with Ghost, it's a platform available at Ghost.org. You can either have them host your content for you, or you can self-host. I took a look at self-hosting it but quickly gave up. I've redefined some of my priorities in recent months, and I seem unable to take more on my plate right now.

The managed Ghost service is not accessible, though. See pricing here. The starter tier is $9/month with an annual subscription. It's probably enough for many, but I needed to go for the Creator tier, which is $25/month - or $300/year. That is a lot of money for mainly hosting static content on the Internet. I'm willing to invest in that, though, as I feel it makes me more productive. I guess I pay the same for a Spotify Family subscription and a few cups of cappuccino yearly.

I needed to go for the pricier tier mainly because of custom themes. I needed to inject a few minor additions to the theme, and you cannot do that with the cheapest $9 tier. It's fine.

Migrating content from WordPress to Ghost

Ghost has a plugin for WordPress that extracts all content (posts, tags, drafts) to a .json file, which you can then upload to Ghost. This carries over 90% of my content in 2 minutes. It won't, however, carry over images - and I have a lot of images in my blog posts from the past decade.

I downloaded all image files from WordPress to a localhost. That's about 25,000 files, or about 5 GB. I zipped those up and tried uploading to Ghost, but it just choked. I think I broke the Ghost admin panel for a few minutes because I got a Bad Gateway error. Sorry.

I then tried splitting the files into 100 MB packages. That's about 50 .zip files. No, thank you. Also, many of those files are duplicates as some of the plugins within WordPress insist on storing 10 different scaled versions of each image.

Once I had my content over, I quickly looked at the API. I have about 300 blog posts; the problem was that each post had embedded HTML. Thanks to WordPress, I couldn't just switch to Markdown-based formatting.

Some friends suggested I use innovative Regex clauses to strip formatting from each blog. I feared this would take several hours, and I'd still have to verify each post. In the end, I opted to do this manually. The problem is that once you have to do something, you don't really want to spend a day building automation for that.

To do this, I switched my WordPress-based blog to https://old.jussiroine.com and enabled the Ghost-based blog for public use at https://jussiroine.com. I now had access to my new service and the old service at the same time.

I went through each blog post and essentially ran this macro:

  1. Select all content on a Ghost article and delete it (to remove HTML formatting)
  2. Add a new line (to switch to Markdown mode)
  3. Copy all content from WordPress to Ghost
  4. Manually copy each image over

It takes about a minute per blog post, so about 5 hours in total. I still have about 100 blog posts to fix, but they are already visible - just missing some images here and there.

Ghost experience

I'm now writing this within the Ghost content editor. It works in lightspeed, and the experience is like a dream. Fixing grammar errors with Grammarly doesn't mess up existing formatting like in WordPress. Saving drafts is automatic and doesn't refresh the page at odd intervals.

I also don't have to memorize all Markdown syntax. I can double-click anywhere and get a small toolbar to aid me. Or I can write Markdown wherever I need. Like here.

Configuring the site is a breeze, as Ghost has far fewer configuration options to worry about. I opted for the Solo theme and just got to creating content. I could also carry over my comment system from Hyvor Talk with a simple modification to the theme template.

Analytics

For the longest time, I used Google Analytics. Eventually, I grew tired of it, as it's messy and over-engineered. I migrated to Cloudflare Analytics a few years ago, which is fine. It's not exceptional, but it's okay. The downside of Cloudflare's analysis is that it's very different if you compare it side-by-side with Google Analytics.

During my migration to Ghost, I also switched to Plausible. Again, not a free service - 9 €/month for 10K pageviews. But I'm willing to try it, as it was so frictionless to enable for Ghost - just a click of a button essentially.

My personal website is now cookie-free, and there are no trackers of any sort. I feel this is fair for my readers and gives me fewer headaches down the road. This way, I feel I'm not feeding Google all sorts of data for free so that 9 € or so per month is negligible in the big picture.

In closing

It's still a honeymoon with Ghost for me. There are many things I'm planning to create for the site, but for now, content is king, and it will take the center and front stage.

I hope you'll enjoy the facelift, and I hope my content turns out useful for many in the future.