A migration you can run twice, check afterwards, and leave running while you do something else.
Three rules, and they are the reason to choose this over the alternatives.
Nobody is emailed. While a migration is running every WooCommerce email is switched off — the new-order one, the completed-order one, and the "set your password" one a customer import would otherwise send several thousand of. Importing three years of orders and emailing three years of customers their receipt again is the single most catastrophic thing a plugin in this category can do: it cannot be undone, it reaches people who no longer shop there, and it is how a shop's sending domain ends up in a blocklist on the day it moves platform. Stock is left alone for the same reason — those orders were fulfilled in the old shop, and the counts here describe what is on the shelf today.
Running the same file twice changes nothing. Every record remembers where it came from, so the second run updates what the first one made rather than making a second copy of the catalogue. Every merchant runs a migration twice, because the first one is always a rehearsal; the plugins that key on SKU or on title double a catalogue, and the merchant deletes four thousand products by hand.
It resumes. A shop with twenty thousand products cannot be imported inside one HTTP request. The connectors here try, and time out around row three thousand, leaving a half-migrated store and no way to tell which half. This one holds a byte offset into the file and writes it back *before* the batch is imported, so a run that dies costs one batch and picks up where it stopped.
What comes across
- Products — name, description, SKU, price, sale price, stock, categories
- Customers — with their billing details, as real WooCommerce accounts
- Orders — with their own totals, tax, shipping, currency and date
- Coupons — code, type and amount
From a Shopify CSV export or a WooCommerce CSV export, out of the box. Another format is one array through the gmsm_sources filter, and it gets the reader, the resume and the idempotency rule for nothing.
Also
* An imported order keeps its own money. Totals, tax and shipping are written exactly as exported rather than recalculated from today's prices and today's tax table — so last year's revenue does not change when you edit a product. The line subtotal is written too, or WooCommerce reports every imported line as fully discounted. * A report you can check. Created plus updated plus skipped adds up to every row in the file; when it does, nothing was lost. Skipped rows are counted by reason, in your terms — "no name of its own, usually a variant line under the product above it" — so you know what to fix rather than that something broke. * A Run now button, because WP-Cron is asleep on most shared hosts and a progress bar that has not moved in five minutes tells you nothing on its own. * Imported products are drafts by default. Finding four thousand products live at the wrong prices is a worse afternoon than pressing publish. * An order already imported is left exactly as it is on a second run — it may have been edited or refunded since, and a re-run must not undo that. That is the opposite call from a product, and deliberately so. * Money is read the way exports write it, so a European file's 1.250,00 is 1250 rather than 1. * The upload is kept behind an index.html and a .htaccess under a random name, and deleted when you finish — it is your whole customer list.
Free edition
A free edition is on wordpress.org: products and customers, with all three rules. Orders and coupons are here. The source mark is shared, so a shop that imported its catalogue with the free edition and then brought its orders across with this one does not end up with two of everything.
Every license includes
- One year of updates and priority support, delivered straight to your WordPress dashboard.
- Use on 1, 5 or 25 sites depending on your license — local, staging and development sites are always free.
- 30-day money-back guarantee — full refund, no questions asked.
- Keeps working after expiry — if you choose not to renew, the plugin keeps running exactly as installed; it simply stops receiving updates and support until you do.
Requires WordPress 6.4+ · PHP 7.4+ · tested up to WordPress 7.0. Works with the classic and block checkout alike.

Amy (verified owner) –
Finally something that doesn’t try to upsell me on every screen. Store Migration is one of about four plugins I wouldn’t run a shop without. Exactly what I hoped for.
Sarah F. (verified owner) –
Set it up, got confused, read the docs, fine ever since. Good, not perfect.
Gary Rowe (verified owner) –
A good plugin that could use one more setting. Store Migration does the basics without complaint. No drama, which is what I wanted.
Thomas (verified owner) –
It does not try to be a page builder as well. Good. Store Migration does what a person would expect it to do. Recommended.
Peter L. (verified owner) –
Emailed on a Sunday, heard back Monday morning. Fair enough.