Migrating my blog from Wordpress to Ghost

nodejs Aug 6, 2016

One day it hit me... it was time for my blog's journey from Tumblr to Wordpress to continue to newer adventures... and the destination was ghost!


The Wordpress Blog

One of the initial attractions of Wordpress was it's WYSIWYG HTML editor. The ability to format a blog post using a UI that is similar to writing offline content in a word processing application seemed a great capability. Plus with a wide range of plugins and themes available, Wordpress is indeed a very versatile content management platform!

My Wordpress Blog

For my blog, I used a nice minimal theme Waipoua by the talented web designer duo - Ellen und Manuel of Elmastudio.

I used the following plugins:

  1. Advanced iFrame : This plugin includes any webpage as shortcode in an advanced iframe or embeds the content directly. I used this for inserting route maps from gpsies.com
  2. Akismet : Used by millions, Akismet is quite possibly the best way in the world to protect your blog from spam.
  3. All In One SEO Pack : Out-of-the-box SEO for your WordPress blog. Features like XML Sitemaps, SEO for custom post types, SEO for blogs or business sites, SEO for ecommerce sites, and much more. This adds the crucial SEO meta data that optimizes blog posts for search engines.
  4. Collapsing Categories : creates an expandable list of categories and subcategories. It can also expand to show posts. I used this for creating the drop down of categories in the right sidebar.
  5. Contact Form 7 : Just another contact form plugin. Simple but flexible. I used this for the contact form.
  6. Disqus Comment System : The Disqus comment system replaces your WordPress comment system with your comments hosted and powered by Disqus.
  7. Google Analytics by MonsterInsights : This plugin makes it simple to add Google Analytics to your WordPress site, adding lots of features, e.g. error page, search result and automatic outgoing links and download tracking.
  8. Google XML Sitemaps : This plugin will generate a special XML sitemap which will help search engines like Google, Yahoo, Bing and Ask.com to better index your blog.
  9. MapPress Easy Google Maps : MapPress makes it easy to insert Google Maps in WordPress posts and pages. I used this for inserting a map to the location of my post.
  10. Pinterest Image Pinner From Collective Bias : Adds Pin this to all post images so that visitors can post the image to Pinterest.
  11. Simple Share Buttons Adder : A simple plugin that enables you to add share buttons to all of your posts and/or pages.
  12. TinyMCE Advanced : Enables advanced features and plugins in TinyMCE, the visual editor in WordPress.
  13. WP-PageNavi : Adds a more advanced paging navigation to your WordPress blog.
  14. Yuzo - Related Posts : Displays a list of related posts to the current post.

This is a reduced set of plugins that I had cleaned up after trying several others.

Issues I had with Wordpress

  • Performance :
  • The application is written in PHP, and has grown from a small blogging platform into a full scale content management system. It is an overkill for a blog!
  • The multitudes of plugins required makes the site slow and heavy
  • Writing Content :
  • Creating and editing content on the blog requires too much effort. Using the WYSIWYG editor is ok when you have a lot of time to write the post, but it is quite cumbersome when you want to write quick posts. Plus, the formatting in a blog post is quite minimal - hence the editor is also an overkill.
  • Adding software code into the post with syntax highlighting requires a special plugin. Though I did not write too many of such posts, as a developer I feel this is a crucial need for me.
  • Media Management :
  • The Wordpress media manager is great to insert and manage images that you upload into Wordpress. But for images inserted as links, it does not provide for features such as galleries and slideshows - they require special plugins. I keep all my pictures on Google Photos. Hence the advanced media management features are an overkill for my blog.
  • Social Media and SEO :
  • Integration with social media and search engine optimization requires plugins
  • Customization :
  • Customizing the theme to add new features requires a lot of PHP development work. As a software developer, this becomes a pain when PHP is not a language of choice.

Why Ghost?

ghost is a platform dedicated to one thing: Publishing. It's beautifully designed, completely customizable and completely Open Source. Ghost allows you to write and publish your own blog, giving you the tools to make it easy and even fun to do.

ghost Logo

What I like about it is that ghost is a quintessential blogging platform - it does only what it needs to and nothing more!

  • Performance :
  • Ghost is written in NodeJS and is extremely small, and serves pages fast! (Read here about the asynchronous I/O model of NodeJS)
  • Writing Content:
  • Ghost uses Markdown for writing content. Markdown does not support advanced formatting like HTML does, but it has a simple syntax for most commonly required features such as text formatting, links, images, lists etc. Plus you can also insert HTML code if you like.
  • Code blocks are also supported by Markdown with a simple syntax

function myFunction(parameter) {
  var myvar = 'some value';
  for (var i=0; i<10; i++) {
    parameter += i * 10;
  return myvar + parameter;
  • Media Management :
  • ghost recommends that all images are stored on image hosting providers like Cloudinary, Google Photos or Flickr. It does not have any fancy media management capabilities, and these are not really required for a blog.
  • Social Media and SEO:
  • ghost has built-in support for social media integration and SEO meta tags. Hence no plugins or customization required.
  • Customization :
  • Ghost is written as a NodeJS / ExpressJS application and uses Handlebars templates. All of which are now mainstream technologies for most developers - Note: No guarantees how long this will last :)

Setting up the ghost blog

ghost provides a hosted service for people who want to get a blog going without any customization. But I knew I would be doing some customization and so chose to host my own ghost blog.

The first task was to choose a cloud platform to host it on. I chose Digital Ocean for its simple and affordable pricing models, and their developer-friendly features. Plus, ghost itself is hosted on Digital Ocean. No brainer!

I created a new Droplet (Digital Ocean's terminology for a cloud server instance), using their one-click-app for Ghost.

Digital Ocean Droplets

I had an empty blog in minutes!

Migrating content from Wordpress to ghost

There are several blog posts on migrating content from Wordpress to Ghost. The most systematic information I found was created by Jeff Owens. He has a series of posts that describe the various steps required to systematically migrate Wordpress content to Ghost.

I followed these steps that he has outlined:

  1. Installed the Cloudinary plugin in Wordpress and migrated all images to Cloudinary (how to)

  2. Installed the Ghost plugin in Wordpress and exported all Wordpress content into ghost JSON format (how to)

  3. Integrated Disqus comments into the default ghost theme (how to)

Now the blog was all ready with content.

Fixing Conversion Issues

But when I started looking at various posts, I found several issues:

  1. The ghost plugin retains several HTML tags from Wordpress that has hard coded styles. This makes some of the content skewed in the ghost blog.

  2. Conversion of Wordpress galleries is a problem, because ghost (markdown) does not have any facility for galleries.

  3. For my Wordpress blog was hosted on a multi-user setup, some of the blog links were to the sub-domain of the parent Wordpress.

  4. Ghost only has tags, while Wordpress has categories as well as tags. During the export, the ghost plugin only exports tags and does not export categories.

  5. The Ghost plugin also does not carry the meta data created by the SEO plugins - not even the native Wordpress extract attribute. Hence all posts lack the hand coded description meta data that is critical for SEO. Ghost by default takes the first few characters of the post content.

I shuddered at the thought of manually correcting all these issues. Being a lazy developer who does not like to do repetitive work, I wrote a program to automate these fixes.

Here's what I did:

  • Wordpress has a native facility to export all its content into XML. I used this to create an XML file of all my old blog content
  • The ghost plugin had created a JSON file that contained all the content in ghost (markdown) format
  • I used another Wordpress plugin Export Categories to export the Wordpress categories into a separate XML file
  • I wrote a NodeJS application that would read all these files, and fix all the issues in the ghost JSON
  • The application compares each Wordpress post with the corresponding ghost post, and adds the description metadata, removes unnecessary HTML tags and corrected the subdomain links.
  • Further, the application adds all Wordpress categories from the categories XML into the ghost JSON

See / download the code from here

Next Steps

The next big step is to address the last missing important feature in ghost - a blog search!


Ashutosh Bijoor

Adventurer, mathematician, software architect, cyclist, musician, aspiring wood worker