From Wordpress To Eleventy With Ease

I recently converted this site from an old Wordpress to Eleventy. I then promised I’d share how I did it, because it really doesn’t have to be difficult. In fact, with the small node script to follow, you should have everything set up in about 5 minutes.

Step 1: Get the old Wordpress data

First you need to get your post content—and associated media—from Wordpress. Since I’ve obliterated the original Wordpress site now, I can’t retrace quite how I did this. I remember it being very straightforward. To get all of my Wordpress post data as JSON, I either used the core export functionality or a popular plugin. Or maybe the Wordpress REST API. If I could manage it, you shouldn’t have much trouble. To get all the images, I almost certainly used a plugin like this one.

In any case, you should end up with a JSON file full of stuff that looks something like this…

...
"post": {
  "ID": 14,
  "post_author": "1",
  "post_date": "2014-08-01 00:00:09",
  "post_date_gmt": "2014-08-01 00:00:09",
  "post_content": "<p>Hi everybody! I've just done a lot of cocaine on the company expense account...",
  "post_title": "Reinventing The Hyperlink",
...

… and a directory of media with subfolders named after years, like:

You’ll want to unzip this exported media archive into wherever the rest of your Eleventy images go.

Step 2: JSON to markdown plus Front Matter

This is where you can use my simple node script. Here it is in its entirety, with notes to follow:

const transformAndWriteToFile = require('json-to-frontmatter-markdown').default;
const wordpressData = require(__dirname + '/wordpress.json');
const slugify = require('slugify');

const posts = wordpressData.post.posts;
Object.keys(posts).forEach((p, i) => {
  let post = posts[p].post;
  transformAndWriteToFile({
    frontmatterMarkdown: {
      frontmatter: [
        { title: post.post_title },
        { date: post.post_date.split(' ')[0] },
        { permalink: `article/${slugify(post.post_title).toLowerCase()}/index.html` }
      ],
      body: post.post_content.replace(/http:\/\/www.heydonworks.com\/wp-content\/uploads/g, '/images')
      },
      path: './src/posts',
      fileName: `${slugify(post.post_title).toLowerCase()}.md`
    })
})
  1. Take a note of the require lines. You will have to npm install (or Yarn, whatever) the json-to-frontmatter-markdown and slugify dependencies. The wordpress.json file is the JSON data I exported in Step 1: Get the old Wordpress data.
  2. The frontmatter part takes the properties I’m interested in from each post and converts them to front matter values. The permalink structure I happen to use starts with /article. By salvaging this structure from the original site, I could avoid doing rewrites/redirects.
  3. The body part writes the post content but, critically, re-paths each of the images to use the local Eleventy URL
  4. The path is where to write the file (presumably where all my non-legacy posts also reside)
  5. Finally, fileName actually names the markdown file itself, slugifying the post_title value as my Wordpress site was instructed to do.

Step 3: Run the script

You can set up an npm script if you really must, but since I knew I’d only run this once, I just hit node wordpress.js (where wordpress.js is the name of the script file, and it’s in the root of the directory).

Step 4: There is no step 4

This step doesn’t even exist. But it's worth noting that, on my site, I split my old Wordpress posts between archive and best (my best posts) directories. Each article (including each new article) on my site has an article/slug-here URL structure, but belongs to one of the latest, best, or archive collections.

In Eleventy, you can set the collection per-post by adding a tags property to its front matter. But it’s less verbose to to add a data file to the appropriate directory instead. For example, my latest posts go in the /latest directory, which contains a latest.json file with the line "tags": "latest".