Moving from ExpressionEngine to WordPress in 64 easy steps.

I’ve had a lot of requests for a post on how I moved my ExpressionEngine blogs over to WordPress so here it, finally, is. And, no, it doesn’t really take 64 steps.

The problem with moving from EE to WordPress is that while WP has an impressive selection of importing tools for various platforms built into it, ExpressionEngine isn’t one of the supported platforms. This means we have to do it ourselves and so that’s what I set out to do. You will find in the ExpressionEngine Wiki some information on how to export to the MovableType Format, but this has a couple of limitations that made it less than ideal. For example, I used the SolSpace Tags module in ExpressionEngine and wanted to move all the tags over to WordPress, but the MT format has no facility to do that. A much better  solution would be to export to WordPress’s native WXR format which does support tags, but finding info on how the WXR format is defined (it’s an extension of XML) was more difficult than I thought it would be. It doesn’t appear anyone has sat down and specifically posted what WordPress looks for and accepts in an WXR file.

Eventually I set up a test blog in WP, put in some content that hit all the features I wanted to support, and then did an WXR export to see how the file was set up. I’m far from an expert on the WXR format, but I managed to figure out enough of it to get things to work. My method is similar to the aforementioned MT export templates except that it outputs WXR formatted data instead. You can download the templates by clicking here.

To use them you’ll want to create a new template group called “export” in ExpressionEngine. Then create two RSS templates in that group to hold the templates themselves. I called the first one “export” and the second one “comments.” It doesn’t really matter what you call the first one, but the second one must be named comments so it’ll be embedded properly. If you change the name then be sure to change it in the first template file. Both templates should be set in EE as RSS pages and you should set Allow PHP to “Yes” and “On Input” on the comments template. In the first template on the very first line is the global variable {assign_variable:master_weblog_name=”yourblogshortname”} which you should change to the short name for your blog in EE.

Once you’ve done all of that you’re almost ready to start exporting data. I use the word almost because there’s one thing that I can’t account for ahead of time and that’s the amount of data you are exporting and what RAM limits your server has. There’s also the fact that these templates do not save out to a file. Instead you have to right click on the “view” link in EE’s template listing and select “open in a new tab/window” then click on that new tab and select “show page source” which will open another new window, and then save that new window’s output to an XML file.

Doesn’t matter what you call the files (I named mine SEB1.xml, SEB2.xml, etc.), but if you try to output all of your data at once and you have a crap load of it then your browser will probably crash before you can save the file. On top of all of that, WordPress has a import size limit of 10MBs per file. In the case of SEB, at the time I made the move, I transferred some 6,500+ entries and 75,000+ comments and there was no way in hell it was all going to come out as one great big file so I ended up having to do multiple exports.

Here’s how you do that: In the first template file there’s a line that reads as follows:

{exp:weblog:entries weblog="{master_weblog_name}" dynamic_start="on" limit="9999" offset="0" sort="asc" rdf="off"}

The two key parameters are the limit and offset. The limit sets the total number of entries that’ll be included an in export and the offset tells it at what entry to start at. If you have a very small blog (couple of hundred entries with less than a dozen comments each) then you might be able to get away with a single export using those settings, but if not then here’s where you will have to experiment to find out what you can get away with and it will depend on how many entries you have as well as how many comments on those entries. There is a similar line in the comments template which limits how many comments to include that is set to 1,000 comments. None of the entries on SEB ever hit 1,000 comments so that worked just fine for me, but if you have entries with more than 1,000 comments you may need to edit that template as well. Due to memory limitations on my server I found that I could only export between 100 and 300 entries at a time before EE would abort with an out of memory error. This meant that I ended up exporting some 32 files total to get everything moved over. If I got an out of memory error then I’d go in and change the limit to a smaller number (usually decrementing by 50 each time) until I got a successful export. Once it was successful I’d go back in and change the limit back to 300 and increase the offset by however much the last export put out. Do that as many times as you need to to export all your data.

If that sounds like a pain in the ass, well, it is, but there’s still more that can go wrong. Because you’re generating an XML file your browser can be pretty fucking picky about any weird or garbled characters that might happen to be in your code. SEB was originally on MovableType and in the move from that to ExpressionEngine there were a few entries that ended up with some non-standard characters in them. Whenever an export hit one of those garbled characters it would cause an XML error and I’d have to try and figure out which entry was causing the problem, edit it in EE to fix the garbled characters, and then retry that particular export. I’d say there was about a dozen entries or so that caused me fits, but if you’ve been running on EE all along then this probably won’t be a problem for you.

Now for some good news: WordPress is impressively good at importing those WXR files. If you screw up and forget to change the offset number and end up with a duplicate file (or just one that has a handful of duplicates) WordPress will NOT create duplicate entries in your database. It’ll report those as duplicate entries and reject them. WordPress will also ask you how to handle entries written by people other than the account you are logged in as when doing the importing. You can either reassign those entries to an existing WP user or you can have WP create accounts for those users when doing the import. WordPress is also just fine with importing one file after another to build up your database back to normal.

Some other things to keep in mind with these templates: They make the assumption you’re using the default field names of {body} and {extended} for your blog entries. I also didn’t include {summary} as I never used it myself so you’ll need to add that in if you want it. The code I used for exporting Tags is not included because not everyone uses that module, but I can supply it if you want it. One other thing I should have done and didn’t think of until after I was finished was adding in code to check if the {extended} field existed and if it did to put in the WP code for a Read More link. So for SEB, all the entries where I had a body and extended section became one big posting under WP. If you’re at all comfortable with making EE templates then you should be able to look at these, see how I did things, and tweak them according to your needs.

That’s pretty much the process in a nutshell. Hopefully this isn’t too confusing. If nothing else it should give you a starting point if you want to make the transition yourself. Perhaps someone else will come up with an even better way to do it. Feel free to ask me any questions you have in the comments.

72 thoughts on “Moving from ExpressionEngine to WordPress in 64 easy steps.

  1. @ Les:

    Les, I feel like the village idiot. Basically haven’t used EE in 2.5 years, since I started new blogs with WordPress.

    I looked at the index template for the blog and saw this:
    {exp:weblog:entries weblog=”suit” …

    So I thought the blog short-name is “suit”. And that’s what I had changed the master_weblog_name to:


    Where do I find the name that I need to use?

  2. The index template should be a good indication of the short name, but you can double check it by going to Admin › Weblog Administration › Weblog Management and looking for the short name there. Presumably the template should have the same short name though otherwise it doesn’t know which blog to pull the data from.

  3. Thanks, Les, I checked in admin and it’s the correct short name. So this is what I have:

    {exp:rss:feed weblog=”{master_weblog_name}”}

    I tried the other blog short names too and get the same error:


    The weblog specified in your RSS feed does not exist.

    What am I missing?

  4. Hmmm. One more seemingly stupid question: Under the template’s preferences do you have it set to “RSS Page”? You’ll find the option under
    CP Home › Templates › Template Preferences.

  5. Yes, RSS, PHP and input.

    This is typical of my EE experiences. I’d leave those old blogs alone, but they’re hosted at engine hosting (I don’t want to pay anymore since I have a reseller account elsewhere) and I figured I’d import the blogs into WP to update and that it would be easier than learning again how to install Expression Engine and how to move the site. I had also hoped that I’d be able to sell my commercial EE license, but as I looked at the latest 1.x release, that’s no longer allowed without prior written permission.

    Maybe I’ll just try to move it all.

  6. Les;

    This looks like a bit of the brill, but I’m having an issue. After a fair amount of data whacking, I get a well-formed feed, but am informed that “This feed has no entries.”

    The article count is 2500+ and nearing 2000 comments.

    It seems clear to me that I have a date issue of some kind. But “show expired entries=”yes” doesn’t fix it, and I am at the end of my pseudo-expertise.

    Any clueage?


  7. Mark, if you’re exporting everything then you shouldn’t need to use a date range at all. It’s been awhile since I last looked at these templates, but make sure that the exp:weblog:entries weblog=”” has either the variable master_weblog_name in it or the shortname for the weblog itself.

    Truth is, I just used the master_weblog_name variable so that you wouldn’t have to go through the template changing all the shortnames to your blog, but there’s no reason why you can’t do that if you wanted to. There’s only two places it needs to be specified: The first is at the top in {exp:rss:feed weblog=”your-blogs-shortname”} and then later in the {exp:weblog:entries weblog=”your-blog’s-shortname” dynamic_start=”on” limit=”100″ offset=”0″ sort=”asc” rdf=”off”} tags.

    Keep in mind you may need to play with the limit parameter to ensure you don’t run out of memory when trying to generate the output. On average I could only export around 150 entries at a time without it crapping out, which is why I used the offset parameter to generate multiple files.

  8. @ Les:

    Spotted the problem. Finally. (Like Barleycorn, I can see through a brick wall, given time.) Odd thing. The quotes in the {exp:rss:feed:…} tag, around the blog name were curly quotes. Fixed that, set the limit to 150 and it wailed.

    You say to save as .xml. Out of Firefox, the default is .html (although it says the page doesn’t have any style info — no kidding). If I just give it a filename extension of .xml, is that sufficient?

    Thanks for the guidance.


  9. Sorry about the curly quotes. Not sure how they got in there. Yes, ending the file name with an .xml should be sufficient.

  10. I am trying to export entries and comments from EE 1.4.2 to WP. I got the entries, but my comments will not export. I get only a correct XML file without any comments.
    Anyone any ideas? I tried a lot of options already.

  11. Joel, not sure what you mean. The older ExpressionEngine I was using put images into entries using standard HTML which should still be in the entry when it’s exported. So long as the path is the same it should still display. I’m not aware of EE having a image caption option.

  12. Just a quick note to say thank you for putting this together! I got everything exported from a few different channels into custom post types and taxonomies with meta fields in WordPress. If only the EE developer didn’t put all the page content into the templates …

  13. Well, its an old thread but i’m trying to do the same thing.

    Using EE 2.4, i think they changed the “weblog” name for something else (i am totally new to EE, i’m rather a WP user).

    Anyway, i have something like 25 blog entries to export and they are related to the Blog channel.

    When i follow your indications, i end up with an empty feed. Don’t know why. And the “{assign_variable:master_weblog_name=”blog”}” line appears as is on the source view.

    Any idea what is wrong?

  14. Jimispire, I wrote these templates for EE 1.x as I left around the time they released 2.0. I suspect some of the tags changed (e.g. I know the “weblog” variable was changed to reflect EE becoming more of a CMS system than a blogging system). You may find you have better luck with the instructions over at Revocomm which you’ll find by clicking here. They have templates specifically for exporting from EE 2.x.

  15. Ok, i had made an error; the export rss template was set to web page instead of rss.

    But now this pops up:

    This page contains the following errors:

    error on line 1 at column 1: Document is empty
    Below is a rendering of the page up to the first error.

  16. Thank you for the article! Just want to share one more way to move ExpressionEngine to WordPress. It’s CMS2CMS service where migration is performing automatically.

  17. Pingback: 블로그 이전 일지 » 안드로메다 토끼

  18. Hi Les I’m using Expression Engine 1.4.1 and wish to migrate to WordPress have followed all the steps but I keep on getting the following:


    The weblog specified in your RSS feed does not exist.

  19. Apologies for not responding sooner, Uubunifu, but I did get your email and replied to you there.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.