Share

Migrating your website’s content from WordPress to Contentful can seem daunting at first, but with the right approach, it’s a manageable process that opens up a world of flexibility. WordPress has been a go-to platform for years, thanks to its ease of use and vast ecosystem of plugins. However, as businesses and developers shift toward headless CMS solutions, Contentful stands out for its API-first design and ability to deliver content across multiple platforms. If you’ve decided to make the switch, one of the first steps is figuring out how to import your WordPress XML file into Contentful. This guide will walk you through the process step-by-step, ensuring your content finds a new home without losing its essence.

Step 1: Export Your WordPress Content as XML

The journey begins in your WordPress dashboard. WordPress offers a built-in export tool that allows you to download your site’s content in an XML format, often referred to as a WXR file (WordPress Extended RSS). To get started, log in to your WordPress admin panel and navigate to Tools > Export. Here, you’ll see options to export all content or specific types like posts, pages, or media. For a full migration, select “All content” to capture everything—posts, pages, comments, categories, tags, and media references.

Once you click the “Download Export File” button, WordPress will generate and download the XML file to your computer. This file is the backbone of your migration, containing structured data that represents your site. Open it in a text editor to get a sense of its structure—you’ll see elements like <item> for each post or page, <category> for taxonomies, and <wp:attachment_url> for media. Understanding this format will help you later when mapping it to Contentful’s system.

Step 2: Analyze the WordPress XML Structure

Before you can import anything into Contentful, you need to understand what’s in your XML file. The WXR format is hierarchical and uses tags to organize content. For example, a blog post might look like this:

<item>

    <title>My Blog Post</title>

    <link>https://example.com/my-blog-post</link>

    <pubDate>Mon, 24 Mar 2025 10:00:00 +0000</pubDate>

    <dc:creator>admin</dc:creator>

    <description></description>

    <content:encoded><![CDATA[This is the content of my post.]]></content:encoded>

    <wp:post_type>post</wp:post_type>

    <wp:status>publish</wp:status>

</item>

Key fields include the title, content, publication date, and post type. Media files, like images, are listed as separate <item> elements with attachment URLs. Categories and tags are nested under <category> tags. Take note of the fields you want to preserve in Contentful, as not everything (like WordPress-specific metadata) may be relevant.

This step is crucial because Contentful doesn’t use the same structure. Instead, it relies on content models—custom blueprints you define for different types of content. You’ll need to decide how to translate WordPress posts, pages, and other data into these models.

Step 3: Set Up Your Contentful Space

If you don’t already have a Contentful account, sign up and create a new space. A space in Contentful is like a project container where all your content lives. Once your space is ready, head to the Content model tab to define your content types. Think of content types as templates for your data—for example, you might create a “Blog Post” type for posts and a “Page” type for static pages.

For a “Blog Post” content type, you could include fields like:

  • Title (Text, short)
  • Slug (Text, short)
  • Content (Text, long, or Rich Text for formatting)
  • Publish Date (Date & Time)
  • Categories (Reference to a separate “Category” content type)
  • Featured Image (Media)

Create these fields based on what’s in your XML file. If your WordPress site uses custom post types or fields (via plugins like ACF), replicate those as closely as possible. For media, Contentful stores assets separately, so you’ll upload images later and link them to entries.

Step 4: Parse the WordPress XML File

Contentful doesn’t have a native importer for WordPress XML, so you’ll need to parse the file yourself. This requires some scripting, and languages like JavaScript (Node.js) or Python are popular choices. Let’s use JavaScript as an example, since Contentful’s API integrates well with it.

First, install a library to parse XML, like xml2js:

npm install xml2js

Then, write a script to read and convert the XML:

const fs = require('fs');

const xml2js = require('xml2js');

fs.readFile('wordpress-export.xml', (err, data) => {

  if (err) throw err;

  xml2js.parseString(data, (err, result) => {

    if (err) throw err;

    const items = result.rss.channel[0].item;

    const posts = items.filter(item => item['wp:post_type'][0] === 'post');

    console.log(posts);

  });

});

This script reads the XML file, converts it to a JavaScript object, and filters for blog posts. You can loop through posts to extract fields like title, content, and date, storing them in a format suitable for Contentful.

Step 5: Transform Data for Contentful

Contentful expects data in JSON format, structured according to your content types. For each WordPress post, create a JSON object that matches your “Blog Post” content type. Here’s an example:

const contentfulPosts = posts.map(post => ({

  fields: {

    title: {

      'en-US': post.title[0]

    },

    slug: {

      'en-US': post.link[0].split('/').pop()

    },

    content: {

      'en-US': post['content:encoded'][0]

    },

    publishDate: {

      'en-US': post.pubDate[0]

    }

  }

}));

Note the ‘en-US’ locale—this is Contentful’s default. If your site uses multiple languages, adjust accordingly. For categories or tags, you might need to create separate entries and reference their IDs.

Step 6: Upload Media to Contentful

WordPress XML includes media URLs, but Contentful requires you to upload assets to its platform. Use the Contentful Management API to automate this. First, install the Contentful Management SDK:

npm install contentful-management

Then, download and upload each image:

const contentful = require('contentful-management');

const axios = require('axios');

const client = contentful.createClient({

  accessToken: 'YOUR_MANAGEMENT_API_TOKEN'

});

async function uploadMedia(item) {

  const attachmentUrl = item['wp:attachment_url'][0];

  const response = await axios.get(attachmentUrl, { responseType: 'arraybuffer' });

  const space = await client.getSpace('YOUR_SPACE_ID');

  const environment = await space.getEnvironment('master');

  const asset = await environment.createAsset({

    fields: {

      title: {

        'en-US': item.title[0]

      },

      file: {

        'en-US': {

          contentType: 'image/jpeg', // Adjust based on file type

          fileName: attachmentUrl.split('/').pop(),

          upload: Buffer.from(response.data)

        }

      }

    }

  });

  await asset.processForAllLocales();

  return asset;

}

Call this function for each attachment in your XML, storing the asset IDs to link them to posts later.

Step 7: Import Content into Contentful

With your data transformed and media uploaded, it’s time to create entries in Contentful. Using the same Management API, loop through your JSON objects:

async function importPosts(posts) {

  const space = await client.getSpace('YOUR_SPACE_ID');

  const environment = await space.getEnvironment('master');

  for (const post of posts) {

    await environment.createEntry('blogPost', post);

  }

}

If a post has a featured image, add the asset ID to the fields object under a “Featured Image” field, using a reference like sys: { type: ‘Link’, linkType: ‘Asset’, id: ‘ASSET_ID’ }.

Step 8: Verify and Publish

After running your script, log in to Contentful to verify the imported content. Check a few entries to ensure titles, content, and media match your WordPress data. If everything looks good, publish the entries manually or via the API. Test your front-end (if connected) to confirm the content displays correctly.

Troubleshooting Common Issues

  • Missing Fields: If data is missing, double-check your XML parsing and JSON mapping.
  • Media Errors: Ensure URLs are valid and your API token has sufficient permissions.
  • Rate Limits: Contentful’s API has limits—add delays between requests if needed.

Automating the Process

For larger sites, consider tools like wp2contentful (a community script) or hire a developer to refine the process. Alternatively, break your XML into smaller chunks to avoid overwhelming the API.

By following these steps, you’ll successfully import your WordPress XML into Contentful, paving the way for a modern, headless CMS experience. The effort pays off with greater control over your content and delivery, making it worth the transition.


Share