WordPress to Wix Migration: A Technical Guide
A technical guide to migrating WordPress to Wix — what actually transfers, URL structure conflicts, WooCommerce limits, SEO preservation, and the manual work most guides skip.
Planning a migration?
Get a free 30-min call with our engineers. We'll review your setup and map out a custom migration plan — no obligation.
Schedule a free call- 1,500+ migrations completed
- Zero downtime guaranteed
- Transparent, fixed pricing
- Project success responsibility
- Post-migration support included
WordPress to Wix Migration: A Technical Guide
A WordPress to Wix migration moves your infrastructure from an open-source, self-hosted MySQL/PHP CMS to a closed, managed SaaS platform. You're trading absolute architectural control and server maintenance for visual velocity and zero-ops hosting.
The only content Wix can auto-import from WordPress is blog posts. Everything else — pages, custom fields, WooCommerce data, SEO metadata, plugin functionality — requires manual recreation, CSV import, or custom scripting through Wix's Velo API. If you're expecting a one-click migration that moves your entire WordPress site to Wix intact, it doesn't exist.
This guide covers exactly what transfers, what breaks, how to engineer a migration that preserves your content, SEO equity, and e-commerce data, and what to do when things go wrong mid-run.
What Wix Can and Cannot Import from WordPress
Understanding the import boundaries is the most important step before committing.
What transfers automatically
When you import posts from WordPress, the post text, images, and videos all get migrated, along with the original post dates and times and any alt text you entered. The categories you had in WordPress will also be migrated and linked to their corresponding posts.
That's it. Published blog posts, their inline media, publish dates, and categories.
What does NOT transfer
- Pages — There is no direct migration feature for pages. As is common when moving to closed visual builders (similar to migrating to Tilda), pages won't import. You will need to build any pages manually in Wix's editor.
- Comments — Wix Blog has its own comment system. WordPress comments do not carry over.
- Custom fields / post meta — WordPress's
wp_postmetatable has no equivalent in the Wix blog import. - Shortcodes — Any
[shortcode]content renders as raw text on Wix. - Custom post types — Wix's importer only reads standard
postobjects. - Tags — Categories transfer, but tags do not.
- Users and roles — WordPress user accounts don't transfer. Wix has its own member system.
- Plugin functionality — Contact forms, sliders, booking systems, and any plugin-dependent feature must be replicated using Wix Apps or Velo.
- Theme and design — Your WordPress theme does not export. You rebuild the design from scratch.
- Manually inserted HTML/CSS — Inline code blocks do not transfer.
- PDFs and attached documents — The blog importer explicitly skips these.
- Drafts and scheduled posts — Only published posts import.
- Author names — WordPress author attribution is not preserved by Wix's importer.
- WooCommerce data — Products, orders, and customers require a separate migration path (covered below).
- Multilingual content — WordPress sites using WPML or Polylang have no automated migration path to Wix Multilingual. Each language version must be recreated manually.
Key constraint: Wix's WordPress blog import reads your site's REST API at /wp-json/wp/v2/posts. If your WordPress site has REST API access disabled (via plugin or server config), the import will fail silently. Verify access by navigating to https://yoursite.com/wp-json/wp/v2/posts before starting.
How the Wix Blog Import Actually Works
Wix's built-in importer doesn't use the WXR (WordPress eXtended RSS) XML file. You can try to access your site JSON by adding /wp-json/wp/v2/posts to the end of your WordPress site's URL (e.g. https://examples.com/wp-json/wp/v2/posts).
The importer pulls content directly from your live WordPress REST API endpoint. This has practical implications:
- Your WordPress site must remain live and publicly accessible during the import.
- Password-protected posts won't import. To migrate these posts, simply remove the password before you start the import process.
- Security plugins can block the import. Wordfence, iThemes Security, and similar plugins sometimes disable or restrict
/wp-json/. Check and whitelist before starting. - Domain transfers break the import. If your domain is being transferred to another host you cannot begin the import process. You'll need to either cancel the domain transfer or wait until it finishes.
Import limits
| Constraint | Limit |
|---|---|
| Posts per import batch | 5,000 |
| Total blog posts on Wix | 100,000 |
| Additional batches | Via XML upload |
| Formatting preservation | Partial — check posts after import |
| Custom HTML/CSS in posts | Does not transfer |
Running the import
- In your Wix dashboard, navigate to Blog → Blog Posts.
- Click Import Posts and select WordPress.
- Enter your WordPress site URL.
- Wix reads
/wp-json/wp/v2/postsand begins pulling content. - Review the imported posts. Some, but possibly not all, of your formatting migrates with the import. Check your posts after the process is completed and make any necessary design changes.
For a standard blog with simple posts and categories, the native importer may be all you need. For anything more complex, read on.
The Architectural Mismatch: Relational vs. Flat Collections
WordPress relies on a relational MySQL database. A single "Page" or "Product" is rarely stored in one place. Core content sits in wp_posts. Custom fields, SEO metadata, and pricing live in wp_postmeta (an EAV-style table). Categories and tags are mapped across wp_terms, wp_term_taxonomy, and wp_term_relationships. Authors sit in wp_users.
Wix CMS is a NoSQL-style document database. Data is stored in flat Collections. Wix supports Reference fields to link Collections (e.g., linking a "Posts" collection to an "Authors" collection), but the structure is far more rigid than WordPress's open-ended meta tables.
Data Model Translation
| WordPress Concept | Wix Equivalent | Migration Action |
|---|---|---|
| Custom Post Type (CPT) | Wix CMS Collection | Create a new Collection with a strictly typed schema |
| Advanced Custom Fields (ACF) | Collection Fields | Map each ACF field to a specific Wix field type (see ACF mapping table below) |
| Categories / Tags | Reference Collections | Create a "Categories" Collection, use a Reference field to link |
Featured Image (_thumbnail_id) |
Image Field | Upload to Wix Media Manager, return the wix:image:// URI |
Shortcodes ([gallery]) |
Native Wix Widgets | Parse shortcode from HTML, replace with Wix component |
Don't map WordPress tables to Wix one-for-one. Whether you are moving from relational to flat, or from a flat CMS to WordPress, you must map business objects to their new destinations:
- Blog posts → Wix Blog
- Unique marketing pages → Static Wix pages (Wix caps static pages at 100, with 298 pages total)
- Repeatable content (case studies, team profiles, resources) → Wix CMS collections + dynamic pages
- Products → Wix Stores
- CRM records → Wix Contacts
- Login users → Wix Members
This step matters because Wix recommends dynamic pages for scale, and CMS imports can handle files up to 1 GB with up to 50,000 items and 1,000 fields per collection. (support.wix.com)
Sites with more than 100 static pages require a rearchitecting decision. If your WordPress site has 200+ individual pages, you cannot migrate them all as static Wix pages — you hit the 100-page hard cap. The options are: (1) convert repeatable page types (service pages, location pages, product detail pages) into CMS Collections backed by dynamic pages, (2) consolidate thin pages, or (3) accept that some pages will be cut. This is a content architecture decision that must happen before any technical migration work begins.
ACF Field Type Mapping to Wix
ACF has more than 30 field types. Many have no direct Wix equivalent and require a workaround. The following table covers the most common:
| ACF Field Type | Wix Field Type | Migration Notes |
|---|---|---|
| Text | Text | Direct mapping |
| Textarea | Long text | Direct mapping |
| Number | Number | Direct mapping |
| True/False | Boolean | Direct mapping |
| Select / Radio Button | Text or Tags | Store selected value as string; no native enum type in Wix |
| Checkbox | Tags (multi-value) | Store as array of strings |
| Image | Image | Upload to Wix Media Manager; store wix:image:// URI |
| File (PDF, doc) | Document | Upload to Wix Media Manager; store document URL |
| Gallery | Array of Images | Wix has no native gallery field; store as JSON array or use multiple Image fields |
| Link (URL) | URL | Direct mapping |
| Date Picker | Date | Map to Wix Date field; verify timezone handling |
| Post Object / Relationship | Reference | Requires migrating the referenced collection first; capture Wix item IDs |
| Repeater | No native equivalent | Store as JSON in a Long Text field, or restructure into a linked Collection |
| Flexible Content | No native equivalent | Must be broken into separate Collections or flattened |
| Clone | No native equivalent | Expand cloned fields into explicit individual fields |
| Group | No native equivalent | Flatten group fields into top-level Collection fields |
| Color Picker | Text | Store hex value as string |
| Google Map | Address | Wix Address field stores structured location data; lat/long must be mapped explicitly |
| User | Reference to Members Collection | Requires Members collection to be migrated first |
| Tab | Not applicable | Tabs are UI-only in ACF; no data to migrate |
Key problem fields: Repeater, Flexible Content, and Clone field types are the most common causes of migration failures. There is no Wix Collection structure that natively represents a variable-length, mixed-type repeater. The practical options are: (1) store serialized JSON in a Long Text field and render it with Velo, (2) create a separate linked Collection where each repeater row becomes a Collection item, or (3) flatten the data if the repeater always has a fixed number of rows.
Extracting Data from WordPress
For complex sites, the built-in Wix importer is not enough. You need a structured extraction pipeline.
Using the WordPress REST API
The WordPress REST API (/wp-json/wp/v2/) is the preferred extraction method because it naturally serializes content as JSON and standardizes the output. By default, it returns 10 items per request and caps at 100 via the ?per_page=100 parameter.
# Extract a Custom Post Type "Case Studies" including embedded data
curl -X GET "https://example.com/wp-json/wp/v2/case_studies?per_page=100&page=1&_embed"The _embed parameter is critical. It forces WordPress to include the full payload for the author, terms (categories), and the featured image URL. Without _embed, you only get the integer ID of the featured image, forcing a secondary API call for every post.
For programmatic extraction across all content types:
import requests
import json
import time
base_url = "https://yoursite.com/wp-json/wp/v2"
endpoints = {
"posts": f"{base_url}/posts",
"pages": f"{base_url}/pages",
"categories": f"{base_url}/categories",
"tags": f"{base_url}/tags",
"media": f"{base_url}/media",
}
def fetch_all(url, per_page=100, auth=None):
"""
Fetches all paginated items from a WordPress REST API endpoint.
Args:
url: WordPress REST API endpoint URL
per_page: Items per page (max 100)
auth: Optional tuple of (username, application_password) for protected sites
Returns:
List of all items, or empty list if endpoint is inaccessible
"""
items = []
page = 1
# First check if the endpoint is accessible at all
try:
test_resp = requests.get(url, params={"per_page": 1}, auth=auth, timeout=30)
except requests.exceptions.ConnectionError:
print(f"ERROR: Cannot connect to {url}. Check site URL and network access.")
return []
if test_resp.status_code == 401:
print(f"ERROR: {url} requires authentication. Provide --auth credentials.")
return []
if test_resp.status_code == 403:
print(f"ERROR: {url} is forbidden. REST API may be disabled by a security plugin.")
return []
if test_resp.status_code == 404:
print(f"WARNING: {url} not found. Custom post type may not be registered with show_in_rest=True.")
return []
while True:
try:
resp = requests.get(
url,
params={"per_page": per_page, "page": page, "_embed": 1},
auth=auth,
timeout=60 # Some sites with _embed are slow
)
except requests.exceptions.Timeout:
print(f"TIMEOUT on page {page} of {url}. If this recurs, use WP-CLI instead.")
break
except requests.exceptions.ConnectionError as e:
print(f"CONNECTION ERROR on page {page}: {e}")
break
# WordPress returns 400 when you request a page beyond the total
if resp.status_code == 400:
break
if resp.status_code != 200:
print(f"HTTP {resp.status_code} on page {page} of {url}. Stopping.")
break
batch = resp.json()
if not batch:
break
items.extend(batch)
print(f" Fetched {len(items)} items from {url}...")
# If we got fewer items than requested, we're on the last page
if len(batch) < per_page:
break
page += 1
time.sleep(0.5) # Avoid hammering the source server
return items
for name, url in endpoints.items():
print(f"Extracting {name}...")
data = fetch_all(url)
with open(f"{name}.json", "w") as f:
json.dump(data, f, indent=2)
print(f"Exported {len(data)} {name}")Custom fields require extra work. The REST API doesn't expose wp_postmeta fields by default. If you use ACF (Advanced Custom Fields), install the ACF to REST API plugin or register custom fields via register_rest_field() to include them in the API output.
Failure mode: Large WordPress sites with heavy plugins often experience REST API timeouts when _embed is used. If your server returns 502 Bad Gateway errors during extraction, bypass the HTTP layer and use WP-CLI to export directly from the server. The _embed parameter on a post with a complex featured image chain can take 2–5 seconds per response on shared hosting — multiply by 10,000 posts and that's a 6–14 hour extraction window at 100 items/page.
Using WP-CLI
WP-CLI gives you granular control and avoids HTTP overhead entirely:
# Export only published posts
wp export --post_type=post --post_status=publish --dir=./export/
# Export pages separately
wp export --post_type=page --post_status=publish --dir=./export/
# Export a specific date range
wp export --post_type=post --start_date=2023-01-01 --end_date=2024-12-31 --dir=./export/
# Dump directly to JSON
wp post list --post_type=case_studies --format=json > case_studies.json
# Export post meta for a custom post type
wp post list --post_type=case_studies --fields=ID --format=ids | xargs -I{} wp post meta list {} --format=json >> case_study_meta.jsonCustom post types only appear in the REST API if they were registered with show_in_rest => true. If they weren't, WP-CLI or direct database queries are your only extraction options.
Media deduplication before upload
WordPress generates multiple resized copies of every uploaded image: image.jpg, image-300x200.jpg, image-768x512.jpg, image-1024x683.jpg. Your wp_postmeta table stores the original image ID, but your HTML content references whichever resize WordPress selected at render time.
Before uploading to Wix:
- Extract originals only. Query
wp_posts WHERE post_type = 'attachment'— theguidcolumn points to the original upload, not a resize. Upload originals to Wix. - Build a URL map. Create a dictionary of
{wordpress_url: wix_url}keyed on every known resize URL for each original. When you rewrite inline imagesrcattributes, all resize variants map to the same Wix image. - Check for duplicates by filename. WordPress allows the same filename to be uploaded multiple times (appended with
-1,-2). Deduplicate by MD5 hash of the file content, not by name.
Skipping this step means uploading 3–6x more images than necessary and leaves broken src references for resize variants not covered by your map.
Transforming Content: Gutenberg, Shortcodes, and HTML Cleanup
WordPress stores post content as a single HTML string in the post_content column. Sites built in the last five years are littered with Gutenberg block comments:
<!-- wp:paragraph {"align":"center"} -->
<p class="has-text-align-center">This is a paragraph.</p>
<!-- /wp:paragraph -->Wix's Rich Text field accepts standard HTML but doesn't understand Gutenberg comments. While Wix usually ignores HTML comments during rendering, they inflate database size and can cause unexpected behavior in Wix's visual editor.
Much like the block-to-HTML conversion required when migrating from Notion to Webflow, your transformation script must:
- Strip Gutenberg block comments — regex-remove all
<!-- wp:... -->and<!-- /wp:... -->patterns. - Handle shortcodes — search your
wp_poststable for[to identify usage. For simple embeds (YouTube, Vimeo), convert to standard HTML<iframe>. For complex plugins (forms, calculators), strip the shortcode and flag it for manual reconstruction using Wix Forms or Velo. - Convert WordPress-specific relative links — map them to the new Wix routing structure or convert to absolute URLs temporarily.
Shortcodes are application instructions, not portable content. If the source post body is full of [gallery], [contact-form-7], or page builder macros, each one needs identification and a Wix-native replacement.
The Image and Media Re-hosting Pipeline
This is where most DIY migrations fail. You cannot pass a WordPress image URL (https://example.com/wp-content/uploads/2023/10/image.jpg) into a Wix image field and expect it to persist. Wix requires images hosted in its own ecosystem. If you use external URLs, every image breaks the moment you decommission the WordPress server.
Every image — featured images, gallery images, and inline images within the post body — must be uploaded to the Wix Media Manager.
Uploading via Wix REST API
The Wix Media API uses a two-step upload process:
- Request an upload URL from Wix.
- POST the binary file to that URL.
// Step 1: Get Upload URL (Requires Wix API Key)
const response = await fetch('https://www.wixapis.com/media/v1/files/upload-url', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_WIX_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({ mimeType: 'image/jpeg', fileName: 'migrated-image.jpg' })
});
const { uploadUrl } = await response.json();
// Step 2: Upload the actual file
// (Assuming you already downloaded it from WordPress)Once uploaded, Wix returns a proprietary URI format: wix:image://v1/hash_filename.jpg/origin_filename.jpg#originWidth=1920&originHeight=1080.
Map this exact URI to your Wix Collection's image field.
For inline images embedded inside HTML content, the process differs: parse the HTML, extract each src attribute, upload the image to Wix, get the new public Wix URL (the static.wixstatic.com URL, not the wix:image:// URI), and rewrite the src in the HTML before loading it into Wix.
Download originals from wp-content/uploads/ as a backup regardless. Even though inline images transfer with the blog importer, if you later cancel WordPress hosting, any externally-referenced images break.
Loading Data into Wix CMS Collections
With your JSON cleaned, HTML sanitized, and images re-hosted, push the data into Wix.
Two primary methods:
- Wix REST API (Server-to-Server): Use the
/wix-data/v2/itemsendpoint to bulk insert items into your target Collection. - Velo by Wix (wix-data): Write a backend
.jswweb module in Wix, expose it as an HTTP function, and POST your data to it. The script useswixData.insert()to write to the database.
The REST API is faster for bulk operations. Wix enforces a rate limit of 200 requests per minute for the Data API (dev.wix.com). If you're migrating 20,000 records, your script must include a rate-limiting queue (roughly 3 items per second) to avoid HTTP 429 errors. At that rate, inserting 20,000 records takes approximately 1 hour 45 minutes of sustained API calls, not counting retry logic for failed inserts.
Handling Reference Fields
If you have a "Blog Posts" collection and an "Authors" collection, migrate Authors first. Capture the generated Wix IDs for each Author. Then when inserting Blog Posts, map the WordPress Author ID to the new Wix Author ID in the payload.
Platform limits for CMS imports
| Constraint | Limit |
|---|---|
| Max items per CMS collection import | 50,000 |
| Max import file size | 1 GB |
| Max fields per collection | 1,000 |
| Max collection item size | 500 KB |
| Velo query max per request | 1,000 items |
| Wix Data API rate limit | 200 requests/minute |
Leaving existing collection fields unmapped during import erases their values. Double-check your field mapping before running any CMS import. (support.wix.com)
Migrating WooCommerce Data to Wix Stores
If your WordPress site runs WooCommerce, the blog import handles none of your e-commerce data. Products, orders, customers, and coupons require a completely separate migration.
Wix Stores platform limits
| Wix Stores Constraint | Limit |
|---|---|
| Max products | 50,000 |
| Product images per product | 19 |
| Product variants per product | 1,000 |
| Product options per product | 6 |
| Choices per option | 100 |
| Velo bulk operation payload | 4 MB |
| Stores/Product query limit | 100 items per query |
If your WooCommerce catalog has products with more than 6 option types, more than 1,000 variant combinations, or more than 19 images, you need to restructure before migration. If a product has options but no variants, and the total combinations exceed 1,000, variants will not be generated automatically — only the options will be imported.
Migration paths
Option 1: CSV export/import
WooCommerce exports products as CSV via WooCommerce → Products → Export. Wix Stores accepts CSV product imports. The schemas don't match, so you need a transformation step:
- WooCommerce uses
regular_priceandsale_price; Wix expects different column names. - WooCommerce variation rows reference a parent product via
parent_id; Wix expects a flat structure with option columns. - WooCommerce image fields contain full URLs; Wix expects its specific format.
Watch currency during catalog migration. Wix's CSV import converts imported prices to the currency already set in the Wix store. If your source catalog is in EUR and your Wix store is set to USD, a naive import produces numerically identical but economically wrong prices. (support.wix.com)
Option 2: Cart2Cart or LitExtension
Third-party services handle the field mapping automatically. Imports are limited to 1,000 products and 1,000 orders per migration run. Run a demo migration first to validate data integrity.
Option 3: Wix Velo Data API
For teams with developer resources, Wix's Velo platform offers wix-data APIs for programmatic import. This gives you the most control but requires custom JavaScript running in Wix's backend environment. Be aware: aggregations can only be used on collections you have created. They cannot be used on Wix App Collections. Wix Stores products live in a Wix App Collection, which limits what you can do programmatically.
What you lose moving from WooCommerce to Wix Stores
Specifically:
- Variable products with 7+ option types must be simplified to 6 or fewer.
- Subscription products have no native equivalent (Wix Pricing Plans is a separate module with different checkout behavior).
- Wholesale pricing / role-based pricing is not natively supported.
- Custom checkout flows built with WooCommerce hooks don't translate.
- WooCommerce's coupon system supports percentage off, fixed cart, fixed product, buy X get Y, and usage limits per user. Wix Stores supports fewer coupon types natively.
- Advanced inventory tracking (stock at location level, backorder rules per SKU) is not replicated.
Order history
Wix's Orders API supports creating orders from external systems, and a companion payments endpoint records payment history after the fact. But order creation can reduce inventory automatically depending on settings, and the Add Payments endpoint records payments only — it does not charge cards. (dev.wix.com)
If you recreate old WooCommerce orders in Wix without accounting for inventory side effects, you can accidentally reduce live stock during migration. Test imported orders against a staging catalog or an explicit inventory strategy before touching production.
Users, Members, and Contacts
User passwords cannot be migrated. WordPress uses phpass or bcrypt; Wix manages its own identity layer with no mechanism to import password hashes. Every user who needs login access must set a new password on Wix.
The documented migration flow is: create the Wix Member via the Members API, then trigger a set-password email via the sendSetPasswordEmail endpoint. There is no bulk password-reset UI in the Wix dashboard — you must either trigger emails programmatically per member or direct users to the "Forgot Password" flow after launch. Bulk member creation requests should be spaced at least 1 second apart to stay within rate limits. (dev.wix.com)
Contacts are separate from Members in Wix. Wix Contacts can import CSV files with fewer than 20,000 contacts, up to 100 custom fields, and up to 200 columns, and each row must contain an email address or phone number. That handles CRM continuity but doesn't create login-capable site members. (support.wix.com)
Create actual Wix Members only for people who need login access. Everyone else can remain contacts only.
Multilingual Sites (WPML / Polylang)
This is one of the most underserved migration scenarios. WordPress multilingual sites built with WPML or Polylang store each language version as a separate post, linked by a translation group ID in wp_postmeta (_wpml_trid for WPML).
Wix Multilingual works differently: it stores the primary language version as the canonical content and translation overrides are attached at the field level within the same item. There is no automated path from WPML's post-duplication model to Wix Multilingual's overlay model.
The manual process:
- Export each language version from WPML using the REST API with the
?lang=frparameter (for French, etc.). - Migrate the primary language first to Wix as the base content.
- In Wix Multilingual, manually add each secondary language and enter translated content field by field.
For a site with 500 posts in 3 languages, that's 1,000 manual translation entries after the base content is migrated. There is no CSV import path for Wix Multilingual translations. Factor this into your effort estimate before committing to migration.
SEO, URLs, and 301 Redirects
This is where most migrations silently destroy SEO equity.
The URL structure problem
WordPress gives you full control over permalink structures. Common patterns:
example.com/post-slug/example.com/category/post-slug/example.com/2024/01/post-slug/
Wix blog posts get a mandatory prefix. You cannot remove the default /post/ or /blog/ prefix in blog post URLs. A WordPress post at example.com/my-great-article/ becomes example.com/post/my-great-article on Wix. This means every blog post URL changes, and every inbound link and search engine index entry points to a dead URL unless you set up redirects.
For CMS-backed dynamic pages, Wix uses a /{prefix}/{field} structure. A "Case Studies" collection might route to /case-studies/{slug}.
Setting up 301 redirects
You can manually create 301 redirects for your pages using the URL Redirect Manager in your site's SEO & GEO dashboard. You can also create group redirects for groups of pages with the same path in their URLs. Group redirects let you map a pattern like /* → /post/* without creating hundreds of individual rules.
The redirect workflow:
- Export all WordPress URLs. Use Screaming Frog, WP All Export, or a direct SQL query:
SELECT post_name FROM wp_posts WHERE post_status = 'publish' AND post_type = 'post'. - Map old paths to new paths. WordPress
/my-post-slug/→ Wix/post/my-post-slug. - Upload redirects to Wix's URL Redirect Manager at SEO & GEO → Tools and settings. Wix's CSV import accepts up to 500 redirects per file (support.wix.com), so larger sites need batched uploads. Use regex patterns in the Redirect Manager to group structural changes when possible.
- Verify with a crawler. After DNS cutover, crawl old URLs and confirm 301 responses.
Google states that permanent 301 redirects do not cause PageRank loss. (developers.google.com)
Preserve slug consistency. When Wix imports your posts, it usually preserves the original slug. Verify this post-import. If slugs match, your redirect rules are straightforward pattern-based remaps. If Wix alters slugs (truncation, character replacement), you need per-URL redirects.
SEO preservation checklist
- Export all meta titles and descriptions from Yoast, Rank Math, or your SEO plugin before migration. Wix's importer ignores these entirely. Export via your plugin's export feature or a database query against
wp_postmetawheremeta_key=_yoast_wpseo_titleor_yoast_wpseo_metadesc. - Set up 301 redirects for every URL that changes. Use group redirects where possible.
- Match slugs exactly. Verify post-import that Wix preserved your original URL slugs.
- Verify the new sitemap. Wix automatically updates sitemaps and canonical tags. Still check
yoursite.com/sitemap.xmlafter going live. - Submit the new sitemap to Google Search Console to speed up re-indexing.
- Re-enter meta titles and descriptions on each Wix page and post manually. Tedious but non-negotiable for SEO continuity.
- Monitor Search Console for crawl errors for at least 30 days post-migration. Expect a temporary ranking dip — it typically recovers within 2–6 weeks if redirects are clean.
DNS considerations
Choose your connection method deliberately. With pointing, your DNS stays with the current host — often safer when the source setup includes business email, verification records, or other DNS-dependent services. With name servers, Wix hosts DNS. Wix's documentation notes that some records may need to be re-added, propagation can take up to 48 hours, and Wix does not support DNSSEC or DNS proxies like Cloudflare during name server connection. (support.wix.com)
If the migration changes the domain or subdomain, use Google's Change of Address tool after the move and redirects are live. Do not use it for path-only URL changes — those should rely on redirects alone. (support.google.com)
Staging and Rollback Strategy
Wix does not have a true staging environment in the WordPress sense (a separate database clone on a separate URL). What it does have:
- Site History — Wix saves versions of your site that you can restore via Dashboard → History. This covers design and content changes but does not independently snapshot CMS Collection data.
- Preview mode — You can preview an unpublished site before DNS cutover. Work on the Wix site in full before pointing your domain.
The recommended pre-cutover sequence:
- Complete the full migration on Wix before touching DNS. Verify all content, redirects, product catalog, and member flows against the Wix preview URL (
username.wixsite.com/sitename). - Keep WordPress live and read-only for 30 days post-cutover. Do not decommission the server immediately.
- After DNS propagates, crawl the Wix live URL with Screaming Frog to confirm all redirects return 301 (not 200 or 404).
Rollback procedure if migration fails mid-run:
- For CMS Collection imports: Wix allows you to delete all items in a Collection. If a bulk insert fails or corrupts data, clear the Collection entirely and re-run from the last known-good checkpoint.
- For blog post imports: individually delete imported posts if formatting or content is wrong. There is no bulk delete in the Wix Blog interface — use the Wix Data API or Velo to delete records programmatically.
- For Wix Stores products: CSV import creates new product records; it does not modify existing ones. If a product import run produces bad data, you can delete the batch by filtering products created within the migration time window.
- For DNS: if the Wix site is critically broken, re-point DNS to the WordPress server (TTL-dependent; set TTL to 300 seconds at least 48 hours before cutover to minimize rollback time).
If you're running a Velo-based data insert and it fails at record 8,000 of 20,000: your insert script should log each successfully inserted Wix item ID to a local file before moving to the next. On failure, reload the ID log and skip already-inserted records. Without this checkpoint pattern, a mid-run failure forces a full Collection clear and full re-run.
What Cannot Be Migrated
Be honest with your stakeholders about what gets left behind:
- PHP Logic and Plugins: Yoast, WooCommerce, Gravity Forms, and custom
functions.phpcode don't migrate. Rebuild using Wix SEO tools, Wix Stores, Wix Forms, or Velo JavaScript. - Complex Hierarchical Taxonomies: WordPress supports infinitely nested categories (Parent > Child > Grandchild). Wix Collections are flat. You can simulate hierarchy with multiple Reference fields, but it requires custom Velo coding for hierarchical navigation.
- Server-side Logic: WordPress hooks, custom REST endpoints, and WP Cron jobs have no direct equivalent. Velo is capable but architecturally different. Expect a rewrite, not a port.
- User Passwords: As covered above — users must reset passwords on first login.
- Multilingual translation overlays: No automated path from WPML/Polylang to Wix Multilingual.
When NOT to Migrate to Wix
- If you rely on custom post types (events, portfolios, testimonials stored as CPTs) and can't afford to flatten them into CMS collections, Wix will constrain your content architecture.
- If you have a complex WooCommerce store with 1,000+ products, complex variations, subscriptions, or B2B pricing, Wix Stores will limit your operations.
- If SEO is your primary traffic source and you have thousands of indexed URLs, the forced
/post/prefix and manual meta re-entry create real risk. A migration to another platform that allows matching URL structures (Webflow, Squarespace, a headless CMS) would be safer. - If you depend on server-side logic — WordPress hooks, custom REST endpoints, WP Cron jobs — Velo requires a complete rewrite of that logic.
- If you have more than 100 static pages. Beyond that, you must rearchitect content into CMS Collections, which adds scope.
- If your site is multilingual with 3+ languages. The manual effort for Wix Multilingual is proportional to (languages × posts) with no automation available.
Wix excels for teams that want to exit the WordPress maintenance burden (hosting, updates, security patching, plugin conflicts) in exchange for a managed, design-first platform. If that trade-off aligns with your priorities, the migration is worth the effort.
Estimated Effort by Site Complexity
The following estimates assume one technically proficient person working full days. Specific task breakdowns are listed to make the numbers falsifiable.
| Site Profile | Estimated Effort | Primary Time Sinks |
|---|---|---|
| <50 posts, <10 pages, no e-commerce | 1–2 days | Blog import + spot-check, redirect setup, meta re-entry |
| 100–500 posts, 20–50 pages, basic media | 3–5 days | Image upload pipeline, page rebuild (20–50 pages @ 30–60 min each), redirect CSV |
| 500+ posts, 50+ pages, WooCommerce (500 products), custom fields | 1–3 weeks | ACF extraction + transformation, WooCommerce schema mapping, member migration, redirect batching |
| 1,000+ posts, complex e-commerce, member areas, multi-author | 3–6 weeks | Full ETL pipeline development, Velo data API scripting, variant restructuring, multilingual (if applicable), staged rollout |
The biggest time sinks are manual page recreation (no automation available) and SEO metadata re-entry (one Wix page at a time, no bulk meta import). Neither can be automated through Wix's native tools. The image upload pipeline, by contrast, can be fully automated using the Wix Media API.
Pre-Cutover Checklist
Before pointing DNS to Wix, verify:
- Every indexable old URL is mapped to a final Wix URL or an intentional 404/410 outcome
- Blog imports spot-checked for category, media, and formatting drift (check first 20 posts manually)
- CMS collections validated for field types and dynamic page slugs
- ACF Repeater / Flexible Content fields accounted for (JSON storage or linked Collection)
- Catalog prices and variants verified in the store currency configured in Wix
- Orders and payments tested in a non-destructive migration run first
- Member creation and password-set emails rehearsed before launch day
- Redirect CSV uploaded and tested against 10 sample old URLs
- DNS TTL lowered to 300 seconds at least 48 hours before cutover
- WordPress server confirmed to remain live for 30 days post-cutover
- Screaming Frog crawl scheduled for day 1 post-cutover to catch broken redirects
- Google Search Console sitemap submission queued for immediately after DNS propagates
For related migration strategies, see our guides on migrating images, attachments, and embeds without broken links and our Magento to Wix migration guide covering the architectural mismatches between e-commerce platforms and Wix.
Frequently Asked Questions
- Can I migrate my entire WordPress site to Wix automatically?
- No. Wix's built-in importer only transfers published blog posts (text, images, dates, categories) via your WordPress REST API. Pages, custom post types, comments, SEO metadata, custom fields, and WooCommerce data must be migrated manually or through separate tools.
- Will my WordPress URLs stay the same on Wix?
- No. Wix forces a /post/ or /blog/ prefix on all blog post URLs, which cannot be removed. A WordPress post at example.com/my-article/ becomes example.com/post/my-article on Wix. You must set up 301 redirects for every changed URL to preserve SEO equity.
- How do I move WordPress images to Wix without them breaking?
- You cannot simply copy image URLs. You must download images from WordPress, upload them to the Wix Media Manager via the Wix REST API, and replace old URLs in your content with the new Wix-generated URIs. External image URLs will break when the WordPress server is decommissioned.
- Can I move WooCommerce products to Wix Stores?
- Yes, but it requires a separate migration via CSV export/import or third-party tools like Cart2Cart. Be aware of Wix Stores limits: max 6 product options, 1,000 variants per product, and 19 images per product. Complex WooCommerce catalogs may need restructuring.
- Does Wix import WordPress SEO meta titles and descriptions?
- No. Wix's WordPress importer ignores all SEO plugin data (Yoast, Rank Math, etc.). You must export meta titles and descriptions separately and re-enter them manually on each Wix page and post.