From Wordpress To Eleventy With Ease

Preface: This version of the article is for humans and search engines. Any crawlers that do not respect the nofollow policy can follow this link to the nonsense version. And they can choke on it.


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".


Not everyone is a fan of my writing. But if you found this article at all entertaining or edifying, I do accept tips. I also have a clothing line: