Skip to main content

Command Palette

Search for a command to run...

Migrating my blog from WordPress to Hashnode

Published
7 min read
Migrating my blog from WordPress to Hashnode
T

Hi, my name is Tina! I am a Full Stack Software Developer and Tech Lead from Canada. 🙋🏻‍♀️

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 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 to export my posts as JSON.

wp-import-export-lite.png

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

{
  "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:

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 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. It's somewhat limited in functionality but has most of the basic features. There's a helpful blog post 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 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.

S

So far, people are very quickly migrating their blogs from WordPress to Hashnode. I am just wondering hashnode will allow some kind of monetization.

S

Hi 👋 welcome to Hashnode!

We are going to revamp our APIs and document them properly this week.

I think it took some time to issue the certs because there were too many failed validations for your domain since Cloudflare was not bypassed after adding DNS records. We are making some changes to our platform which will help us catch these mistakes early on and prompt our users to correct the config.

5
T

Thanks! I’m glad it’s all figured out now. Thanks for featuring the article. ❤️

One more thing I noticed because I can’t use Cloudflare proxying is that if I link to the SSL version, the social media image doesn’t show up. I need to link to the non-SSL version for that to show. Do you know if there’s a way to address that or should I continue to link to the non-SSL version?

S

Tina Holly I am afraid I don’t follow. Could you please elaborate the issue?

T

Sandeep Panda

Yes, sure!

This is what it's like when I share the link with https:// (using SSL):

And when I share with http:// (not using SSL):

Note that the image doesn't show on social media unless I share the insecure link. Do you have any suggestions for this?

What I've seen other services do, like Heroku, Netlify, and Github Pages, is allow you to use the service without SSL. This allows me to use Cloudflare to its full potential, including its SSL certificates.

Thanks!

S

Tina Holly That's weird -- because for me the social image appears correctly with HTTPS.

Can you retry and see?

Unfortunately, we are not able to serve blogs without SSL. There are a couple of strong reasons for this:

  • Serving a website without SSL is insecure and is prone to man-in-the-middle attack. If we don't serve a blog over HTTPS, we are compromising on security of our users. Read more about it here: https://web.dev/why-https-matters/

  • HTTPS is a must in order to use many new browser features (e.g. PWAs)

  • Lastly, some domains such as those having .dev extension work only over HTTPS.

Let me know if the problem persists. I'll dig deeper and find a solution.

1
T

Sandeep Panda thanks for checking. That's bizarre. I'll see if it clears up after some time. Thanks for looking into it.

The reasoning re: SSL makes perfect sense. I always use it but usually via Cloudflare. It makes sense to protect users who don't use a CDN like Cloudflare.

Thanks! Really excited about this product!

2
S

Hey Tina Just checking - is the problem resolved? If not, happy to dig deeper. :)

T

Sandeep Panda Thanks for checking in. It looks like if I copy/paste it multiple times, it works subsequent times. Perhaps it's a redirection or timeout issue. I've only tested on Facebook. It's sufficient for now, I'll just keep it in mind to try multiple times if it doesn't show the first time. Thanks for verifying.

E

Welcome to Hashnode. I can't wait to read your articles.

1
T

Thank you Edidiong Asikpo! ❤️

1
V
Vamsi Rao5y ago

This is really helpful for the community. Thanks for sharing!

1
T

Thanks Vamsi Rao! I was looking for such an article when I started and didn’t find one so I thought I’d make one after figuring it out! 🙃

3
B

This is really amazing, I'm really glad to see that you're happy with the migration to Hashnode 🤩

Thank you for sharing the process. I'll be happy to get some feedback on your experience so far and some functionalities you think we should add to our APIs.

4
T

Hi Bolaji Ayodeji, thanks! Back-dating posts would be valuable to add to the API, i.e. the published date field, and to not enforce the front-end age restriction of ~6 years. Thanks!

1
B

Thanks for the feedback Tina Holly!

We're revamping the APIs and we'll support backdating posts in the next release. Stay tuned :)

2
T

Bolaji Ayodeji that’s so great to hear!

Also adding the ability to query my posts and get more than just 6 items. Pagination isn’t documented in the GraphQL API for the query user —> publications —> posts. Once your team adds support for historical post dates in the API, I’d like to query my Hashnode posts, match them with my old post data, and update the published date so that it’s accurate.

1
B

I've noted this Tina Holly, once we release the new version, we'll ensure to document officially.

Thank you once again :)

3

More from this blog

T

Tinacious Design Blog

47 posts