Tom Sailors
· Refreshed
Brief · Anonymized case study

WooCommerce to Shopify Plus Migration

Migrating from WooCommerce to Shopify Plus requires four overlapping systems: a bulk product and inventory importer that stores original WooCommerce IDs as reference metadata; a URL redirect router that intercepts legacy paths and serves 301s to new Shopify URLs; a separate Postgres archive for historical orders that Shopify's API cannot expose; and a pre-launch crawl audit that tests every redirect before DNS cutover. Each runs independently but must be orchestrated to avoid data loss or SEO leakage.

A mid-market retail merchant operating WooCommerce needed to migrate to Shopify Plus while preserving 8 years of order history with original timestamps, maintaining every legacy URL with 301 redirects, and protecting SEO authority across the transition.
Four pieces
Migration

Product & Inventory Import

Pulls the WooCommerce product catalog, SKUs, pricing, inventory, and custom fields into Shopify Plus, storing the original WooCommerce IDs as reference data in metafields so discrepancies can be traced later.

Custom Shopify app + Heroku backend
Admin GraphQL explorer graphql
# Admin GraphQL — bulk product + metafield import
query GetProductsForImport($first: Int!) {
  products(first: $first) {
    edges {
      node {
        id
        title
        handle
        productType
        vendor
        variants(first: 100) {
          edges {
            node {
              id
              sku
              barcode
              price
              inventoryQuantity
            }
          }
        }
        metafields(first: 100, namespace: "wc_legacy") {
          edges {
            node {
              id
              namespace
              key
              value
            }
          }
        }
      }
    }
    pageInfo { hasNextPage endCursor }
  }
}

mutation ImportProduct($input: ProductInput!) {
  productCreate(input: $input) {
    product {
      id
      title
      handle
    }
    userErrors { field message }
  }
}
Pair with a CSV or JSON export from WooCommerce REST API; use metafieldsSet to store original WC product ID under namespace 'wc_legacy' key 'product_id' for traceability.
Migration

URL Redirect Router

Maps every WooCommerce product, category, and post URL to its new Shopify equivalent via a lookup table, serving 301 redirects that search engines follow and preserving all backlink authority.

Shopify Plus theme extension + Heroku redirect service
theme/snippets/legacy-redirect-check.liquid liquid
{% comment %}
  Legacy URL redirect checker — intercept old WC URLs and 301 them to new Shopify ones.
  Store redirect map in a JSON metafield on the store's settings.
{% endcomment %}

{% assign wc_redirects = shop.metafields.migrations.wc_url_map | parse_json %}
{% assign current_path = request.path | downcase %}

{% for mapping in wc_redirects %}
  {% if current_path == mapping.old_path %}
    {% comment %} Match found; render 301 redirect {% endcomment %}
    <meta http-equiv="refresh" content="0; url={{ mapping.new_url }}" />
    <script>
      if (navigator.userAgent.indexOf('Googlebot') !== -1 || navigator.userAgent.indexOf('bingbot') !== -1) {
        window.location.href = '{{ mapping.new_url }}';
      }
    </script>
    {% break %}
  {% endif %}
{% endfor %}
For true 301 responses (not meta-refresh), use a Heroku middleware that intercepts requests and returns HTTP 301; upload the redirect map as a Shopify metafield CSV.
Operations

Historical Order Archive

Stores 8 years of WooCommerce orders in a secure, queryable archive with original timestamps and customer data intact, accessible to the team without cluttering Shopify's order list.

Postgres database + custom admin dashboard
Migration

Pre-Launch SEO Audit

Runs an automated crawl of the live WooCommerce site, builds the redirect map, tests every 301 response, and flags broken or missing mappings before going live.

Crawl service + Heroku validation job
Shopify Flow editor: When → Then flow
Trigger: Manual workflow start or scheduled daily at 2 AM

Condition: Check if "migration_stage" metafield equals "pre_launch"

Actions:
  1. Send HTTP request to Heroku crawl service:
     POST /crawl/validate-redirects
     Body: { wc_domain: "legacy-site.com", shopify_domain: "new-site.myshopify.com" }
  2. Wait for response; parse redirect_success_count and redirect_fail_urls
  3. If redirect_fail_urls.length > 0:
     → Slack notification: "Redirect audit failed on {{redirect_fail_urls.count}} URLs — review dashboard"
  4. If all pass:
     → Email store owner: "Pre-launch audit passed. Safe to flip DNS."

Got a similar problem?

Sketch your build in 30 seconds — voice, type, or attach a screenshot.

Sketch the build →