← All insights

Migrating WordPress to Shopify: the redirect-map you need before launch

The single biggest cause of organic traffic loss after a WordPress-to-Shopify migration is a sloppy redirect map. Here is the process we run.

Last quarter we migrated a 1,400-product WooCommerce store to Shopify Plus. The client had nine years of WordPress URLs in Google’s index — product pages, category pages, eight years of blog posts, customer guides, every comment thread, every author archive. The fear at the start of the project was the same fear every WooCommerce-to-Shopify migration starts with. What happens to the organic traffic on day one?

The answer, when the migration is done well, is nothing. The client’s organic sessions in the four weeks after launch matched the four weeks before within a margin of three percent. They did not lose rankings. They did not lose ad-tracked revenue. The site moved, and the traffic moved with it.

The only reason that worked is the redirect map. It is the most boring deliverable of any migration and the one that most often gets a fifteen-minute treatment in the timeline. We spend two to four days on it for a site this size, and that is where the time has to go.

The shape of the URL structures

WordPress and Shopify have fundamentally different URL conventions. The most common patterns we see, and the Shopify destinations they map to:

  • WordPress product URL: /product/slug/ → Shopify: /products/slug
  • WordPress product category: /product-category/slug/ → Shopify collection: /collections/slug
  • WordPress tag: /product-tag/slug/ → Shopify collection or tag filter
  • WordPress blog post: /2018/03/19/slug/ → Shopify blog: /blogs/news/slug
  • WordPress page: /about-us/ → Shopify page: /pages/about-us
  • WordPress author archive: /author/jane/ → typically nowhere meaningful

None of these are automatic. Shopify has no idea that your old store called the news section /blog and the new store calls it /blogs/news. Without a redirect map, every one of those URLs returns a 404 the moment you flip DNS.

Exporting the source-of-truth list

Step one is to know what URLs exist. We pull from three sources in parallel.

The first is the WordPress database. A SELECT on wp_posts where post_status=’publish’ and post_type in (‘post’,’page’,’product’) gives every public URL the site can generate. We pair it with a function that runs get_permalink() through wp eval-file so we get the actual rendered URL, not the slug.

The second is Google Search Console. Export the last 12 months of pages with at least one impression. This catches URLs the database does not — old paginated archive pages, attachment pages WordPress generated when an image was uploaded, query-string variants Google has indexed.

The third is a crawl. We run Screaming Frog at depth-15 against the production site, no JavaScript rendering, with 200-only filtering. The crawl catches links from internal navigation that have drifted from the canonical URL — trailing slashes, www variants, mixed-case slugs.

The three lists get deduplicated into a single CSV. On a 1,400-product site this list typically runs eight to twelve thousand URLs.

Categorizing the rows

Each row in the master list gets a tag. We use seven tags:

  • product — direct one-to-one to a Shopify product URL
  • collection — old category or tag, mapping to a Shopify collection
  • blog — blog post, mapping to a Shopify blog article
  • page — static page, mapping to a Shopify page
  • archive — author archive, paginated category, date archive — usually 301 to the home page or a sensible parent collection
  • kill — attachment pages, login URLs, admin URLs, broken pages that shipped 404 already
  • review — anything the script could not classify; gets a human review

The script reads the wp_postmeta table for the old product SKU, looks up the corresponding Shopify product by SKU, and writes the new URL into the destination column. For collections we do the same with category slug to Shopify handle. The unmatched rows — typically less than 5 percent on a clean store — go into a Google Sheet for manual review.

The Shopify side

Shopify accepts a CSV upload of redirects through the URL Redirects admin or via the API. There is a per-shop limit — currently 100,000 redirects on Plus, 1,000 on standard plans — which is plenty for any project we have shipped.

One catch: Shopify’s redirect engine does not match query strings by default. URLs like ?utm_source=newsletter on the old WordPress side need to be normalized — either stripped before the redirect lookup or accounted for explicitly. We strip them in the redirect rules and let Shopify’s analytics handle the UTMs natively.

Another catch: Shopify redirects do not support regex. They are exact-match strings. If you have 4,000 dated blog post URLs you need to redirect, each one is a separate row in the redirect table. Plan the import accordingly.

The verification step nobody runs

The most common migration failure we audit is a redirect map that was generated and uploaded but never tested. The script ran, the CSV went up, the launch happened, and three months later organic traffic is down 30 percent because half the redirects pointed at 404s on the Shopify side.

We run a verification crawl against the staging Shopify store, with the redirect map active, the day before launch. The crawler hits every URL on the master list and confirms the HTTP status. A clean run should be 100 percent 301 → 200. If we see 301 → 404 chains, those rows go back into manual review.

We also test the canonical tags. A Shopify product page exists at /products/slug, but the same product can be accessed through /collections/some-collection/products/slug. Both should render with rel=canonical pointing to the bare /products/slug URL. If the canonical is wrong on one of those, Google will index both and split the link equity.

The first 48 hours after launch

Day-one monitoring is non-negotiable. We watch the Shopify access logs, Search Console’s coverage report, and a custom URL-status crawl every six hours for the first 48 hours.

The most common day-one issue we have caught: a missed redirect for a high-volume URL we did not notice in the master list because it had a tracking parameter we did not normalize. The fix is usually a single redirect row added in the admin.

The second most common: Shopify’s default rate limiting on the redirect import API. If you push 8,000 redirects through the API too fast you get throttled and half the import silently drops. Run the import in batches of 500 with a delay between batches, or use the CSV upload which does not have the same limit.

The deliverable

When the migration ships, the client gets the master CSV, the verification crawl results, and a runbook for what to do if Search Console reports a coverage issue in the first three months. The runbook has cost us almost nothing to write and has saved the client every single time something has gone sideways. It is now part of every migration we quote.

Pick a stack. Or pick the team that ships every one of them.