# Migrating my blog from WordPress to Hashnode

A step-by-step guide for migrating a blog from WordPress to Hashnode.


## Why did I switch from WordPress to Hashnode?

Currently, my portfolio website and blog are on WordPress. It's been really great for search engine optimization, and the experience with [WP Engine](https://www.shareasale.com/r.cfm?B=943418&U=779380&M=41388&urllink=) has been almost flawless, but it's been a long time since I built it so everything I use to run it locally is broken: Vagrant, Scotchbox (LAMP stack), WP Distillery (Wordpress-flavoured LAMP), etc. It's no longer as quick as it used to be to make small changes.

I have been evaluating different blogging platforms. I considered Medium, but I am not a fan of the experience of landing on a Medium link and hitting a paywall, so I didn't want users to experience that if they find one of my posts. It also didn't have any ads injected, so that's great. 

I also thought about using a headless CMS and a static site generator like Nuxt as I've had a great experience with it, but that would've taken a lot of dev time to build. I think that's something I would do for the rest of my site once I have more time.

Hashnode has a variety of features that I appreciate:

- Markdown editor
- Canonical link support so I can link to my original post if I wanted to
- Automated backups to a Github repository
- Custom domain linking
- Nice code syntax highlighting, with the bonus of embedding external services for code snippets

What's great is that these are all free, too. There's also a helpful community on Discord to get some help if needed. 


## Walkthrough for migrating from WordPress to Hashnode

### Download post content

To begin the migration, you'll need to download your existing posts. By default these are in XML format. Since I don't really like working with XML, I used the plugin [WP Import Export Lite](https://wordpress.org/plugins/wp-import-export-lite/) to export my posts as JSON. 


![wp-import-export-lite.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1596515059753/j37zcB9uY.png)

The resulting output was an array of objects that had the following shape.

```json
{
  "ID": "463",
  "Title": "iTerm colour schemes",
  "Content": "Introducing 2 iTerm colour schemes [...]",
  "Excerpt": "iTerm colour schemes based off of my Visual Studio Code theme",
  "Date": "June 22, 2020",
  "Post Type": "post",
  "Permalink": "https:\/\/tinaciousdesign.com\/blog\/iterm-colour-schemes\/"
}
```

### Download images

Next, you'll need to download all your images. There's more than one way you can approach it:

1. Download all of the images uploaded to your WordPress install
2. Programmatically process a JSON or XML export of the Media Library, which has links to the media

The first option is by far the easiest, so I went with that.

Images are stored in the `./wp-content/uploads` directory by year and month.

```
wp-content/
└── uploads
    ├── 2019
    │   ├── 01
    │   ├── 02
    │   └── 03
    └── 2020
        ├── 01
        ├── 02
        └── 03
```

Your posts reference images like this:

```text
https://example.com/wp-content/uploads/2020/08/filename.png
```

You can use an SFTP tool like Cyberduck or FileZilla to download this folder.


### Upload images elsewhere

_**Update**: This section is out of date. The service Fast no longer offers a free plan and Hashnode has its own CDN so I have been manually updating them in an effort to save on server costs._

That "elsewhere" I chose is [Fast.io](https://fast.io) because it had a generous free plan that leverages a variety of storage options like Dropbox, Google Drive, OneDrive, etc. I can take advantage of one of those amazing storage services and link it to Fast.io. I chose Dropbox. After manually deleting some images that weren't used in the blog posts, I uploaded the entire contents of the downloaded `./wp-content/uploads` directory to Dropbox.


### Programmatically publish posts to Hashnode using their API

Hashnode has a [GraphQL API](https://api.hashnode.com/). It's somewhat limited in functionality but has most of the basic features. There's a [helpful blog post](https://engineering.hashnode.com/introducing-hashnode-graphql-api-public-beta-cjydzvp59001q2gs1b5zxaeaf) on how to use it.

Back-dating posts is not supported in the API so I needed to do this manually for each of my posts, which was tedious.

I've created a [repository of the scripts](https://github.com/tinacious/migrate-wordpress-blog-hashnode) I used to facilitate cleaning up and bulk uploading posts.


## Conclusion

Overall, I was happy with my migration to Hashnode. It didn't take very long. Hashnode has a lot of features I look forward to using and I was happy to invest the time in migrating.

Setting up my custom domain was a bit painful compared to other services I've set up domains with, e.g. Heroku, Netlify, Github Pages, Amazon S3. I use Cloudflare, and eventually what worked was contacting support on Discord, disabling Cloudflare's default proxying behaviour, and waiting until the SSL certificate was re-generated. Within a day it was working, so the trouble was only a minor setback.

The authoring experience is nice, typographically. There's also support for a lot of different types of embeds. Showing code is pretty without any effort on my part, and their embeds support the services I use most (Codepen, Codesandbox).

Overall, migrating to Hashnode is a relatively low investment, low risk migration.

If you like the sound of this and want to migrate your WordPress blog to Hashnode, you can use some handy [scripts I created](https://github.com/tinacious/migrate-wordpress-blog-hashnode).

%[https://github.com/tinacious/migrate-wordpress-blog-hashnode?v=1]
