How do I migrate my Wordpress project to Craft CMS?

What would be the best way?

  • 2
    Could you tell us more about your Wordpress project? What types of posts do you have, any content-specific plugins? -- There is always another way to do sth. in Craft, that's why 'the best way' will heavily depend on your project.
    – Victor
    Commented Jun 13, 2014 at 12:09
  • 1
    I just asked because I wanted to help you with your problem, but a generic topic is awesome as well, and will surely help a few people ;)
    – Victor
    Commented Jun 13, 2014 at 12:36

4 Answers 4


At this point in time, you have a few options:

Import Plugins

As of this post, there are a few partial import plugins available and rumors that a few others might be on their way.

  • Sprout Import - Sprout Import supports over 40 data types such as Entries, Users, Assets, Products, Orders, Forms, Email, and Redirects; and more can be added as needed via plugin integrations.
  • Feed Me - Feed Me is a Craft plugin for super-simple importing of content, either once-off or at regular intervals. With support for XML, RSS, ATOM or JSON feeds, you'll be able to import your content as Entries, Categories, Craft Commerce Products (and variants), and more.
  • Import - Handles Entries and allows you to map them to fields in your Entries Sections
  • EE/Craft Import - While this plugin has EE in it's title, it looks like it's framed more around XML imports in general and promotes itself as being a starting point if you have other custom import needs.

Import Service

Full disclosure, my company offers a migration service to help folks migrate to Craft. We use a combination of a private plugin, custom scripts, and manual processes when necessary. We find, in most cases, many things about your data architecture can be improved when migrating to Craft. So, while an import plugin can help with some heavy lifting, being able to make architecture decisions on how to import certain types of content outside of what a plugin would allow is useful for improving user experience and getting the most of of Craft. For example, content that fits nicely in Singles and Matrix Fields don't always have equivalents in other CMSs, yet frequently other CMSs have content that fits these use cases.

Do It Yourself

If you want to roll up your sleeves, you can create a utility plugin or script for your own needs. If you need to go this route, you probably want to import your data using Craft's Service Layer and the save methods for each of the individual Elements you are importing.

You can see some examples of this in the plugins available on GitHub above, or read up more on the service layer in the Craft docs. A good place to start may be the Entries Service.

You will need to get your data into a format that matches the EntryModel and then you can pass that information to the saveEntry method:


That's a fairly simple explanation, but the gist of where to start. All of the other Elements are going to have similar Models and save methods you can use to import your data.


Here is how I did it on a recent project:

  1. Create a temporary WP site to work in: I installed WP locally, imported the database, and downloaded the wp-content/uploads folder. You don't need the theme or any plugins (unless they affect the content output). In the Reading section of the WordPress settings, change "blog pages show at most" to a number higher than the number of posts in the system. You could also do this in a hidden template on the live site if you like to live on the edge. I was actually importing from a WordPress.com site, so I first had to export from that and then import into a self-hosted site.
  2. Migrate comments to Disqus: Create a new site in Disqus and install the Disqus plugin in your local WP installation. Let it run its import process to move all your existing comments into their system. Now the comments are their responsibility, and you only have to worry about the posts.
  3. Export the posts to a CSV: Paste the code below into the index.php file of WP's default twentyfifteen theme. Now when you visit the homepage of the temporary site, it will output a CSV file instead of HTML. Press cmd/alt-s to save it to a file. You may need to tweak the code a bit depending on your needs, but this should get you close. The interesting part is lines 20-23, where we apply the the_content filter (which replaces WP's short-tags), fix some character encoding issues, and replace image URLs with their corresponding URLs on the new site. I also set a "fullWidth" transformation on all the images, which I created in my Craft site to limit the images to the width of the page. See below for more on that. Save that resulting CSV file somewhere.

$df = fopen("php://output", 'w');
fputcsv($df, array(

global $more;
if ( have_posts() ) :
    while ( have_posts() ) : the_post();

        $more = 1;
        $content = apply_filters( 'the_content', get_the_content() );
        $content = str_replace( ']]>', ']]&gt;', $content );
        $content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5, 'UTF-8');
        $content = preg_replace('#http://cmnh-blog.dev/wp-content/uploads/\d{4}/\d{2}/(.+?)\.(jpg|jpeg|png|gif)#', 'http://childrens-museum.s3-us-west-2.amazonaws.com/blog/_fullWidth/$1.$2', $content);
        $content = preg_replace('#https://childrensmuseumnh.files.wordpress.com/wp-content/uploads/\d{4}/\d{2}/(.+?)\.(jpg|jpeg|png|gif)#', 'http://childrens-museum.s3-us-west-2.amazonaws.com/blog/_fullWidth/$1.$2', $content);
        $cats = implode(', ', wp_get_post_categories( $post->ID, array( 'fields' => 'names' ) ));
        $tags = implode(', ', wp_get_post_tags( $post->ID, array( 'fields' => 'names' ) ));

        $row = array(
            html_entity_decode(get_the_title(), ENT_QUOTES | ENT_HTML5, 'UTF-8'),
        fputcsv($df, $row);


echo ob_get_clean();
  1. Create user accounts: If you set up user accounts before importing the posts, the authorship will be maintained. Just make sure to use the same email address for each person as in the old site.
  2. Import the content: I used Import for this, although FeedMe might actually work better, as it will create Categories for you on the fly.
  3. Reconnect the comments: If you are keeping the same URL structure, you can just use Disqus's Domain Migration Tool to update their records from the temporary WordPress site to your live domain. If you are changing the URL structure as well, you'll need to use URL Mapper and somehow generate a CSV of corresponding old and new URLs for each post. Now you can add the Disqus embed code to your post template and the comments should appear.
  4. Generate image transforms: Remember how we set a transform on the images in the posts? Craft won't automatically generate those. So create the asset source and copy all the images in from your WP site. Now reindex the asset source in Craft and make sure you can see all the files in the Assets tab. Finally, create a new template with the following code. Open it in the browser and wait for all the images to appear. If you have more than 200 images, you will need to set the offset to 200 and run it again, and so on until all the transforms have been generated.
    {% set images = craft.assets.source('blogImages').limit(500).offset(0) %}
    {% for image in images %}
        <img src="{{ image.url('fullWidth') }}">
    {% endfor %}
  5. Check for broken styling: You will need to include WordPress's default classes in your new stylesheet, or you will lose image alignment and such. If there were any other markup patterns in the WP site that were generated by plugins, you will also need to accommodate those. If necessary, you can also add additional preg_replace lines to the export script to manipulate the markup as needed.
  • I've updated index.php of my theme with the code to export a CSV, but when I visit the page in a browser, it's being printed out to the page and not saving a CSV. It's also not printing all the posts either, only about 10 of more than 100.
    – Tyssen
    Commented Oct 1, 2015 at 6:14
  • You can just cmd-S to save the CSV as a file. And yes, you will need to set the "posts per page" in your WordPress Reading settings to a number higher than the number of posts. I will edit my answer to include that. Commented Oct 1, 2015 at 22:14
  • Great, thanks, that works fine for saving the CSV. Now I'm having trouble importing the CSV. I'm not sure whether it's the way the CSV is formatted. Would you have a small sample of one you've used you could post somewhere for comparison?
    – Tyssen
    Commented Oct 2, 2015 at 2:58

If you're just trying to migrate data, the most simple method would be to use a WordPress plugin to export your posts to a CSV and import it into Craft using this Import Plugin by Bob Olde Hampsink. This is just for posts. I'm not sure what you would do for pages, since we have a special section type for those.

A WordPress Import Plugin has not yet been created because many, if not most, Craft developers came from ExpressionEngine.


Its not a full-blown guide yet, but the Feed Me Guide will get you off to a good start. That really deals with getting the data out of Wordpress. Handles Advanced Custom Fields, WooCommerce, Custom Taxonomies and Custom Post Types.

Once you've got out export file, you can following the Importing Entries guide for Feed Me.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.