Si vous avez déjà cliqué sur “Commander” et que rien ne se passe (ou pire, une erreur 500/403 apparaît), vous avez probablement un checkout WooCommerce cassé par du JavaScript, un endpoint AJAX bloqué, ou un cache mal configuré. Le piège, c’est que le checkout mélange page HTML, appels AJAX (wc-ajax), nonces et parfois REST API. Un seul maillon faible et tout s’écroule.
Le problème
Les messages exacts varient, mais ceux que je vois le plus souvent dans la console et les logs serveur ressemblent à ça :
Failed to load resource: the server responded with a status of 403 (Forbidden)
/?wc-ajax=checkout:1 403 (Forbidden)
Uncaught TypeError: Cannot read properties of undefined (reading 'checkout_url')
at checkout.js:...
PHP Fatal error: Uncaught Error: Call to undefined function wc() in /wp-content/themes/votre-theme/functions.php:123
PHP Fatal error: Uncaught Error: Class "AutomatticWooCommerceBlocksPackage" not found in /wp-content/plugins/mon-plugin/mon-plugin.php:45
[error] [client ...] ModSecurity: Access denied with code 403 (phase 2). Matched "Operator `Rx' with parameter `(?i)(?:bselectb|bunionb|bdropb)'" ... uri "/?wc-ajax=checkout"
Où ça apparaît :
- Front-end : page
/checkout/, au clic sur “Commander”, lors du changement de méthode de livraison/paiement, ou au chargement (fragments). - Admin : parfois via les réglages WooCommerce (si des assets ne se chargent pas), mais le checkout se casse surtout côté visiteur.
- API / AJAX : endpoints
?wc-ajax=checkout,?wc-ajax=update_order_review,?wc-ajax=get_refreshed_fragments, et parfois/wp-json/.
Circonstances typiques :
- Juste après une mise à jour WordPress (ici 6.9.4), WooCommerce, un plugin de paiement, ou un plugin de cache/minification.
- Après activation d’un WAF/CDN (Cloudflare, ModSecurity côté hébergeur) qui bloque
wc-ajax. - Après modification de template checkout dans un thème enfant (ou via un builder) et perte d’un hook WooCommerce.
À qui s’adresse ce dépannage : si vous êtes à l’aise avec PHP/JS et l’écosystème WordPress, vous repartirez avec une méthode reproductible pour isoler la cause (JS, cache, endpoint, conflit) et une série de correctifs concrets (avec code avant/après) compatibles WordPress 6.9.4+ et PHP 8.1+.
Résumé rapide
- Commencez par la console navigateur : une seule erreur JS peut empêcher le submit checkout.
- Testez les endpoints :
/?wc-ajax=update_order_reviewet/?wc-ajax=checkoutdoivent répondre (souvent en JSON/HTML partiel). - Désactivez temporairement la minification/différage JS : c’est la cause n°1 sur les sites avec cache agressif.
- Excluez checkout/cart/my-account du cache et des optimisations (CDN, page cache, Rocket Loader, etc.).
- Vérifiez WP_DEBUG + Query Monitor : une fatal PHP “silencieuse” côté AJAX ressemble à un checkout “qui ne fait rien”.
- Conflits plugins : test rapide avec Health Check (mode dépannage) sans impacter les visiteurs.
Les symptômes
Voici les symptômes visibles que vous pouvez rencontrer, souvent combinés :
- Le bouton “Commander” ne fait rien (pas de redirection, pas de message d’erreur).
- Spinner infini après sélection d’un moyen de paiement ou recalcul des frais de port.
- Erreur 500 sur
/?wc-ajax=checkoutou/?wc-ajax=update_order_review. - Erreur 403/406 (WAF/ModSecurity) sur les endpoints Woo.
- Erreur 400 “Bad Request” ou message “Invalid nonce” (souvent causé par cache).
- Console JS :
Uncaught TypeError,jQuery is not defined, ou erreurs surcheckout.js. - REST API :
/wp-json/renvoie 401/403, ce qui peut impacter certains moyens de paiement ou blocs. - Ça marche en local mais pas en production : CDN, cache serveur, règles de sécurité, ou différences PHP/extensions.
- Shortcode / bloc checkout non rendu après personnalisation (builder) : page vide ou contenu partiel.
Tableau de diagnostic rapide
| Symptôme | Cause probable | Vérification | Solution |
|---|---|---|---|
| Bouton “Commander” inactif | Erreur JS / minification / defer | Console navigateur + désactiver optimisation JS | Solution 1 + exclure scripts Woo |
| Spinner infini sur livraison/paiement | Endpoint update_order_review en erreur |
Onglet Réseau: status 500/403 | Solution 1 ou 3 selon code |
403 sur ?wc-ajax=checkout |
WAF/ModSecurity/CDN | Logs serveur + en-têtes WAF | Solution 3 (whitelist règle) |
| “Invalid nonce” / session perdue | Page cache sur checkout | Comparer HTML caché vs non caché | Solution 2 (exclusions cache) |
| 500 sur endpoint AJAX | Fatal PHP dans un plugin/thème | WP_DEBUG_LOG + Query Monitor | Corriger fatal + hook approprié |
Pourquoi ça arrive
Version simple : le checkout WooCommerce n’est pas “une page”. C’est une page qui déclenche des appels AJAX, manipule la session, et valide des nonces. Si un plugin modifie le chargement JS, si le cache sert une version figée, ou si le serveur bloque l’endpoint, le processus d’achat se bloque.
Version technique : WooCommerce s’appuie sur :
- Assets JS/CSS (notamment
wc-checkout,woocommerce,jquery-blockuiselon contexte), et sur des variables localisées (ex: URL AJAX, nonces, paramètres). - Endpoints AJAX via
admin-ajax.phppour certains flux, mais surtout?wc-ajax=...(plus léger) pourupdate_order_review,checkout, fragments, etc. - Cookies/session WooCommerce (panier, session client), sensibles aux caches et aux proxies.
- Hooks côté thème/plugins qui peuvent injecter des champs, valider des données, ou casser le flux (ex: validation trop stricte, erreur PHP).
Causes probables (du plus fréquent au plus rare) :
- Optimisation front (minify/combine/defer/delay JS) qui casse l’ordre d’exécution ou supprime une dépendance.
- Cache page / CDN sur checkout/cart/my-account (nonces périmés, fragments incohérents).
- WAF / ModSecurity qui bloque
?wc-ajax=checkout(faux positif sur payload). - Fatal PHP dans un plugin de paiement/livraison, ou snippet qui appelle Woo trop tôt.
- Templates checkout surchargés (thème enfant / builder) obsolètes ou hooks manquants.
- Permaliens / réécriture ou règles serveur qui redirigent mal (HTTP↔HTTPS, trailing slash, langues).
- Problèmes “edge” : objet cache persistant mal configuré, headers cookies cassés, limite mémoire, timeouts.
Prérequis avant de commencer
- Sauvegarde (fichiers + base) et idéalement un staging. Ne testez pas des snippets au hasard en production.
- Versions : WordPress 6.9.4 (votre contexte), PHP 8.1+ (recommandé), WooCommerce à jour.
- Activer les logs côté WordPress :
/** Activer le debug en environnement de test */
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false ); // Évitez d'afficher les erreurs aux clients
define( 'SCRIPT_DEBUG', true ); // Charge les versions non minifiées quand dispo
- Outils :
- Query Monitor (voir requêtes, hooks, erreurs PHP, appels AJAX).
- Health Check & Troubleshooting (mode dépannage sans impacter les visiteurs).
- Accès aux logs PHP/serveur (error_log, nginx/apache) et à la console navigateur.
Sources officielles utiles pendant le diagnostic :
- Debugging in WordPress
- wp_enqueue_script()
- REST API Handbook
- Code source WordPress (GitHub mirror)
- PHP error reporting (php.net)
Solution 1 : Corriger un checkout bloqué par une erreur JavaScript/AJAX (wc-ajax)
Quand le checkout “ne fait rien”, je commence presque toujours par l’onglet Console puis Réseau. Si l’appel ?wc-ajax=checkout ne part pas, ou part mais revient en 500/403, vous avez votre piste.
Diagnostic concret (2 minutes)
- Ouvrez la page checkout en navigation privée.
- F12 → Console : notez la première erreur (pas la dixième).
- F12 → Réseau → filtrez “wc-ajax”.
- Cliquez “Commander” et observez :
- statut HTTP (200/302/400/403/500)
- réponse (JSON d’erreur, HTML, page de firewall)
Cas typique : un script personnalisé “trop tôt” casse WooCommerce
J’ai souvent vu un snippet qui manipule le checkout sans déclarer les dépendances JS, ce qui casse l’ordre de chargement quand un plugin de perf “diffère” des scripts.
AVANT (cassé) : enqueue sans dépendances + exécution globale
add_action( 'wp_enqueue_scripts', function () {
// Mauvaise pratique : pas de dépendances, pas de condition checkout
wp_enqueue_script(
'mon-checkout',
get_stylesheet_directory_uri() . '/assets/checkout.js',
[],
'1.0.0',
true
);
} );
// Mauvaise pratique : suppose que jQuery et wc_checkout_params existent toujours
jQuery(function ($) {
$(document.body).on('click', '#place_order', function () {
console.log(wc_checkout_params.checkout_url);
});
});
Ce code “marche” parfois… jusqu’au jour où un plugin de cache diffère jQuery, ou où WooCommerce charge ses paramètres différemment selon le contexte. Résultat : jQuery is not defined ou wc_checkout_params is undefined, et le checkout peut ne plus soumettre.
APRÈS (corrigé) : dépendances + condition + garde-fous
add_action( 'wp_enqueue_scripts', function () {
// Ne chargez ce script que sur le checkout pour limiter les conflits
if ( function_exists( 'is_checkout' ) && is_checkout() ) {
wp_enqueue_script(
'mon-checkout',
get_stylesheet_directory_uri() . '/assets/checkout.js',
[ 'jquery', 'wc-checkout' ], // Dépendances explicites
'1.0.1',
true
);
}
}, 20 );
jQuery(function ($) {
// Garde-fou : si WooCommerce n'a pas initialisé ses paramètres, on n'exécute pas
if (typeof window.wc_checkout_params === 'undefined') {
console.warn('wc_checkout_params absent : un plugin de cache/minification a peut-être modifié l’ordre de chargement.');
return;
}
// Exemple : écoute d’événement WooCommerce plutôt que de surcharger le submit
$(document.body).on('updated_checkout', function () {
// Ici votre logique, sans bloquer le flux natif
});
});
Pourquoi ça corrige
- Dépendances :
wc-checkoutest chargé avant votre script, donc les variables et handlers existent. - Condition : vous évitez d’impacter d’autres pages (où Woo ne charge pas les mêmes assets).
- Garde-fou : en cas d’optimisation agressive, vous loggez un indice au lieu de casser le submit.
Variante : l’appel AJAX renvoie 500 (fatal PHP)
Si /?wc-ajax=checkout renvoie 500, cherchez une fatal PHP dans wp-content/debug.log ou dans les logs PHP-FPM. Une erreur fréquente : un snippet appelle WooCommerce trop tôt.
AVANT (cassé) : appel à wc() avant que Woo soit chargé
add_action( 'init', function () {
// Mauvais : sur certains contextes (AJAX tôt / ordre de chargement), wc() peut ne pas être dispo
$currency = wc()->currency->get_currency();
error_log( 'Devise: ' . $currency );
} );
APRÈS (corrigé) : attendre le bon moment + vérifier la présence
add_action( 'woocommerce_init', function () {
// Correct : WooCommerce est initialisé
if ( function_exists( 'wc' ) && wc() && isset( wc()->currency ) ) {
$currency = wc()->currency->get_currency();
error_log( 'Devise: ' . $currency );
}
} );
Pourquoi : quand WooCommerce traite un endpoint wc-ajax, l’ordre d’initialisation peut exposer les snippets “trop tôt”. En vous accrochant à woocommerce_init, vous réduisez drastiquement les fatals intermittentes.
Compatibilité Divi 5 / Elementor / Avada
- Divi 5 : évitez d’injecter du JS inline via un module Code sur la page checkout. J’ai vu des erreurs de scope et d’ordre de chargement. Préférez un enqueue propre (ci-dessus).
- Elementor : si vous utilisez le template Checkout (WooCommerce), désactivez les optimisations “Improved Asset Loading”/expériences qui retardent jQuery sur checkout, ou excluez cette page.
- Avada : Fusion Builder + options perf peuvent combiner/différer. Excluez checkout des optimisations JS si vous voyez des erreurs
wc_checkout_params.
Solution 2 : Éliminer les problèmes de cache/CDN qui cassent les nonces et les fragments
Un checkout mis en cache, c’est souvent un checkout mort. Le symptôme typique : “Invalid nonce”, panier qui se vide, ou paiement qui échoue uniquement pour certains visiteurs (selon POP CDN / cookies).
Ce qui se passe en coulisses
Le checkout contient des nonces et des champs dynamiques. Si un cache page sert une version HTML générée pour un autre utilisateur (ou trop ancienne), WooCommerce reçoit un nonce périmé et refuse l’action. Même chose si votre CDN ignore certains cookies WooCommerce.
Diagnostic
- Testez checkout avec cache bypass :
- désactivez temporairement le cache page (plugin + cache serveur si possible)
- désactivez “Rocket Loader”/optimisations JS côté CDN
- Comparez les en-têtes :
Cache-Control,CF-Cache-Status,X-Cachesur/checkout/
- Vérifiez si
/checkout/est servi depuis le cache malgré un panier non vide.
Correctif : envoyer des headers no-cache sur checkout/cart/my-account
WooCommerce gère déjà beaucoup de cas, mais sur certains stacks (reverse proxy agressif, règles custom), forcer des headers aide. Attention : ce n’est pas une excuse pour laisser un plugin de cache mettre en cache checkout. C’est un filet de sécurité.
AVANT (cassé) : règles de cache globales
add_action( 'send_headers', function () {
// Mauvais : forcer un cache public partout, y compris checkout
header( 'Cache-Control: public, max-age=3600' );
} );
APRÈS (corrigé) : no-cache ciblé WooCommerce
add_action( 'send_headers', function () {
if ( is_admin() ) {
return;
}
// Sur les pages sensibles WooCommerce, on empêche le cache navigateur/proxy
if ( function_exists( 'is_checkout' ) && ( is_checkout() || is_cart() || is_account_page() ) ) {
header( 'Cache-Control: no-store, no-cache, must-revalidate, max-age=0' );
header( 'Pragma: no-cache' );
header( 'Expires: Wed, 11 Jan 1984 05:00:00 GMT' );
}
}, 20 );
Pourquoi : vous réduisez les cas où un proxy/CDN “s’entête” à mettre en cache une page dynamique.
Correctif : exclure checkout des optimisations JS (pratique)
La plupart des plugins de perf permettent des exclusions par URL. Ciblez au minimum :
/checkout//cart//my-account/?wc-ajax=*(si votre outil touche aux requêtes)
Dans mon expérience, le combo le plus destructeur est : “Delay JS execution” + “Combine JS” + “Remove jQuery Migrate” (selon site) appliqué au checkout. Vous gagnez 100 ms et vous perdez des commandes.
Note sécurité
Un cache mal configuré peut exposer des données (adresse, email) si une page compte est mise en cache. Vérifiez vos règles. Si vous suspectez une fuite, purgez les caches et auditez immédiatement.
Solution 3 : Réparer les endpoints (REST / wc-ajax / permaliens) et traquer les 403/404 côté serveur
Quand la console montre des 403/404 sur ?wc-ajax=... ou /wp-json/, le problème n’est plus WooCommerce “en lui-même”. C’est votre serveur (WAF, règles, permaliens, redirections) qui bloque.
Test rapide des endpoints
Depuis votre navigateur (connecté/déconnecté), testez :
https://votre-site.tld/?wc-ajax=get_refreshed_fragmentshttps://votre-site.tld/?wc-ajax=update_order_review(peut exiger POST en situation réelle)https://votre-site.tld/wp-json/
Et via WP-CLI (utile pour vérifier la santé globale WordPress) :
wp core version
wp plugin list --status=active
wp option get permalink_structure
Cas 1 : permaliens cassés / redirections incohérentes
Un classique après migration : redirection HTTP→HTTPS ou ajout/retrait de “www” via plusieurs couches (WordPress + plugin + serveur + CDN). Les endpoints AJAX se retrouvent redirigés (302) vers une page HTML, et WooCommerce n’arrive plus à parser la réponse.
Vérification :
- Onglet Réseau : l’appel
?wc-ajax=checkoutreçoit un 302 vers une page de login, une page 404, ou une page “consentement cookies”. - La réponse contient du HTML au lieu du JSON attendu.
Correctif : unifier l’URL du site et réduire les redirections. Vérifiez :
- Réglages > Général : “Adresse web de WordPress” et “Adresse web du site”
- Règles serveur (nginx/apache) et CDN
Si vous avez un code de redirection custom, évitez de toucher aux requêtes AJAX WooCommerce.
AVANT (cassé) : redirection globale naïve
add_action( 'template_redirect', function () {
// Mauvais : redirige aussi les endpoints wc-ajax et casse les réponses
if ( ! is_ssl() ) {
wp_safe_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], 301 );
exit;
}
} );
APRÈS (corrigé) : exclure wc-ajax et admin-ajax
add_action( 'template_redirect', function () {
// On ne redirige pas dans l'admin
if ( is_admin() ) {
return;
}
// On évite de casser les endpoints AJAX WooCommerce
if ( isset( $_GET['wc-ajax'] ) || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
return;
}
if ( ! is_ssl() ) {
$host = isset( $_SERVER['HTTP_HOST'] ) ? $_SERVER['HTTP_HOST'] : '';
$uri = isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : '/';
wp_safe_redirect( 'https://' . $host . $uri, 301 );
exit;
}
}, 1 );
Pourquoi : WooCommerce attend une réponse précise sur wc-ajax. Une redirection 301/302 transforme l’appel en autre chose, et le checkout se bloque.
Cas 2 : WAF/ModSecurity bloque ?wc-ajax=checkout
Si vous voyez un 403 uniquement sur wc-ajax, cherchez une signature ModSecurity dans les logs. J’ai vu des faux positifs sur des champs adresse (ex: “Rue de l’Union”) ou des notes de commande.
Correctifs possibles (du plus propre au plus “bricolage”) :
- Whitelister l’URL ou la règle ModSecurity côté hébergeur (recommandé).
- Configurer votre WAF/CDN pour ne pas inspecter agressivement
/checkout/et?wc-ajax=checkout. - Si vous contrôlez nginx/apache, ajouter une exception ModSecurity sur cette route (dépend de votre stack).
Je ne vous donne pas une règle serveur “universelle” ici, parce que ModSecurity varie selon hébergeur. Mais le diagnostic est stable : 403 + log ModSecurity + endpoint Woo = faux positif à lever.
Cas 3 : REST API bloquée (plugins sécurité)
Certaines extensions de sécurité bloquent /wp-json/ aux visiteurs non connectés. Ça peut casser des moyens de paiement, des blocs WooCommerce, ou des intégrations.
Vérification : /wp-json/ doit répondre 200 (ou au moins ne pas être 403) publiquement. WordPress documente la REST API ici : REST API Handbook.
Correctif : ajustez le plugin de sécurité pour autoriser les routes nécessaires. Si vous avez du code custom qui filtre rest_authentication_errors, testez-le avec Query Monitor et retirez les blocages globaux.
Vérifications après correction
- Test fonctionnel :
- Produit simple → ajout panier → checkout → paiement (idéalement un moyen “test”)
- Produit avec livraison → changement d’adresse → recalcul OK
- Console : zéro erreur JS sur checkout.
- Réseau :
?wc-ajax=update_order_reviewrépond 200?wc-ajax=checkoutrépond 200 et retourne une réponse attendue (pas une page HTML de firewall)
- Logs :
- plus de fatal dans
wp-content/debug.log - plus de 403 WAF sur les endpoints
- plus de fatal dans
- Cache : vérifiez que checkout/cart/my-account ne sont pas mis en cache (en-têtes + outil cache).
Si ça ne marche toujours pas
Voici une procédure que j’applique quand le bug est “glissant” (ça marche parfois, parfois non) :
1) Isoler conflit plugin/thème sans casser la prod
- Installez Health Check & Troubleshooting.
- Activez le mode dépannage pour votre session admin.
- Désactivez tout sauf WooCommerce + le plugin de paiement concerné.
- Testez checkout en navigation privée.
Si ça remarche : réactivez les plugins un par un. Les coupables fréquents : cache/optimisation, sécurité, traduction, champs checkout, anti-spam agressif.
2) Vérifier mémoire, timeouts, et fatals silencieuses
- Regardez
debug.loget logs PHP-FPM. - Avec Query Monitor, inspectez l’onglet “PHP Errors”.
- Si vous voyez des erreurs “Allowed memory size exhausted”, augmentez la mémoire côté PHP et côté WP (
WP_MEMORY_LIMIT), puis retestez.
3) Vérifier la console + sourcemaps (SCRIPT_DEBUG)
Avec SCRIPT_DEBUG, vous obtenez souvent des fichiers non minifiés, donc des stack traces exploitables. Ça accélère énormément l’identification d’un script tiers qui pollue le scope global.
4) Vérifier les règles de réécriture
- Admin → Réglages → Permaliens → Enregistrer (sans changer) pour régénérer.
- WP-CLI :
wp rewrite flush --hard
Si vous avez un reverse proxy, assurez-vous qu’il ne réécrit pas ? ou ne supprime pas des query strings (ça casse wc-ajax).
5) Vérifier les permissions fichiers (cas rares mais réels)
Si des fichiers JS/CSS WooCommerce ne sont pas servis (403/404), le checkout casse. Vérifiez que votre serveur sert bien /wp-content/plugins/woocommerce/assets/. Sur certains hébergements durcis, des règles bloquent .map ou certains types MIME.
6) Tester sans builder
Divi/Elementor/Avada peuvent surcharger la page checkout via templates. Pour trancher :
- Créez une page “Checkout test” avec uniquement le bloc/shortcode WooCommerce natif (sans mise en page complexe).
- Assignez-la temporairement comme page de commande (WooCommerce → Réglages → Avancé).
- Retestez.
Pièges et erreurs courantes
| Symptôme | Cause probable | Solution recommandée |
|---|---|---|
| Le checkout marche admin connecté, pas pour les clients | Cache/CDN varie selon cookies | Solution 2 : exclusions cache + vérifier cookies Woo |
| “Uncaught TypeError … wc_checkout_params” | Script chargé avant wc-checkout ou minification/delay |
Solution 1 : dépendances + exclure optimisation |
500 sur ?wc-ajax=checkout |
Fatal PHP dans plugin/snippet | WP_DEBUG_LOG + corriger hook (woocommerce_init) |
| 403 ModSecurity | WAF faux positif | Solution 3 : whitelist règle/URL |
| Checkout cassé après “copier-coller” d’un snippet | Code collé au mauvais endroit / point-virgule manquant | Revenir en arrière, valider syntaxe, utiliser un plugin de snippets fiable |
| Plus de frais de port / total incorrect | AJAX update_order_review bloqué |
Console + réseau, désactiver conflit, vérifier 200 |
| Le CSS/JS Woo ne se charge pas | Mauvais enqueue, blocage serveur, concat agressive | Vérifier 200 sur assets, exclure Woo des optimisations |
Erreurs que je vois souvent chez des utilisateurs intermédiaires
- Copier le code dans le mauvais fichier (ex: dans un template WooCommerce au lieu de
functions.phpou d’un plugin mu). - Oublier une parenthèse et provoquer une fatal qui n’apparaît pas à l’écran (car
WP_DEBUG_DISPLAYest àfalse). - Utiliser un hook inadapté (
initau lieu dewoocommerce_init) et déclencher des bugs intermittents sur AJAX. - Confondre action et filtre : retourner une valeur dans une action ne sert à rien, et vous pensez avoir “bloqué” un comportement.
- Tester sur production sans staging : vous découvrez le bug quand les clients payent.
- Oublier de vider le cache navigateur/CDN après correction : vous retestez sur une version cassée.
Variante / alternative
Méthode sans code (plugins/outils)
- Health Check pour isoler le conflit sans impacter les visiteurs.
- Query Monitor pour voir les erreurs PHP, requêtes lentes, et appels AJAX.
- Si vous utilisez un plugin de cache : appliquez la configuration “WooCommerce safe” (exclusions checkout/cart/account, désactivation delay JS sur checkout).
Méthode plus avancée (développeurs) : journaliser précisément les appels checkout
Quand le problème est rare (1 commande sur 30), je journalise l’état du contexte sur les endpoints WooCommerce. Le but : savoir si c’est un 403 WAF, une fatal, ou une validation qui bloque.
Exemple minimaliste : loggez les requêtes wc-ajax côté WordPress (attention à ne pas logguer de données sensibles en clair).
add_action( 'init', function () {
// Journalisation légère : ne stockez pas de données personnelles
if ( isset( $_GET['wc-ajax'] ) ) {
$action = sanitize_key( wp_unslash( $_GET['wc-ajax'] ) );
// Évitez de logger des payloads complets (adresse, email, etc.)
error_log( '[wc-ajax] action=' . $action . ' ip=' . ( $_SERVER['REMOTE_ADDR'] ?? 'unknown' ) );
}
}, 1 );
Pourquoi : si vous voyez le log WordPress mais un 403 côté navigateur, c’est souvent un cache/CDN entre les deux. Si vous ne voyez même pas le log, la requête n’atteint pas WordPress (WAF/serveur).
Éviter ce problème à l’avenir
- Excluez systématiquement checkout/cart/my-account de :
- cache page
- optimisations JS agressives (delay/defer/combine) sauf test strict
- règles WAF trop strictes
- Chargez vos scripts proprement :
- dépendances explicites (
jquery,wc-checkout) - conditions
is_checkout()
- dépendances explicites (
- Évitez les redirections “globales” en PHP qui touchent les endpoints AJAX. Si vous devez rediriger, excluez
DOING_AJAXetwc-ajax. - Surveillez les logs après mise à jour WooCommerce/paiement. Une fatal sur AJAX peut passer inaperçue si vous ne regardez pas
debug.log. - Gardez les surcharges de templates WooCommerce sous contrôle : si vous copiez des templates dans un thème enfant, ré-auditez-les après mises à jour WooCommerce. (C’est une source récurrente de checkout “bizarre”.)
Ressources
- developer.wordpress.org — Debugging in WordPress
- developer.wordpress.org — wp_enqueue_script()
- developer.wordpress.org — REST API Handbook
- wordpress.org — Query Monitor
- wordpress.org — Health Check & Troubleshooting
- github.com/WordPress — WordPress core mirror
- core.trac.wordpress.org — Tickets WordPress Core
- php.net — Error handling and logging
Questions fréquentes
Pourquoi le checkout fonctionne sur mon compte admin mais pas pour les visiteurs ?
Parce que le cache/CDN applique souvent des règles différentes selon cookies (utilisateur connecté vs non). Excluez checkout/cart/account du cache page et retestez en navigation privée.
J’ai un 500 sur /?wc-ajax=checkout, mais la page checkout s’affiche. C’est possible ?
Oui. La page HTML peut se charger, mais l’action “Commander” déclenche un endpoint AJAX qui plante sur une fatal PHP. Regardez wp-content/debug.log et les logs serveur.
Est-ce que je peux “forcer” WooCommerce à ne pas utiliser AJAX ?
Techniquement vous pouvez contourner certains comportements, mais c’est rarement une bonne idée : vous risquez de casser des moyens de paiement et la validation. Mieux vaut corriger la cause (JS/caching/WAF).
Un plugin de minification peut-il casser uniquement le checkout ?
Oui, parce que checkout dépend d’un ordre de scripts précis et de variables localisées. Une combinaison/différage peut changer l’ordre ou supprimer une dépendance, sans impacter les pages simples.
Que faire si ModSecurity bloque des commandes aléatoirement ?
Collectez l’heure, l’IP, l’URL et le code d’erreur, puis demandez à l’hébergeur la règle déclenchée. La solution propre est la whitelist ciblée (URL/règle), pas la désactivation globale du WAF.
Elementor/Divi/Avada sont-ils “responsables” du bug ?
Pas directement, mais leurs options de performance et leurs templates peuvent modifier le chargement d’assets ou la structure de la page checkout. Le test “page checkout minimale” permet de trancher rapidement.
Pourquoi j’obtiens “Invalid nonce” après une mise à jour ?
Souvent parce que votre cache sert une ancienne version du checkout. Purgez cache plugin + cache serveur + CDN, puis mettez en place des exclusions durables.
Dois-je activer WP_DEBUG en production pour diagnostiquer ?
Évitez. Faites-le sur staging. Si vous n’avez pas le choix, activez WP_DEBUG_LOG et gardez WP_DEBUG_DISPLAY à false pour ne pas exposer d’informations sensibles.
Le checkout renvoie du HTML au lieu de JSON dans la réponse AJAX : c’est grave ?
C’est un indicateur fort de redirection (HTTPS, cookies, page de sécurité) ou d’erreur interceptée par un proxy/WAF. Inspectez l’onglet Réseau et corrigez la couche qui injecte ce HTML.