Migration
Magento 1 naar Shopify in 48 uur: het complete draaiboek
Magento 1's support stopte in juni 2020. Draait je shop er nog op, dan verliest de standaard migratieaanpak de URLs die geld opleveren en de reviews die de verkoop sluiten.

Het is vrijdagmiddag 16:00 in Rotterdam. De webshop van je klant draait sinds 2016 op Magento 1.9. Adobe stopte vijf jaar geleden met patches. De hosting-rekening valt elke maand binnen, omdat niemand de migratie wil aanraken. Twaalfduizend productpagina's zijn negen jaar lang gecrawld, gerankt en gereviewd. Marketing-automation verwijst naar die product-URLs in 1.400 outbound e-mails per kwartaal. De eigenaar wil maandagochtend op Shopify staan. Je hebt het weekend.
Dit is het draaiboek dat we gebruiken als een klant ons vraagt om in één weekend van Magento 1 af te stappen, zonder de URLs te verliezen die geld opleveren of de reviews die de verkoop sluiten. We gaan ervan uit dat je het Shopify-abonnement al hebt gekozen, het thema vaststaat en de payment processors gematcht zijn. Het werk hieronder is het deel waar niemand je over vertelt.
De drie dingen die kapotgaan
Drie dingen doen pijn bij een migratie van Magento naar Shopify, en ze doen op verschillende momenten pijn.
Product-URLs gaan als eerste stuk, omdat Magento's URL rewrite table volledig anders is opgebouwd dan hoe Shopify het regelt. Reviews gaan als tweede stuk, omdat ze in vendor-specifieke tabellen leven en de Shopify-kant vendor-specifieke apps wil. SEO-autoriteit gaat als derde stuk, met zes weken vertraging, omdat Google tijd nodig heeft om je site opnieuw te crawlen en het model ervan opnieuw op te bouwen. De migratie die misgaat verliest één of twee van deze drie. De migraties die we ons graag herinneren bewaren alle drie.
De officiële einddatum voor Magento 1 staat in Adobe's eigen end-of-software-support notitie: 30 juni 2020. De shops die er nog op draaien betalen meestal een derde partij voor PCI-patches. De meeste van die contracten kosten inmiddels meer per jaar dan Shopify Plus.
Acht blokken van zes uur
We splitsen het weekend in acht blokken van ruwweg zes uur. Twee mensen verdelen die. Eén drijft de export en de data-engineering, de ander drijft de Shopify-kant, het thema en de verificatie. Slapen doe je in shifts.
Blok 1 (vrijdag 17:00–23:00): bevriezen en snapshot
Stop alles dat naar Magento schrijft. Zet de admin achter HTTP basic auth. Schakel order capture op de front-end uit. Pauzeer elke cron die voorraad raakt. Maak daarna drie snapshots:
- Een
mysqldumpvan de volledige database met--single-transaction --routines --triggers. - Een tarball van
/media/catalog/product/. - Een statische crawl van de live site naar disk met
wget --mirrorals fallback.
De statische crawl is het vangnet. Gaat maandag mis, dan kun je de crawl vanuit een bucket serveren terwijl je uitzoekt wat er gebeurde. Sla 'm niet over omdat het paranoïde voelt.
Blok 2 (vrijdag 23:00–zaterdag 05:00): de URL-map
Dit is het belangrijkste blok van het weekend. Bouw een CSV met drie kolommen: de oude URL, de nieuwe URL en een status. Trek 'm uit core_url_rewrite in de Magento-database.
SELECT
CONCAT('/', request_path) AS old_path,
product_id,
category_id
FROM core_url_rewrite
WHERE is_system = 1
AND product_id IS NOT NULL
AND store_id = 1
ORDER BY product_id;
De ruwe output is niet de map. Shopify normaliseert handles anders (lowercase, ASCII, alleen hyphens) en categorie-geneste URLs zoals /men/shoes/blue-runner.html klappen in tot /products/blue-runner in Shopify, omdat het platform producten niet nest onder collections in z'n canonical URLs.
Dus je genereert de kandidaat en haalt die door een transform die Shopify's handle-regel naspeelt. De betrouwbaarste aanpak is de transform in code schrijven en op elke rij toepassen:
function shopifyHandle(slug) {
return slug
.toLowerCase()
.replace(/\.html$/, '')
.replace(/[^\w\s-]/g, '')
.replace(/\s+/g, '-')
.replace(/-+/g, '-')
.replace(/^-|-$/g, '');
}
Sla het resultaat op als url-map.csv. Je gaat 'm voor maandag drie keer gebruiken.
Blok 3 (zaterdag 05:00–11:00): producten
Exporteer Magento's producten in het formaat dat Shopify's bulk importer verwacht. De schoonste route aan de Shopify-kant is Matrixify (vroeger Excelify), die Shopify's import-schema native spreekt en een CSV accepteert met images, varianten, SEO-velden en metafields.
De Magento-export is de lastigere kant. catalog_product_entity joint met al z'n EAV attribute-tabellen, het deel van Magento 1 waar niemand blij van wordt. Gebruik n98-magerun voor nette CLI-toegang:
n98-magerun.phar db:console < queries/products_full_export.sql > products_raw.tsv
Map vervolgens elk Magento-attribute naar een Shopify-kolom. Let op deze valkuilen. Magento's description-veld zit vaak vol met inline styles uit oude WYSIWYG-sessies; Shopify rendert ze, maar ze zien er op het nieuwe thema kapot uit. Strip ze. Magento-varianten staan als aparte parent- en child-rijen; Shopify-varianten zitten genest binnen één product. Het Matrixify-template handelt dit correct af als je Variant Position consistent meegeeft.
Blok 4 (zaterdag 11:00–17:00): reviews
Dit is het blok dat bureaus overslaan. Negen jaar aan reviews gooi je niet weg omdat de export irritant was. De pull is één SQL-query tegen review, review_detail en rating_option_vote:
SELECT
r.review_id,
r.created_at,
rd.title,
rd.detail,
rd.nickname AS author_name,
rd.customer_id,
rov.value AS rating,
cpe.sku
FROM review r
JOIN review_detail rd ON rd.review_id = r.review_id
JOIN rating_option_vote rov ON rov.review_id = r.review_id
JOIN catalog_product_entity cpe ON cpe.entity_id = r.entity_pk_value
WHERE r.status_id = 1
ORDER BY r.created_at;
Draait de shop op Yotpo, Trustpilot of Reviews.io bovenop Magento, dan houden die vendors hun eigen kopie. Open vrijdagmiddag een ticket bij de vendor en vraag om een volledige export op SKU. De meesten leveren binnen 24 uur als je het op schrift vraagt.
Aan de Shopify-kant is onze default Judge.me, omdat de CSV-importer precies de vorm hierboven accepteert met een kleine kolom-rename, en omdat het review-HTML server-side rendert, zodat de schema in de page source verschijnt.
Renderen reviews op de nieuwe shop alleen via client-side JavaScript, dan verdwijnen je structured-data rich results binnen twee weken. Check de gerenderde HTML op aggregateRating via view-source op een productpagina vóór je cutover, niet erna.
Blok 5 (zaterdag 17:00–23:00): klanten, orders, historie
Klantaccounts hebben hun e-mail en adresboek nodig. Hun hashed password niet; Shopify accepteert geen Magento bcrypt-hash, dus elke klant reset bij eerste login. Verpak dit in de launch-mail als een security upgrade. Dat is het ook.
Orders zijn lastiger. Je hebt ze strikt genomen niet nodig in Shopify om te draaien, maar je hebt ze wel vindbaar nodig als een klant support mailt. Twee aanpakken: importeer de laatste 24 maanden in Shopify en houd de rest in een read-only archief, of houd alle orders in het archief en route support daar naartoe. Wij doen het tweede. Shopify's plan tiers duwen je richting kleinere order-tabellen, en een archief van negen jaar is grotendeels ruis.
Blok 6 (zondag 00:00–06:00): thema en product-import
Push de producten in Shopify. Voor 12.000 SKU's neemt Matrixify ruwweg drie tot vijf uur, dus trap die af aan het begin van dit blok en gebruik de tijd om het thema af te maken. Het themawerk gaat vooral over zorgen dat de productpagina de juiste metafields rendert, de collection-pagina's de juiste faceting gebruiken en de cart shipping rates uit je zones pakt.
Reserveer het laatste uur van dit blok voor spot-checks. Open 30 willekeurige product-URLs uit url-map.csv en bevestig dat ze renderen met afbeeldingen, varianten en prijs.
Blok 7 (zondag 06:00–12:00): de redirect-laag
Shopify's ingebouwde URL-redirects werken, maar er zit een limiet van 100.000 entries op en bulk-updates zijn traag. Voor 12.000 product-URLs plus categorieën, blogposts, CMS-pagina's en parametrische varianten wil je dat de redirect aan de edge gebeurt, voordat de request Shopify raakt.
Onze default is een Cloudflare Worker met de URL-map in KV geladen. De vorm is klein:
export default {
async fetch(req, env) {
const url = new URL(req.url);
const target = await env.URL_MAP.get(url.pathname);
if (target) {
return Response.redirect(`https://${url.hostname}${target}`, 301);
}
return fetch(req);
}
};
Laad de KV-namespace uit url-map.csv in één batch-upload. Worker plus KV kost enkele euro's per maand voor een shop van dit formaat. Wil je Cloudflare overslaan, dan is Shopify's redirects.csv bulk-import via Matrixify de tweede keus, met dezelfde datavorm.
Drie categorieën URLs verdienen een eigen ronde: query-string filters (?color=blue op categoriepagina's), CMS-pagina's (/about-us, /shipping) en de homepage van eventuele sub-language stores waarvan de slug-structuur veranderde. Loop ze met de hand af. Het zijn er niet zoveel.
Blok 8 (zondag 12:00–18:00): DNS, verifiëren, monitoren
Zet DNS over op Shopify zodra de redirect-laag verified is en de product spot-check slaagt. TTL moet al op 60 seconden staan, omdat je 'm vrijdagmiddag verlaagd hebt. Kijk naar de propagatie en draai dan drie verificaties:
- Een status-check tegen elke URL in
url-map.csv.curl -o /dev/null -s -w "%{http_code} %{url_effective}\n"in een loop is prima. - Een Lighthouse-pass tegen de top-30 best bezochte pagina's. Noteer LCP en CLS. Die zien er op dag één slechter uit dan de Magento-cijfers en herstellen binnen een week.
- Een live zoekopdracht op één van je hoogst-gerankte queries. Bevestig dat het resultaat nog steeds resolveert.
Dien de nieuwe sitemap in bij Google Search Console als laatste actie. Houd de oude property open. Daar kijk je de komende 30 dagen naar het volume crawl-errors om URLs te vangen die de map heeft gemist.
De staart van dertig dagen
De migratie is niet voorbij als DNS flipt. De eerste maand is wanneer je de URLs vindt die niemand bijhield: deep-linked productvarianten uit e-mails verstuurd in 2019, blogposts die naar categoriepagina's linkten met filter-params die niemand documenteerde, de affiliate die wijst naar een vanity URL die de oorspronkelijke developer vergeten was op te schrijven. Kijk de eerste twee weken dagelijks naar Search Console's coverage report en de twee weken daarna wekelijks. Elke nieuwe 404 die het vindt is een rij die je toevoegt aan de KV-redirect-map.
Reviews op het nieuwe platform beginnen binnen ongeveer twee crawls van de pagina rich-result eligibility te scoren. Zie je na vier weken nog geen sterren terug in je SERP, dan is de meest voorkomende oorzaak dat Judge.me (of welke app je ook gekozen hebt) de schema alleen in JavaScript rendert. Switch de widget naar de server-rendered variant.
Eén echte klant, één onverwachte hobbel
Toen we deze migratie eerder dit jaar deden voor een Nederlandse outdoor-gearshop, was de onverwachte hobbel niet de catalogus. Het was een e-mailmarketingplatform uit 2014 met 800 product-URLs hardcoded in automation flows waar niemand was ingelogd sinds de dochter van de oprichter ze had opgezet. We losten het op door die 800 URLs te promoveren tot priority entries in de Cloudflare Worker, zodat de click-through Shopify niet raakte totdat het content-team van de e-mailvendor de templates een maand later herschreef.
De vijf-minuten audit
Voordat je een migratie-weekend vastlegt, draai je één query tegen je Magento-database. Tel het aantal rijen in core_url_rewrite waar is_system = 1 en store_id = 1. Dat getal is de omvang van je URL-map. Tel daarna de rijen in review waar status_id = 1. Dat is je review-bewaarprobleem. Is één van beide groter dan je verwachtte, bouw dan een extra blok in voordat je het weekend boekt.
Kern
Bouw eerst de URL-map, dan de product-import, dan de review-import. Alles wat je in een andere volgorde doet kost je organisch verkeer dat je niet meer terugkrijgt.
FAQ
Wat is het grootste risico bij een migratie van Magento 1 naar Shopify?
Het verliezen van de canonical URLs die organisch verkeer opleveren. Bouw de URL-map eerst, voordat je iets anders aanraakt, en serveer de redirects aan de CDN-edge, niet binnen Shopify.
Kun je klant-wachtwoorden importeren van Magento naar Shopify?
Nee. Magento's bcrypt-hashes zijn niet compatibel met Shopify's auth. Elke klant reset bij de eerste login. Verpak dit in de launch-mail als een security upgrade, want dat is het.
Hoe behoud je negen jaar aan productreviews?
Exporteer uit de tabellen review, review_detail en rating_option_vote in Magento, en importeer in Judge.me of een vergelijkbare Shopify-app die de review-widget server-side rendert, zodat de schema overleeft.
Kan Shopify 12.000 SKU's zonder problemen aan?
Ja, maar de bulk importer is traag. Reken op drie tot vijf uur per import-ronde met Matrixify, en draai kleinere batches waar mogelijk om sneller te herstellen van fouten.
Moet je Shopify-redirects gebruiken of een Cloudflare Worker?
Voor shops met minder dan 1.000 redirects zijn Shopify's ingebouwde redirects prima. Daarboven schaalt een Cloudflare Worker met KV beter en kun je updates uitrollen zonder een CSV-import opnieuw te draaien.