WordPress to Shopify redirects: WooCommerce urls into /products/ and /collections/

every url of a WooCommerce store changes on Shopify, and every one of them is its own row.

by Max Lorenz, Goodaim · updated

woocommerce → shopify
  • /product/linen-shirt/301
    /products/linen-shirt
  • /product-category/shirts/301
    /collections/shirts
  • /about/301
    /pages/about
  • /shop/linen-shirt/reserved
    not redirectable in shopify

SHORT ANSWER

A WordPress or WooCommerce site moving to Shopify needs a 301 for nearly every url, because Shopify’s url structure is fixed: products live under /products/, categories become collections under /collections/, pages sit under /pages/ and posts under /blogs/news/ (or whatever the blog is called). Shopify has no wildcard redirects, so each old url gets its own row in a two-column csv imported under Content, Menus, URL redirects. Two things break the routine: Shopify refuses redirects from /shop and a few other prefixes, and a redirect only fires when nothing exists at the old path.

Which WordPress and WooCommerce urls move where?

WooCommerce adds its own url patterns on top of WordPress’s. The product base and the category base are configurable under Settings, Permalinks, so check what the old store actually used before you trust the defaults (WooCommerce permalinks). On the Shopify side, the prefix comes from the template type and only the handle after it is yours to choose (Shopify theme templates).

old patternon shopifyhow
/product/slug//products/slugone row per product, matched on the slug
/shop/category/slug//products/slugreserved prefix on shopify, see below
/product-category/name//collections/nameone row per category; sub-categories flatten
/product-tag/name/a collection, or nothingonly the tags that get traffic
/shop//collections/allnot redirectable on shopify
/about//pages/aboutone row per page
/post-name/ · /2021/03/post-name//blogs/news/post-nameone row per post
/category/name/ · /tag/name//blogs/news/tagged/name, or the bloga handful of rows by hand
/cart/ · /checkout//cart · /checkoutshopify's own routes, no row
/my-account//accountone row
/wp-content/uploads/…/file.pdfthe file's new cdn urlper file, full url as target

sub-categories — WooCommerce nests categories, /product-category/men/shirts/. Shopify collections are flat, so the nested url becomes /collections/mens-shirts or similar. The slug is no longer the last segment alone, which is why these rows land in needs review more often than products.

two urls per product on shopify — Shopify also answers /collections/name/products/slug and marks /products/slug as canonical. Always redirect to the /products/ form; Silentfrog reads the canonical tag when it crawls the new store, so the matched target is already the canonical url.

EXAMPLE

a store with 420 products under /product/, 28 categories, 15 pages and a blog of 90 posts at the root: about 550 rows, of which the products match on the slug almost without exception because migration apps keep the slug as the Shopify handle.

The /shop problem: paths Shopify will not redirect

Shopify’s help center lists the prefixes a redirect cannot start with — any url beginning with them, not only the bare path: /apps, /application, /cart, /carts, /orders, /services and /shop, plus fixed paths such as /products, /collections and /collections/all (Shopify url redirects). Two of those collide head-on with typical WordPress sites:

  • /shop. WooCommerce’s shop page is /shop/ by default, and with the shop base or shop base with category product permalink every product url starts with it: /shop/hoodie-with-logo/, /shop/hoodies/hoodie-with-logo/.
  • /services. A service business on WordPress very often has /services/ and pages below it.

A row with one of those on the left is refused or ignored by the import. There is no setting that changes this. If the old store had its products under /shop/, the realistic options are a redirect layer in front of Shopify (a cdn or proxy that answers before the store does), or accepting the loss for the urls without traffic. Decide before the domain moves; Search Console tells you how much traffic those urls still get.

EXAMPLE

a store on the shop base with category permalink: 380 product urls start with /shop/. The Silentfrog map pairs every one of them correctly, but the Shopify import will refuse them, so these rows go to whoever configures the proxy instead.

Redirects only fire on broken urls

Shopify redirects a url only when it would otherwise be a 404. If a product, page or collection exists at the Redirect from path, the store serves it and the redirect does nothing. In a WooCommerce migration that matters in two places: a migration app that created a page with the old slug, and a Shopify page whose handle happens to equal an old WordPress path. The import accepts such rows without complaint, so check them after go-live, not in the import dialog.

The same page also caps the count: 100,000 redirects per store, 20 million on Plus. A WooCommerce store would need a very large catalogue to get near it, even though every row is written out individually.

Getting the complete list of old urls

WordPress has a sitemap index at /wp-sitemap.xml on a default install and at /sitemap_index.xml with Yoast or Rank Math; it points at one file per post type, products included. Silentfrog reads robots.txt and follows the index on its own. Add the Search Console pages export to the url list: it holds the discontinued products and old posts that no sitemap lists any more, and those are often the urls with the backlinks (finding the urls nothing links to).

Variation urls with query strings, ?attribute_pa_color=blue, are treated as the product itself: the tool ignores query strings, and Shopify’s redirect matches the path.

start a crawl

extra old-site urls the crawl might not reach — one per line, or a csv export with the url in the first column (crawler export, search console, server logs). paths like /blog/post work too.

free up to 50 pages per site

the crawl form with the old site url, the new site url, the page cap, the sitemap option and the field for your own url list.

the crawl form: the sitemap index is read automatically, and the url list takes the search console export.

Crawling the new store before launch

The matcher needs the new store’s pages, and a Shopify store in development sits behind a storefront password that a crawler cannot pass. Switch the password off for the run, on the your-store.myshopify.com domain, while the old domain still points at WordPress. The crawl takes minutes; the password can go back on afterwards.

Products match well because migration apps usually keep the WooCommerce slug as the Shopify handle, so slug and title agree. Categories and pages are where the fuzzy matches and the needs-review rows collect: collection handles get renamed, and /about-us/ becomes /pages/about. Sort by confidence and read those.

Posts, archives and the things that are not products

posts — a post at /post-name/ or /2021/03/post-name/ becomes /blogs/news/post-name. Shopify’s default blog is called News; if you rename it or add a second one, the handle in the middle changes with it. The date segments have no counterpart, which makes no difference on Shopify: every row is written out anyway.

category and tag archives — WordPress’s post categories and tags have no successor unless the theme shows tag-filtered blog pages. Redirect the archives that get traffic to the blog index and let the rest go.

uploads — a pdf other sites link to gets its own row with the file’s new Shopify cdn url as a full-url target. Images are rarely worth it.

feeds and admin paths — /feed/, /wp-admin/, /wp-login.php and /wp-json/ need nothing. Letting them 404 is the point.

Redirects that already exist on both sides

The WordPress side may carry a redirect table in Redirection, Yoast Premium or Rank Math. Put those source urls into the url list, so they are matched against the new store directly; importing them as they stand would chain the old target to the new one.

The Shopify side may already have redirects too: Shopify adds one whenever a handle is changed with the redirect box ticked, and some migration apps write their own. Export the list from the URL redirects page before importing, and use the import’s overwrite option when your new map should win over what the app wrote (importing redirects into Shopify).

Trailing slashes

Every WordPress url ends in a slash; Shopify’s do not. Silentfrog treats /product/hoodie/ and /product/hoodie as one page and writes the source without the slash. Shopify’s documentation does not say whether a redirect for the slashless path also catches the slashed form, so include both forms in the check after the import: request /product/hoodie/ as well as /product/hoodie, since the slashed one is what the backlinks contain.

Doing it in one pass

  • Export the WordPress plugin’s redirects and the Search Console pages report while the old site is up.
  • Take the storefront password off, and start a run with the WordPress domain as the old site and the myshopify.com domain as the new one. Paste the plugin’s sources and the Search Console urls into the url list (starting a run).
  • Review needs review from the top, re-map categories and pages that went to the wrong target, and verify the rows you accept.
  • Pull out every row whose old path begins with /shop or /services (the bare page and everything below it); those cannot go into Shopify.
  • Download the redirects file with shopify picked, which writes the Redirect from,Redirect to header and every directory rule as single rows, and import it under Content, Menus, URL redirects.
  • After the domain moves, crawl the old url list against the live store: one 301, then 200. Compare the imported count to the file; the difference is reserved prefixes or paths that still load.
export

site settings → publishing → 301 redirects, or the data api

the two export buttons — webflow csv and generic csv — next to the option that includes needs-review matches.

the export: pick shopify and the file is ready for the url redirects import, with no wildcard rows in it.

The first 50 pages of the old site are free, which covers a small shop or a test of one category. Medium at 46 € per relaunch covers up to 150 old pages; a store with a few hundred products needs Unlimited at 150 €. Only the old site’s pages count.

In short

  • Shopify's prefixes are fixed: /products/, /collections/, /pages/, /blogs/<blog>/. Practically every WordPress url changes.
  • No wildcards: one row per product, category, page and post. The shopify export writes them out for you.
  • /shop and /services cannot be redirected inside Shopify. A WooCommerce store on the shop base permalink needs a redirect layer in front of the store.
  • A redirect only fires when nothing exists at the old path.
  • Take the storefront password off for the crawl, and test the slashed form of each old url after go-live.