
WordPress to Craft CMS Migration: Preserving Your Content, Design, and SEO
Moving from WordPress to Craft CMS can feel like a major undertaking, but with the right approach, you can make the switch without losing your hard-earned content, design work, or search rankings. This guide walks you through the entire migration process, from initial planning to post-launch monitoring, with practical code examples and specific steps you can follow.
Why Teams Choose to Migrate from WordPress to Craft CMS
WordPress powers millions of websites, but as sites grow and requirements become more complex, its limitations start showing. Plugin conflicts, security concerns, and performance issues push many teams to look for alternatives.
Craft CMS offers a different approach. Instead of relying on dozens of plugins, Craft provides built-in flexibility for custom content structures. You get cleaner code, better performance, and more control over how your site works. The trade-off? Migration requires careful planning and execution.
Prerequisites Before Starting Your WordPress to Craft Migration
Before you begin moving content, you'll need several things in place:
Technical Requirements:
- Access to your WordPress admin panel and database
- A staging server with PHP 8.2 and MySQL 5.7.8 or PostgreSQL 13
- Composer installed for managing Craft dependencies
- Basic familiarity with command-line operations
WordPress Site Preparation:
- Complete backup of your WordPress files and database
- List of all active plugins and their functions
- Documentation of your current URL structure
- Export of your current redirects (if any)
- Screenshot or documentation of custom post types and taxonomies
Craft CMS Setup:
- Fresh Craft CMS 5 installation on your staging server
- Admin account created and configured
- Basic project configuration completed
Step-by-Step WordPress to Craft CMS Migration Process
Step 1: Audit and Map Your Content Structure
Start by creating a detailed inventory of your WordPress content. Open a spreadsheet and document:
- All post types (standard posts, pages, custom post types)
- Taxonomies (categories, tags, custom taxonomies)
- Custom fields (especially if using ACF or similar plugins)
- Media files and their organization
- User roles and permissions
Next, map each WordPress element to its Craft equivalent:
| WordPress Component | Craft CMS Equivalent | Notes |
|-------------------|---------------------|-------|
| Posts | Channel entries | Create a "Blog" channel |
| Pages | Singles or Structure entries | Depends on hierarchy needs |
| Custom Post Types | Channel entries | One channel per post type |
| Categories | Category groups | Direct mapping possible |
| Tags | Tag groups | Direct mapping possible |
| Media Library | Assets | Requires volume setup |
| Custom Fields | Field types | May need field type conversion |
Step 2: Export Your WordPress Content
WordPress offers several export methods. For most migrations, you'll want to combine approaches:
Using WordPress's Built-in Export:
# From WordPress admin: # Tools > Export > All content > Download Export File # This creates an XML file with your content
For custom fields and complex data, use WP All Export or create a custom export script:
'any',
'posts_per_page' => -1,
'post_status' => 'any'
]);
$export_data = [];
foreach($posts as $post) {
$export_data[] = [
'title' => $post->post_title,
'slug' => $post->post_name,
'content' => $post->post_content,
'excerpt' => $post->post_excerpt,
'date' => $post->post_date,
'author' => get_the_author_meta('user_login', $post->post_author),
'categories' => wp_get_post_categories($post->ID, ['fields' => 'names']),
'tags' => wp_get_post_tags($post->ID, ['fields' => 'names']),
'meta' => get_post_meta($post->ID),
'featured_image' => get_the_post_thumbnail_url($post->ID, 'full')
];
}
// Save as JSON for easier import
file_put_contents('wordpress-export.json', json_encode($export_data));
}Step 3: Import Content into Craft CMS
We've found that the wp-import CLI tool handles most standard WordPress migrations well, but complex sites often need additional work. Here's how to use it:
# Install wp-import via Composer composer require craftcms/wp-import # Run the import php craft wp-import /path/to/wordpress-export.xml # The tool will: # - Analyze your WordPress structure # - Create matching sections and fields in Craft # - Import all content with relationships intact
For more control over the import process, use Feed Me plugin with custom mapping:
# feed-me-config.yaml
elementType: craft\elements\Entry
siteId: 1
section: blog
entryType: post
fieldMapping:
title:
field: title
node: wp:title
slug:
field: slug
node: wp:post_name
postDate:
field: postDate
node: wp:post_date
body:
field: body
node: content:encoded
categories:
field: blogCategories
node: category
options:
create: trueStep 4: Rebuild Your Templates in Craft
Craft uses Twig templating instead of PHP. You'll need to convert your WordPress theme files:
WordPress header.php example:
>
<?php wp_title('|', true, 'right'); ?>
Becomes this in Craft (_layout.twig):
{{ siteName }} | {{ title ?? entry.title ?? '' }}
{{ head() }}
WordPress loop:
Becomes this in Craft:
{% for entry in craft.entries.section('blog').all() %}
{{ entry.title }}
{{ entry.body }}
{% endfor %}Step 5: Set Up URL Routing and Redirects
Maintaining your URL structure is critical for SEO. Configure Craft's routes to match your WordPress permalinks:
// config/routes.php
return [
// Match WordPress blog structure
'blog///' => ['template' => 'blog/_entry'],
// Category archives
'category/' => ['template' => 'blog/_category'],
// Tag archives
'tag/' => ['template' => 'blog/_tag'],
];For URLs that must change, set up 301 redirects using the Retour plugin:
// Setting up redirects programmatically
use nystudio107\retour\Retour;
Retour::$plugin->redirects->saveRedirect([
'sourceUrl' => '/old-url-pattern/.*',
'destinationUrl' => '/new-url-pattern/$1',
'matchType' => 'regex',
'redirectHttpCode' => 301
]);Step 6: Migrate SEO Metadata
Working with teams has taught us that SEO preservation often determines migration success. Install and configure SEOmatic for Craft:
{# In your templates, pull in existing SEO data #}
{% do seomatic.meta.seoTitle(entry.seoTitle ?? entry.title) %}
{% do seomatic.meta.seoDescription(entry.seoDescription ?? entry.excerpt) %}
{% do seomatic.meta.seoImage(entry.featuredImage.one() ?? null) %}
{# Set up structured data #}
{% do seomatic.jsonLd.create({
'type': 'Article',
'headline': entry.title,
'datePublished': entry.postDate|atom,
'dateModified': entry.dateUpdated|atom,
'author': {
'type': 'Person',
'name': entry.author.fullName
}
}) %}Common Mistakes to Avoid During WordPress to Craft Migration
1. Forgetting Media File Permissions
When migrating media, ensure your Craft assets volume has proper write permissions:
chmod -R 775 web/uploads chown -R www-data:www-data web/uploads
2. Missing Internal Link Updates
WordPress internal links often use absolute URLs. Update them during migration:
// Migration script to update internal links
$content = $entry->body;
$content = str_replace('https://old-domain.com', '@web', $content);
$content = str_replace('/wp-content/uploads/', '/uploads/', $content);
$entry->body = $content;3. Ignoring Custom Field Complexity
ACF repeater fields and flexible content require special handling:
// Converting ACF repeater to Craft Matrix
foreach($acf_repeater as $row) {
$matrixBlock = new MatrixBlock();
$matrixBlock->type = 'blockType';
$matrixBlock->setFieldValues([
'fieldHandle' => $row['field_value']
]);
$blocks[] = $matrixBlock;
}4. Not Planning for Plugin Replacements
Document which Craft plugins replace WordPress functionality:
- Contact Form 7 → Formie or Contact Form
- Yoast SEO → SEOmatic
- WP Super Cache → Craft's built-in caching
- Custom Post Type UI → Native Craft sections
Testing and Verification Steps
Content Verification Checklist
Run these checks on your staging site:
# Check for broken images wget --spider -r -nd -nv -l 2 https://staging-site.com 2>&1 | grep -B1 "404" # Verify all entries imported php craft shell >>> \craft\elements\Entry::find()->count() >>> // Compare with WordPress post count # Check for missing categories/tags >>> \craft\elements\Category::find()->count() >>> \craft\elements\Tag::find()->count()
SEO Audit Process
1. Pre-migration baseline: Export all URLs, titles, and meta descriptions from WordPress
2. Post-migration check: Use Screaming Frog to crawl the staging site
3. Compare results: Look for missing pages, changed URLs, or dropped metadata
4. Verify redirects: Test a sample of old URLs to confirm 301 redirects work
Performance Testing
# Test page load times lighthouse https://staging-site.com --output json --output-path ./lighthouse-report.json # Check Time to First Byte (TTFB) curl -w "@curl-format.txt" -o /dev/null -s https://staging-site.com
User Acceptance Testing
Create test scenarios for content editors:
1. Can they create new entries easily?
2. Do image uploads work correctly?
3. Are preview functions working?
4. Can they find and edit existing content?
Post-Launch Monitoring
After going live, monitor these metrics closely:
- 404 errors: Check server logs and Google Search Console daily
- Search rankings: Track key pages in your ranking tool
- Page speed: Monitor Core Web Vitals in Google Search Console
- User feedback: Set up a feedback form for editors and visitors
Conclusion
Migrating from WordPress to Craft CMS requires careful planning and attention to detail, but the payoff comes in the form of a more flexible, performant, and maintainable website. By following this guide's steps, from initial content audit through post-launch monitoring, you can preserve your valuable content, maintain your design, and protect your search rankings throughout the transition.
Our experience shows that successful migrations happen when teams take time to properly map content structures, test thoroughly on staging environments, and have solid rollback plans. The tools available today, particularly wp-import and Feed Me, make the technical aspects of migration more manageable than ever.
If you're planning a WordPress to Craft CMS migration and need help evaluating your specific requirements, whether it's handling complex custom fields, preserving specialized plugin functionality, or ensuring zero downtime during the switch, we can review your current setup and create a detailed migration plan tailored to your site's unique needs.
