10 min read

Migrating Wordpress to Gridsome on Netlify through GitHub Actions

Justin Yoo

This post discusses the whole process that migrates existing Wordpress websites to gridsome based on vue.js, deploys them to Netlify through GitHub Actions.

Why Migration?

There's no doubt that Wordpress is one of the most well-known and well-made blog publishing tools in the world. However, I have to deploy it to somewhere and maintain it. It's OK unless any issue is coming up, which make our lives harder. Wordpress has continuously evolved so that it automatically updates its core, plugins and themes, but it sometimes stops working without knowing it. We also want to avoid our maintenance efforts as much as possible, including website and database. On the other hands, hosted Wordpress is really handy because we don't have to care for most things. But it becomes costly if we need to add custom domains, SSL certificates, custom plugins and custom themes.

Because of these issues, I've been looking for alternatives using static site generators such as Jekyll, Hexo and Hugo, but none of them was satisfying. Then I found Gatsby based on React. As I've never used React before, although it looks very promising, I didn't even start taking a look. Instead, I looked for another tool based on vue.js that I used to build some web apps before, and ola! found gridsome! So, I played around this tool and wrote this blog post and this post. And finally, I decided to use gridsome for my migration.

Why GitHub Actions?

Instead of Azure DevOps, I chose GitHub Actions because I don't have to leave GitHub to build and publish. If I select Azure DevOps, I have to create an instance, followed by creating a project and configuring it. Too much work for my simple blog hosting. Additionally, the fact that GitHub Actions is a fork of Azure Pipelines is appealing to me, and it's modified easier for us to use. And the runners for GitHub Actions are running on Azure. Why not using it then?

If there is no GitHub Actions, I would definitely go for Azure DevOps, because it gives the best user experience as a serviced and free service supporting open source projects.

Why Netlify?

Azure Blob Storage for static website hosting feature was my first consideration in the first place. However, one blob storage can host only one static website. I'm hosting three websites – justinchronicles.net, aliencube.org and devkimchi.com. One blob storage for three websites is not possible. In addition to this, after the custom domain configuration, to use HTTPS connection, I have to use Azure CDN or something similar extra work is required, which I wanted to avoid. Therefore, Netlify has become my choice.

Converting Wordpress Posts

XML Export

Wordpress doesn't support markdown export out-of-the-box. There are third-party plugins for it, but not working as my expectations. Therefore, I just exported all posts using the built-in export feature. I've now got the XML file, and I needed it to be converted to markdown.

Markdown Conversion

This took most of my migration time and efforts. First of all, I used wordpress-export-to-markdown to convert the XML file to markdown files. But the result markdown files didn't have enough front-matter details, so I had to open every sing file to update each front-matter. As Jekyll's front-matter has been widely adopted to other static site generators, including gridsome, it wasn't that difficult. It was just a matter of time for conversion.

The front-matter after the markdown conversion from XML looks like this:

---
title: "Cloud Service Lock-in Guidelines from UK Government"
date: "2019-12-31"
---

But the default front-matter generated by gridsome has more attributes:

---
title: "Post Title"
slug: post-unique-slug
description: "Post description"
date: "2020-01-03"
author: Justin-Yoo
tags:
cover:
fullscreen: false
---

Therefore, except title and date, every other attribute were manually updated. As there were a relatively small number of posts, it didn't take too much, but I wouldn't do it again. Anyway, I completed all the markdown conversion. Yay! Nearly there.

Preparing Gridsome Blog Theme

gridsome offers many official and third-party starters. I chose Bleda because it basically includes many other plugins out-of-the-box.

Preparing Gridsome Plugins

As mentioned earlier, the starter contains almost everything I needed, except...

gridsome-plugin-remark-embed

This plugin is to embed social media for Twitter, YouTube and GitHub gist. However, as it has a bug on the gist embedding script, I raised a PR to fix the bug and have been waiting for the official release. Instead, while I'm waiting for the official release, I locally copied the updated script so that it can be used later on in the GitHub Actions.

vue-disqus

This plugin is to add comment feature. I've already been using Disqus for a while and reviewing whether I keep using it or not after the migration. But as I've already got many valuable comments there, I decided to keep it for now.

Configuring Gridsome

Metadata Configuration

All metadata, including the favicon, were updated for my blog settings.

...
module.exports = {
siteName: 'Dev Kimchi',
siteDescription: "Fermentation: Turning .NET, Web and Cloud into Something",
siteUrl: 'https://devkimchi.com',
titleTemplate: `%s | DevKimchi`,
icon: 'src/favicon.png',
...

To keep the existing Wordpress permalink structure, gridsome.config.js updated the permalink settings.

Also, the RSS feed URL has been updated.

...
{
use: 'gridsome-plugin-rss',
options: {
...
feedItemOptions: node => ({
title: node.title,
description: node.description,
//url: 'https://devkimchi.com' + node.slug,
url: 'https://devkimchi.com' + node.path,
author: node.author,
date: node.date,
}),
...
},
},
...

GitHub Gist Style Configuration

The following stylesheet has been added to src/main.js to follow the GitHub gist style.

...
head.link.push({
rel: 'stylesheet',
href: 'https://github.githubassets.com/assets/gist-embed-d89dc96f3ab6372bb73ee45cafdd0711.css'
})
...
view raw main-gist.js hosted with ❤ by GitHub

Cover Image Configuration

The original starter doesn't show the cover images on the list page. I changed /src/components/PostItem.vue to display the cover images.

...
<header class="text-center mb-8">
<div v-if="post.cover">
<g-link :to="`${post.path}/`" class="text-black font-bold"><img :src="`${post.cover}`" /></g-link>
</div>
<time :datetime="post.datetime" class="text-gray-700 text-xs mb-2 uppercase">{{ formatPublishDate(post.datetime) }}</time>
...

And this also needs the GraphQL query updated. Both /src/templates/Author.vue and /src/templates/Tag.vue have been updated.

...
edges {
node {
...on Post {
id
title
datetime: date (format: "YYYY-MM-DD HH:mm:ss")
path
content
excerpt
description
timeToRead
cover
tags {
id
title
path
}
}
}
}
...
view raw graphql.vue hosted with ❤ by GitHub

All the settings on gridsome have been completed.

Preparing Netlify Instance

We need an instance on Netlify for static website hosting. We can directly integrate GitHub with Netlify for it, but we're going to use GitHub Actions. Therefore, we create an instance manually, by dropping any file.

Now, the newly created instance has its own instance ID and site name, which will be used in GitHub Actions.

Finally, we need to create a Personal Access Token for deployment through Netlify CLI.

Preparing GitHub Actions Workflow

We've now got the static website artifact and Netlify instance. The GitHub Actions workflow will orchestrate all the things.

Event

I'm using the master branch to update the original starter, and the dev branch to publish posts. Therefore, I set up the push event only triggered by the dev branch.

on:
push:
branches:
- dev

Runner

I used Ubuntu LTS 18.04 as the GitHub-hosted runner.

jobs:
build_and_publish:
runs-on: ubuntu-latest

Steps

The first step should be the checkout action.

steps:
- name: Checkout the repo
uses: actions/checkout@v1

All the rest actions are using the built-in shell action. This action downloads and installs the Netlify CLI. Due to the -g option, we should use the sudo command here.

- name: Install Netlify CLI
shell: bash
run: |
sudo npm install -g netlify-cli

This action restores all the npm packages.

- name: Install npm packages
shell: bash
run: |
npm install

This interim action will replace Gist.js until the official release is updated.

- name: Monkey patch npm package (Interim)
shell: bash
run: |
cp patches/Gist.js node_modules/@noxify/gridsome-plugin-remark-embed/src/providers

This action builds the app.

- name: Build app
shell: bash
run: |
npm run build

As the second last step, it copies the domain redirection settings to dist.

- name: Apply redirects
shell: bash
run: |
cp _redirects dist

And finally, the dist directory is published to Netlify through CLI. Both NETLIFY_SITE_ID and NETLIFY_AUTH_TOKEN are secrets stored in the repository settings.

- name: Publish app
shell: bash
run: |
netlify deploy -p -s ${{ secrets.NETLIFY_SITE_ID }} -a ${{ secrets.NETLIFY_AUTH_TOKEN }}

We all complete the blog migration from Wordpress to gridsome. Now, I don't have to worry about maintenance unless GitHub shuts down.