WooCommerce winkelmandje werkt niet: een kapotte add-to-cart of checkout diagnosticeren

Je WooCommerce add-to-cart knop doet niks, het winkelmandje leegt zichzelf tussen pagina's, of de checkout blijft eindeloos draaien zonder de bestelling af te ronden. De oorzaak is bijna nooit 'een plugin conflict' zoals de meeste fora beweren. In het overgrote deel van de gevallen is het een cachingconfiguratie die een verouderde pagina serveert waar een dynamische hoort. Dit artikel loopt elke gangbare oorzaak door op volgorde van waarschijnlijkheid, met een browserdiagnose per geval.

De symptomen zien er verschillend uit maar delen een patroon: de browser stuurt een AJAX-verzoek naar WooCommerce's ?wc-ajax= endpoint, en dat verzoek wordt niet verstuurd, wordt verstuurd maar faalt stil, of wordt verstuurd en krijgt een verouderd antwoord terug. Zodra je weet welk van die drie het is, is de fix meestal binnen een paar minuten duidelijk. Het diagnosepad hieronder gaat van meest voorkomend naar minst voorkomend.

Veelvoorkomende symptomen

Drie variaties van hetzelfde onderliggende probleem duiken het vaakst op:

  • Add-to-cart knop doet niks. Je klikt, en er gebeurt helemaal niks. Geen pagina-reload, geen update van het winkelmandje-aantal, geen foutmelding. Het product blijft gewoon staan alsof er niks gebeurd is.
  • Winkelmandje leegt zichzelf tussen pagina's. Je voegt een product toe, navigeert naar de winkelwagenpagina, en die zegt dat je mandje leeg is. Opnieuw proberen. Zelfde resultaat.
  • Checkout draait eindeloos. Je vult de factureringsgegevens in, klikt op "Bestelling plaatsen", de spinner start en stopt nooit. Geen orderbevestiging, geen foutmelding. Soms toont de browserconsole een AJAX-response van -1.

Elk symptoom wijst naar een ander faalpunt, maar caching is de oorzaak in meer gevallen dan al het andere bij elkaar.

Caching: veruit de meest voorkomende oorzaak

WooCommerce's winkelmandje-, checkout- en mijn-accountpagina's zijn sessiegebonden en mogen nooit full-page gecached worden. Het winkelmandje toont de items van die ene klant; de checkout bevat een nonce-token dat uniek is voor die bezoeker. Een gecachte versie van die pagina's serveert de verkeerde data aan de verkeerde persoon, of een verlopen nonce dat WooCommerce afwijst bij het afrekenen.

WooCommerce zet automatisch de DONOTCACHEPAGE constante op de winkelmandje-, checkout- en mijn-accountpagina's. Elke WordPress-level caching plugin die deze constante respecteert (WP Rocket, WP Super Cache, W3 Total Cache, LiteSpeed Cache) slaat die pagina's over. Het probleem begint wanneer een cachelaag buiten WordPress draait en de constante nooit ziet:

  • nginx fastcgi_cache cachet PHP-output voordat WordPress draait. PHP-constanten leest hij niet.
  • Varnish zit helemaal voor de webserver. Die heeft expliciete VCL-regels nodig om WooCommerce-sessiecookies door te laten.
  • Cloudflare APO cachet HTML op de edge. De WooCommerce-integratie regelt uitzonderingen, maar die integratie moet wel actief zijn, en custom checkout-URL's worden niet automatisch uitgezonderd.
  • LiteSpeed server-level cache staat los van de LiteSpeed Cache WordPress-plugin en vereist eigen uitzonderingsregels in .htaccess of het LiteSpeed-beheerpaneel.

Hoe je het checkt

Open de checkoutpagina in een incognitovenster (een browser waar je niet ingelogd bent). Open de Network-tab in de DevTools van je browser (F12 > Network), herlaad de pagina en klik op het hoofdverzoek (degene die matcht met je checkout-URL). Bekijk in de Response Headers sectie of je x-cache, cf-cache-status, age, x-proxy-cache of x-nginx-cache ziet staan.

Als x-cache: HIT of cf-cache-status: HIT verschijnt, of age: een getal boven 0 toont, dan wordt de checkoutpagina uit een cachelaag geserveerd. Dat is het probleem.

Als je SSH-toegang hebt:

curl -sI https://jouwsite.nl/afrekenen/ | grep -Ei '^(x-cache|cf-cache-status|age|x-proxy-cache|x-nginx-cache)'

Hoe je het oplost

Voeg de WooCommerce-sessiecookies toe aan de cache-bypass-regels van je server-level cache. De drie cookies die je moet matchen:

Cookie Doel
woocommerce_items_in_cart Houdt bij of het mandje items bevat
woocommerce_cart_hash Detecteert wijzigingen in de mandjeinhoud
wp_woocommerce_session_* Koppelt de browser aan een server-side sessie

Voor nginx fastcgi_cache ziet de bypass-regel in het server-blok er zo uit:

# Bypass cache wanneer WooCommerce-sessiecookies aanwezig zijn
if ($http_cookie ~* "woocommerce_items_in_cart|woocommerce_cart_hash|wp_woocommerce_session_") {
    set $skip_cache 1;
}

# Bypass ook op specifieke WooCommerce-pagina's via URL
if ($request_uri ~* "/cart/|/checkout/|/my-account/|\?wc-ajax=") {
    set $skip_cache 1;
}

Voor Cloudflare voeg je Page Rules (of Cache Rules in het nieuwe dashboard) toe die "Cache Level: Bypass" instellen op /checkout/*, /cart/*, /my-account/* en /*?wc-ajax=*.

Na het toevoegen van de uitzonderingen wis je de volledige cache en test je opnieuw. Je weet dat het werkt als de checkoutpagina x-cache: MISS of cf-cache-status: BYPASS retourneert bij elk verzoek, en de age header afwezig is of op 0 staat.

Voor een diepere kijk op waarom cache bypass-regels falen en hoe je hit rates diagnosticeert, behandelt waarom je WordPress cache niet werkt het volledige diagnosepad.

Verlopen nonce op een gecachte checkoutpagina

Dit is een specifieke variant van het cachingprobleem die een eigen sectie verdient, want het symptoom is anders: de checkoutpagina laadt prima, maar klikken op "Bestelling plaatsen" geeft een AJAX-response van -1 of een "beveiligingscontrole mislukt" melding.

WordPress nonces gebruiken een tick-gebaseerd verloopsysteem. De standaard levensduur is 24 uur, opgedeeld in twee ticks van 12 uur. Een nonce die aan het begin van een tick gemaakt is, leeft de volle 24 uur; eentje die aan het eind gemaakt is, leeft net iets meer dan 12 uur. WooCommerce's checkout gebruikt het woocommerce-process-checkout-nonce nonce, ingebouwd in de checkout-form HTML.

Wanneer een server-level cache een checkoutpagina uit de opslag serveert, zit het nonce in de HTML bevroren op het moment dat de cache gemaakt werd. Als de cache langer leeft dan 12 uur (of over een tick-grens heen gaat), is het nonce al verlopen of in zijn tweede tick wanneer een klant het ziet.

De misvatting: "gewoon de pagina verversen". Verversen helpt niet als de servercache de oorzaak is, want de refresh haalt dezelfde gecachte HTML op met hetzelfde verlopen nonce. De klant blijft in een lus hangen. De fix is hetzelfde als hierboven: sluit de checkout uit van de cachelaag en wis de verouderde gecachte versie.

Hoe je bevestigt dat het een nonce-probleem is

  1. Open de checkoutpagina, vul de gegevens in en klik op "Bestelling plaatsen".
  2. Open de Network-tab van de browser (F12 > Network) en zoek het ?wc-ajax=checkout verzoek.
  3. Klik erop en lees de response body. Als die "result":"failure" bevat en het bericht naar een beveiligingscontrole verwijst, of als de ruwe response -1 is, dan is het nonce ongeldig.
  4. Vergelijk de nonce-waarde in het verborgen formulierveld (woocommerce-process-checkout-nonce) met een verse, gegenereerd door de checkout in een nieuw incognitosessie te openen. Als ze identiek zijn, is de pagina gecached.

Mixed content blokkeert het wc-ajax endpoint

Als je site op HTTPS draait maar het WordPress-adres of het Site-adres in Instellingen > Algemeen nog http:// bevat, of als een reverse proxy SSL termineert en de juiste headers niet doorstuurt naar WordPress, dan gaan de ?wc-ajax= verzoeken over HTTP terwijl de pagina HTTPS is. Moderne browsers blokkeren dat stil als mixed content.

Hoe je het checkt

Open de browserconsole (F12 > Console) op een pagina met een add-to-cart knop. Als je dit ziet:

Mixed Content: The page at 'https://jouwsite.nl/shop/' was loaded over HTTPS,
but requested an insecure XMLHttpRequest endpoint 'http://jouwsite.nl/?wc-ajax=add_to_cart'.
This request has been blocked; the content must be served over HTTPS.

Dan is dat de oorzaak.

Hoe je het oplost

  1. Ga naar Instellingen > Algemeen en controleer of zowel WordPress-adres als Site-adres https:// gebruiken.
  2. Als je achter een reverse proxy zit (nginx, Varnish, Cloudflare, een load balancer) die SSL termineert, controleer dan of de proxy X-Forwarded-Proto: https meestuurt en dat wp-config.php het volgende bevat. Je kunt wp-config.php bewerken via de bestandsbeheerder van je hostingpaneel of via SFTP:
// Vertrouw de X-Forwarded-Proto header van de reverse proxy
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
    $_SERVER['HTTPS'] = 'on';
}
  1. Na het fixen van de URL-instellingen flush je de permalinks (Instellingen > Permalinks > Opslaan) en wis je alle caches.

Voor een volledig overzicht van het vinden en fixen van mixed content resources voorbij alleen het AJAX-endpoint, behandelt mixed content waarschuwingen in WordPress het complete diagnosepad.

JavaScript-conflict verhindert de AJAX-aanroep

Als een plugin- of themascript een JavaScript-fout gooit voordat WooCommerce's eigen scripts draaien, bindt de add-to-cart AJAX-handler nooit, of vuur de checkout-submission handler nooit af. De knopklik doet niks omdat er geen listener aan hangt.

Hoe je het diagnosticeert

  1. Open de browserconsole (F12 > Console).
  2. Klik op de add-to-cart knop of de "Bestelling plaatsen" knop.
  3. Zoek naar rode foutmeldingen. Een conflict toont zich doorgaans als een Uncaught TypeError of Uncaught ReferenceError die wijst naar een bestand dat niet van WooCommerce is (een themascript, een slider plugin, een analytics tag).

Hoe je het isoleert

  1. Schakel tijdelijk over naar een standaardthema (Storefront of Twenty Twenty-Five). Als het probleem verdwijnt, is het JavaScript van het thema de oorzaak.
  2. Als het thema het niet is, schakel dan plugins een voor een uit. Begin met plugins die front-end JavaScript injecteren: sliders, popups, analytics, page builders en cookieconsent-tools. Test opnieuw na elke deactivatie.
  3. De plugin waarvan de deactivatie het probleem oplost, gooit ofwel een fout of laadt een script dat conflicteert met WooCommerce's jQuery dependency chain.

Als je de conflicterende plugin vindt, check dan eerst of er een update beschikbaar is. Als geen update het oplost, neem contact op met de plugin-ontwikkelaar met de exacte consolefout. Laat de plugin niet permanent uitgeschakeld als die een bedrijfsfunctie vervult; de fout is een bug, geen configuratiekeuze.

Cart fragments laden niet meer na WooCommerce 7.8

Sinds WooCommerce 7.8 wordt het cart-fragments.js script alleen nog geladen op pagina's waar de Mini Cart widget actief is. Voor 7.8 draaide dit script op elke pagina en stuurde het bij elke page load een AJAX-verzoek naar ?wc-ajax=get_refreshed_fragments om het mini-cart itemtelling actueel te houden.

Als je thema een custom mini-cart implementatie gebruikt (handgeschreven HTML die het winkelmandje-aantal in de header toont, in plaats van de WooCommerce Mini Cart widget), dan breekt upgraden voorbij WooCommerce 7.8 die update stil. De mini-cart stopt met vernieuwen en toont een verouderd of nul items. Klikken op add-to-cart werkt wel op serverniveau, maar de visuele feedback komt nooit aan omdat het fragment-script niet geladen is.

Hoe je het checkt

Bekijk de paginabron (Ctrl+U) en zoek naar cart-fragments. Als de script-tag ontbreekt, is het fragment-systeem niet actief op die pagina.

Hoe je het oplost

Voeg dit toe aan je thema's functions.php (te bewerken via Weergave > Thema-editor in wp-admin, of via de bestandsbeheerder van je hostingpaneel) of een site-specifieke plugin:

// Laad cart fragments opnieuw op alle pagina's voor custom mini-cart markup
add_action('wp_enqueue_scripts', function () {
    if (function_exists('is_woocommerce')) {
        wp_enqueue_script('wc-cart-fragments');
    }
});

Je weet dat het werkt wanneer de paginabron de cart-fragments script-tag bevat en het mini-cart aantal bijwerkt na het toevoegen van een product zonder volledige pagina-reload.

Betaalgateway-misconfiguratie

Als de betaalgateway helemaal niet verschijnt op de afrekenpagina (in plaats van verschijnt maar faalt), is de oorzaak meestal Checkout Block-incompatibiliteit, SSL-afdwinging of geografische beperkingen. De gids voor ontbrekende WooCommerce-betaalgateways behandelt die gevallen in detail.

Een minder voorkomende maar makkelijk te missen oorzaak: de betaalgateway staat in sandbox- of testmodus en de sandbox-credentials zijn verlopen, of de gateway staat op live maar de API-keys horen bij een ander account of domein.

Het symptoom: de checkout lijkt te werken, de spinner draait, en het verzoek wordt afgerond, maar de bestelling wordt nooit aangemaakt of krijgt direct de status "Mislukt" met een gateway-fout in de ordernotities.

Hoe je het checkt

  1. Ga naar WooCommerce > Instellingen > Betalingen en open de actieve gateway.
  2. Controleer of de gateway in live of test/sandbox modus staat.
  3. Als sandbox-modus aan staat, controleer dan of de sandbox-credentials geldig zijn en voor de juiste winkel-URL.
  4. Plaats een testbestelling met de gedocumenteerde testkaarten van de gateway (voor Stripe: 4242 4242 4242 4242; voor PayPal sandbox: een sandbox buyer-account).
  5. Check WooCommerce > Bestellingen voor de nieuwe order. Open die en lees de ordernotities voor gateway-specifieke foutmeldingen.

Als de ordernotities een authenticatiefout bevatten, een "merchant not found" fout, of een domein-mismatch, dan moeten de gateway-credentials vervangen worden door geldige voor de huidige site-URL en modus.

Sessiecookies geblokkeerd door browser, WAF of CDN

WooCommerce slaat mandjedata server-side op in de wp_woocommerce_sessions databasetabel en koppelt de browser aan die sessie via het wp_woocommerce_session_* cookie. Als er iets tussen de server en de browser dat cookie verwijdert of blokkeert, start elke page load een nieuwe sessie. Het mandje leegt zichzelf bij elke navigatie.

Dingen die WooCommerce-sessiecookies blokkeren:

  • Een CDN die geconfigureerd is om alle cookies uit responses te verwijderen (gebruikelijk op Cloudflare Free met agressieve optimalisatie).
  • Een Web Application Firewall (WAF) regel die cookies met lange namen blokkeert of cookies die matchen op een wildcardpatroon.
  • Browserprivacy-extensies (uBlock Origin in strict mode, Privacy Badger) die third-party of sessiecookies op alle sites blokkeren.
  • Een cookieconsent-banner die alle cookies blokkeert totdat toestemming gegeven is, inclusief WooCommerce's functionele cookies.

Hoe je het checkt

Open de Application-tab van de browser (F12 > Application > Cookies) op de winkelwagenpagina na het toevoegen van een product. Zoek naar woocommerce_items_in_cart, woocommerce_cart_hash, en een cookie dat begint met wp_woocommerce_session_. Als een van deze ontbreekt, houdt de sessie niet stand.

Hoe je het oplost

De fix hangt af van wat het cookie blokkeert. Voor een CDN: voeg de drie WooCommerce-cookienamen toe aan de cookie pass-through lijst van de CDN. Voor een cookieconsent-tool: classificeer WooCommerce's sessiecookies als "functioneel" of "strikt noodzakelijk" zodat ze gezet worden voordat de bezoeker met de consentbanner interacteert. Voor een WAF: whitelist de cookienaam-patronen.

Wanneer escaleren

Als geen van de bovenstaande oorzaken matcht, verzamel dan het volgende voordat je contact opneemt met je hostingprovider of een developer:

  • De exacte WordPress-versie, WooCommerce-versie en PHP-versie (te vinden in WooCommerce > Status > Systeemstatus).
  • Een volledige kopie van het systeemstatusrapport (WooCommerce > Status > Systeemrapport ophalen).
  • Een screenshot van de browserconsole (F12 > Console) met eventuele fouten tijdens de falende actie.
  • Een screenshot van de Network-tab (F12 > Network) gefilterd op wc-ajax, met de verzoek-URL, HTTP-status en response body.
  • De lijst van actieve plugins op het moment van de fout.
  • Of het probleem begon na een specifieke update (WordPress, WooCommerce, een plugin, een serverwijziging).
  • Of het probleem alle klanten treft of alleen specifieke browsers of apparaten.

Deze informatie stelt een developer in staat het probleem te reproduceren in plaats van te gokken. Zonder komt het eerste antwoord neer op "probeer plugins uit te schakelen", en dat is het traagste diagnosepad dat er is.

Herhaling voorkomen

  • Voeg nooit een server-level cachelaag toe zonder expliciet WooCommerce's dynamische pagina's en het ?wc-ajax= endpoint uit te sluiten. De WooCommerce caching configuratiegids vermeldt elke URL en elk cookie dat uitgezonderd moet worden.
  • Na elke grote WooCommerce-update test je de volledige aankoopflow op staging: toevoegen aan mandje, mandje bekijken, doorgaan naar checkout, betaling afronden met een testkaart, controleren dat de bestelling verschijnt in WooCommerce > Bestellingen.
  • Na het wijzigen van de SSL-configuratie of het plaatsen achter een reverse proxy controleer je dat de ?wc-ajax= verzoeken in de Network-tab https:// gebruiken en JSON teruggeven, geen HTML of een redirect.
  • Als je een custom mini-cart gebruikt (niet de WooCommerce Mini Cart widget), pin dan de wc-cart-fragments enqueue in je thema zodat een WooCommerce-update die niet stil breekt.
  • Als de afrekenpagina "Geen verzendopties gevonden" toont, is de oorzaak meestal de zonevolgorde of niet-voldane voorwaarden voor gratis verzending — zie de WooCommerce verzendzones-probleemoplossingsgids.
  • WooCommerce is een fundamenteel andere workload dan een contentsite. Behandel het conversiepad van de winkel als onaantastbaar voor elke cachelaag, en test het na elke infrastructuurwijziging.

Wil je dat dit niet steeds jouw probleem is?

Als storingen blijven terugkomen, is de 'fix' vaak consistent beheer: updates, backups en monitoring die niet versloffen.

Bekijk WordPress onderhoud

Doorzoek deze site

Begin met typen om te zoeken, of blader door de kennisbank en blog.