Quand un paiement WooCommerce casse, ce n’est pas une panne « à moitié ». C’est une explosion de revenus, de tickets support et de votre confiance dans la réalité. Les clients voient des spinners, des pages blanches, « Une erreur est survenue lors du traitement de votre commande », ou le classique : rien ne se passe quand ils cliquent sur Passer la commande.
Le truc est d’arrêter de deviner. Le checkout est une chaîne : navigateur → thème/JS → AJAX WooCommerce → WordPress/PHP → base de données → passerelle de paiement → callbacks webhook → emails/mise à jour du stock. Un maillon faible et tout ressemble à « paiement en panne ». Trouvons le maillon.
Feuille de route pour diagnostic rapide
Si vous êtes de permanence en ce moment, commencez ici. C’est la séquence avec le meilleur rapport signal/bruit pour trouver rapidement le goulot d’étranglement.
1) Confirmez que c’est réel et délimité
- Faites un checkout en navigation privée avec un produit à faible valeur. Notez le symptôme exact : spinner, redirection, erreur de passerelle, page blanche, ou commande créée mais paiement échoué.
- Testez depuis un autre réseau (hotspot mobile). Si ça marche là-bas, suspectez un DNS/WAF/caching d’entreprise bizarre sur le premier réseau.
- Vérifiez dans un autre navigateur. Si seul Safari échoue, vous avez probablement affaire à des règles de cookies cross-site, des paiements en iframe ou une prévention de tracking agressive.
2) Regardez la console et l’onglet réseau avant de toucher le serveur
- Ouvrez DevTools → Console pour les erreurs JS.
- DevTools → Network → filtrez sur
?wc-ajax=checkout,admin-ajax.phpet les endpoints de passerelle. Surveillez les codes d’état et le corps des réponses.
3) Vérifiez les logs WooCommerce (ils sont ennuyeux, donc utiles)
- WooCommerce → État → Logs. Cherchez les logs de passerelle, erreurs fatales, échecs de webhook.
- Le log de debug WordPress et le log d’erreurs PHP-FPM si vous gérez le serveur.
4) Décidez dans quelle voie vous êtes
La plupart des pannes de checkout tombent dans une de ces voies :
- SSL/HTTPS ou cookies : boucles de redirection, contenu mixte, « nonce invalide », spinner infini.
- Passerelle/API : Stripe/PayPal qui échouent, webhooks non reçus, problèmes 3DS.
- Plugins/thème/cache : JS cassé, AJAX bloqué, pages de checkout mises en cache.
- Limites serveur : timeouts, erreurs mémoire, BD lente, disque plein, CPU saturé.
5) Appliquez les mitigations rapides les plus sûres
- Désactivez le cache full-page pour
/cart/,/checkout/,/my-account/et tous les endpoints?wc-ajax=. - Basculez temporairement vers un thème par défaut et désactivez les plugins non essentiels sur une copie de staging (ou utilisez une approche « désactiver uniquement sur le checkout » si vous devez le faire en production).
- Revenez en arrière sur le dernier changement : mise à jour de plugin, mise à jour de thème, règle CDN/WAF, upgrade PHP. Les ruptures de checkout adorent les changements récents.
Carte des pannes de checkout : où ça casse et à quoi ça ressemble
Couche navigateur et JavaScript
Symptômes : le bouton Passer la commande ne fait rien, spinner infini, champs qui ne valident pas, élément de paiement qui ne se charge pas.
Causes typiques : minification JS ratée, blocage de contenu mixte, thème qui surcharge les templates de checkout, scripts de passerelle obsolètes, règles CSP, ou scripts injectés par un plugin provoquant des erreurs de syntaxe.
Couche AJAX / REST de WooCommerce
Symptômes : 400 ou 403 sur ?wc-ajax=checkout, « nonce invalide », session perdue, panier vidé au rafraîchissement.
Causes typiques : cache, cookies bloqués, règle WAF côté serveur, mise en cache en edge Cloudflare, ou URL site/HTTPS mal configurées.
Couche WordPress / PHP
Symptômes : HTTP 500, page blanche, « erreur critique », échecs aléatoires sous charge.
Causes typiques : erreurs fatales PHP, limite mémoire trop basse, problèmes d’opcode cache, versions de plugins incompatibles, ou épuisement des workers PHP-FPM.
Couche base de données et stockage
Symptômes : le checkout marche parfois mais devient lent ; commandes créées avec métadonnées manquantes ; deadlocks ; « erreur base de données » intermittente.
Causes typiques : requêtes MySQL lentes, IO saturée, disque plein, index manquants, ou jobs en arrière-plan lourds qui concurrencent les écritures du checkout.
Couche passerelle et webhook
Symptômes : commande bloquée « en attente de paiement », paiement capturé mais commande non marquée comme payée, client débité mais pas d’email de commande, remboursements échouant.
Causes typiques : webhooks non délivrés, secret de webhook incorrect, requêtes entrantes bloquées, clés API pointant vers le mauvais environnement, flux 3DS bloqués, ou dérive d’horloge serveur qui casse les signatures.
Faits intéressants et court historique (oui, ça compte)
- WooCommerce a commencé comme plugin eCommerce de WooThemes et a ensuite été acquis par Automattic ; c’est pourquoi les conventions WordPress imprègnent tout, pour le meilleur et pour le pire.
- Le checkout utilise un mélange d’admin-ajax classique et d’endpoints AJAX propres à WooCommerce ; des hypothèses de sécurité et de cache différentes s’appliquent selon la route utilisée.
- Les « nonces » dans WordPress ne sont pas des nonces cryptographiques ; ce sont des tokens liés à une fenêtre temporelle et aux sessions. Si des caches ou des proxies rejouent des pages, les nonces pourrissent.
- La pression de conformité PCI explique pourquoi de nombreuses passerelles ont déplacé la saisie des cartes dans des champs hébergés (iframes/elements). Cela rend les checkouts modernes sensibles au CSP, au contenu mixte et aux règles de cookies tiers.
- Les flux 3-D Secure (3DS) sont devenus beaucoup plus fréquents après les règles SCA en Europe ; les passerelles exigent maintenant des étapes navigateur supplémentaires qui cassent facilement quand JS ou les redirections sont perturbés.
- HSTS peut faire mentir le « ça marche sur ma machine » ; une fois qu’un navigateur met en cache HSTS, il forcera HTTPS même si vous cassez HTTPS plus tard.
- Beaucoup de « problèmes de checkout » sont en réalité des bugs de cache : mettre en cache une page personnalisée revient à photocopier le passeport de quelqu’un et le donner au client suivant.
- Les retries de webhook ne sont pas infinies. Si votre serveur bloque les callbacks de la passerelle pendant des heures, vous réconcilierez manuellement les paiements plus tard.
- Les WAF Cloud bloquent de plus en plus par défaut les POST « suspects » ; les formulaires de checkout sont un buffet de champs qui peuvent déclencher des règles.
SSL et HTTPS : contenu mixte, HSTS et boucles de redirection
Comment le SSL casse spécifiquement le checkout
Les problèmes SSL n’apparaissent que rarement sous la forme d’une bannière « SSL cassé ». À la place, vous avez des effets secondaires :
- Les widgets de paiement ne se chargent pas parce qu’un script est servi en HTTP (contenu mixte bloqué).
- Les cookies ne sont pas définis parce que vous basculez entre HTTP et HTTPS, ou entre
wwwet le domaine apex. - La validation des nonces échoue car du contenu mis en cache est servi entre différents schémas.
- Boucles de redirection parce que WordPress pense que l’URL du site est en HTTP mais le proxy termine TLS, ou inversement.
Contenu mixte : le tueur silencieux du checkout
Les navigateurs modernes bloquent les ressources non sécurisées sur des pages sécurisées. Vous le verrez dans la console comme « Mixed Content: The page was loaded over HTTPS, but requested an insecure resource. » Quand cette ressource non sécurisée est le JS de votre passerelle ou un script de validation du checkout, le checkout devient une danse interprétative.
Reverse proxies et « is_ssl() » qui vous mentent
Si vous êtes derrière un load balancer ou un CDN qui termine TLS, le serveur d’origine peut voir seulement du HTTP. WordPress génère alors des URLs HTTP, définit mal les cookies et conditionne des comportements sécurisés sur un mauvais signal.
La correction consiste généralement à s’assurer que le proxy définit X-Forwarded-Proto: https, et que WordPress est configuré pour lui faire confiance (souvent via la pile d’hébergement). Ne « corrigez » pas cela en codant des redirections en dur à cinq endroits. C’est comme ça que vous obtenez des boucles qui n’arrivent que le mardi.
Deux règles précises
- Règle 1 : les pages de checkout et compte doivent être constamment en HTTPS avec un seul nom d’hôte canonique.
- Règle 2 : ne mettez jamais en cache des pages contenant des nonces, des paniers, des sessions ou des fragments personnalisés.
Paiements : passerelles, webhooks, 3DS et « commande en attente pour toujours »
Les deux moitiés de « paiement réussi »
Un paiement réussi est généralement composé de deux événements :
- Le client termine le flux sur le site (tokenisation/autorisation/capture).
- La passerelle envoie un webhook serveur-à-serveur confirmant l’état final.
Si le n°1 fonctionne mais que le n°2 échoue, vous obtenez le cauchemar : les clients sont débités, mais les commandes restent en « en attente de paiement » ou « en attente ». Ce n’est pas un « problème de passerelle ». C’est un problème de fiabilité d’intégration, et c’est à vous de le résoudre.
Stripe : points de rupture courants
- Désaccord sur le secret du webhook : les événements arrivent mais échouent à la validation de signature.
- Mauvaises clés API : site en production utilisant des clés de test ou inversement ; parfois seuls certains clients déclenchent des échecs selon le moyen de paiement.
- Modal 3DS bloqué : CSP agressif, JS cassé, ou interférence d’un plugin d’optimisation.
PayPal : points de rupture courants
- Problèmes d’URL de retour : schéma/hôte mismatched entraînant un échec du retour depuis PayPal ou une boucle vers le panier.
- IPN/webhook bloqué : callbacks entrants bloqués par firewall, WAF, ou DNS mal routé.
Blague #1 : Une intégration de passerelle de paiement, c’est comme une amitié : ça va bien jusqu’à ce que quelqu’un arrête de vous rappeler, et là tout devient « en attente ».
Dérive d’horloge : une panne de checkout étonnamment réelle
Les payloads signés de webhook et l’authentification API peuvent échouer quand l’horloge serveur dérive. Si NTP est cassé, votre pipeline de commandes devient quantique : payé et non payé en même temps.
Conflits de plugins et de thèmes : les assassins silencieux
Pourquoi le checkout attire les conflits
Les pages de checkout sont l’endroit où chaque plugin veut avoir son moment de gloire : analytics, pixel tracking, upsells, multi-devises, validation d’adresse, cache, sécurité, consentement cookie, « améliorer les conversions », « améliorer la performance », « améliorer le bonheur ». La plupart injectent des scripts et filtrent la sortie. Il suffit d’un mauvais acteur pour casser tout le runtime.
Comment penser les conflits
- Conflits JS : un script lance une exception, le reste du JS de checkout cesse de s’exécuter.
- Overrides de template : les thèmes qui remplacent les templates de checkout WooCommerce peuvent être obsolètes par rapport à votre version de WooCommerce.
- Hooks de validation : des plugins ajoutent des champs de checkout personnalisés mais ne gèrent pas les cas limites, provoquant des échecs de validation.
- Plugins de sécurité : bloquent les endpoints AJAX, les requêtes REST, ou les corps POST.
Arrêtez « d’optimiser » le checkout avec la roulette minify/bundle
Les plugins de minification qui concatènent les scripts peuvent casser les champs hébergés des passerelles et les fragments de checkout. Si vous ne pouvez pas expliquer le graphe de dépendances, ne laissez pas un plugin l’« auto-optimiser ».
Cache, CDN et règles WAF qui sabotent le checkout
Ce qui ne doit jamais être mis en cache
/cart/,/checkout/,/my-account/- Toute URL avec
add-to-cart=,wc-ajax=ou des paramètres de requête porteurs de session - Réponses qui définissent des cookies comme
woocommerce_cart_hash,woocommerce_items_in_cart,wp_woocommerce_session_*
Pièges des CDN
Les CDN sont formidables jusqu’à ce qu’ils décident que votre checkout est « statique ». Alors les clients partagent les sessions comme un jardin communautaire. Aussi : les règles WAF managées signalent parfois les POST de checkout comme injection SQL parce que les adresses et les noms ressemblent à des saisies utilisateur (parce que c’en sont).
En-têtes de sécurité : bonnes intentions, paiements cassés
Content Security Policy (CSP) et les réglages SameSite des cookies peuvent casser les flux de paiement tiers. Vous pouvez tout à fait utiliser CSP ; ne le faites pas en devinant. Commencez par le mode report-only, capturez les violations, puis resserrez.
Blague #2 : La seule chose plus confiante qu’un WAF est un plugin marketing qui « garantit » des conversions plus rapides.
Échecs côté serveur : PHP, BD, disque et timeouts
Le checkout est une requête lourde en écritures : il crée une commande, met à jour le stock, stocke des métadonnées, parle peut-être à une passerelle, déclenche peut-être des APIs taxes/livraison, puis envoie des emails. C’est beaucoup de pièces mobiles dans une seule requête HTTP.
PHP-FPM et épuisement des workers
Quand PHP-FPM n’a plus de workers, les requêtes font la queue. Le checkout expire, les navigateurs retentent, et vous créez des commandes en double. C’est comme ça qu’on se réveille avec « pourquoi avons-nous 200 commandes en attente ? »
Performance et verrouillage de la base de données
WooCommerce stocke beaucoup de données dans les tables post et meta. Sous charge, des requêtes mal indexées et la contention de locks peuvent rendre le checkout lent et instable. Si vous voyez des pics de CPU BD ou des slow query logs remplis de requêtes meta, vous n’avez pas besoin de « plus de cache ». Vous devez corriger la charge sur la base.
Disque plein : la panne la plus embarrassante
Si le disque se remplit, PHP ne peut plus écrire de sessions, de logs ni de fichiers temporaires ; MySQL ne peut pas flush ; et WordPress commence à échouer de manières créatives. Les problèmes de stockage n’annoncent que rarement poliment leur arrivée.
Une citation de fiabilité (idée paraphrasée)
« L’espoir n’est pas une stratégie. » — idée souvent paraphrasée attribuée à des responsables opérationnels chevronnés. Dans le monde du checkout, vous vérifiez avec des logs et des traces, sinon vous improvisez.
Tâches de diagnostic pratiques (commandes + sortie + décisions)
Voici des tâches réelles que vous pouvez exécuter sur un hôte Linux type avec Nginx/Apache, PHP-FPM et MySQL/MariaDB. Servez-vous-en pour passer de « checkout cassé » à « ce composant précis échoue ». Chaque tâche inclut : la commande, un exemple de sortie, et la décision à prendre.
Task 1: Confirm DNS and TLS are sane from the server
cr0x@server:~$ dig +short A example-shop.com
203.0.113.10
cr0x@server:~$ echo | openssl s_client -servername example-shop.com -connect example-shop.com:443 2>/dev/null | openssl x509 -noout -subject -issuer -dates
subject=CN = example-shop.com
issuer=CN = R3, O = Let's Encrypt, C = US
notBefore=Nov 1 00:00:00 2025 GMT
notAfter=Jan 30 23:59:59 2026 GMT
Ce que ça signifie : le DNS pointe là où vous attendez et le certificat correspond au hostname avec des dates valides.
Décision : Si le CN/SAN ne correspond pas, corrigez le cert/virtual host. Si le DNS pointe vers une IP différente de votre origine, votre config CDN/load balancer peut être incorrecte.
Task 2: Detect redirect loops or HTTP→HTTPS confusion
cr0x@server:~$ curl -I -L -s -o /dev/null -w '%{url_effective} %{http_code} %{num_redirects}\n' http://example-shop.com/checkout/
https://example-shop.com/checkout/ 200 1
cr0x@server:~$ curl -I -s https://example-shop.com/checkout/ | egrep -i 'location:|set-cookie:|strict-transport-security'
strict-transport-security: max-age=31536000; includeSubDomains; preload
set-cookie: wp_woocommerce_session_123abc=...; path=/; secure; HttpOnly
Ce que ça signifie : Une redirection vers HTTPS est correcte. La présence de cookies Secure sur le checkout est bonne.
Décision : Si num_redirects est élevé ou si le statut indique une boucle 301/302, corrigez les options Site URL/Home URL de WordPress et les headers proxy avant de toucher les plugins.
Task 3: Find mixed content candidates in generated HTML
cr0x@server:~$ curl -s https://example-shop.com/checkout/ | egrep -o 'http://[^"]+' | head
http://example-shop.com/wp-content/plugins/some-plugin/js/tracker.js
http://fonts.example.net/somefont.woff2
Ce que ça signifie : le HTML du checkout référence des assets en HTTP ; les navigateurs peuvent les bloquer.
Décision : Corrigez les URLs HTTP codées en dur dans les réglages du thème/plugin, ou corrigez les URL WordPress et effectuez un remplacement de contenu approprié (avec précaution) si nécessaire.
Task 4: Watch Nginx/Apache logs for checkout requests in real time
cr0x@server:~$ sudo tail -f /var/log/nginx/access.log | egrep 'checkout|wc-ajax=checkout|admin-ajax.php'
203.0.113.55 - - [27/Dec/2025:11:02:13 +0000] "POST /?wc-ajax=checkout HTTP/2.0" 400 182 "-" "Mozilla/5.0"
203.0.113.55 - - [27/Dec/2025:11:02:13 +0000] "GET /checkout/ HTTP/2.0" 200 98234 "-" "Mozilla/5.0"
Ce que ça signifie : L’endpoint AJAX de checkout retourne 400. Ce n’est pas « un problème de thème » jusqu’à preuve du contraire.
Décision : Passez aux logs PHP/Woo pour voir l’erreur exacte (nonce, validation, réponse de passerelle).
Task 5: Inspect PHP-FPM health and worker pressure
cr0x@server:~$ sudo systemctl status php8.2-fpm --no-pager
● php8.2-fpm.service - The PHP 8.2 FastCGI Process Manager
Active: active (running) since Sat 2025-12-27 09:10:02 UTC; 1h 52min ago
cr0x@server:~$ sudo grep -i 'server reached pm.max_children' /var/log/php8.2-fpm.log | tail -3
[27-Dec-2025 10:59:01] WARNING: [pool www] server reached pm.max_children setting (20), consider raising it
Ce que ça signifie : PHP-FPM se sature. Sous charge, le checkout mettra en file ou expirera.
Décision : Augmentez pm.max_children seulement si CPU/RAM le permettent ; sinon réduisez la charge des plugins, ajoutez du cache pour les pages non-checkout, et corrigez les requêtes lentes.
Task 6: Locate PHP fatal errors triggered during checkout
cr0x@server:~$ sudo tail -n 80 /var/log/php8.2-fpm.log
[27-Dec-2025 11:02:13] PHP Fatal error: Uncaught Error: Call to undefined function wc_get_order() in /var/www/html/wp-content/plugins/custom-checkout/hooks.php:41
Stack trace:
#0 /var/www/html/wp-includes/class-wp-hook.php(324): custom_checkout_validate()
Ce que ça signifie : Un plugin appelle des fonctions WooCommerce incorrectement ou trop tôt, provoquant un fatal pendant le checkout.
Décision : Désactivez ou corrigez le plugin. Une erreur fatale n’est pas un « peut-être ». C’est un défaut bloquant.
Task 7: Confirm WordPress can write sessions and disk isn’t full
cr0x@server:~$ df -h / /var
Filesystem Size Used Avail Use% Mounted on
/dev/vda1 40G 39G 0.9G 98% /
cr0x@server:~$ sudo du -sh /var/log | tail -1
6.2G /var/log
Ce que ça signifie : Vous êtes presque à court de disque. Les bases et PHP vont échouer de manières étranges à 99–100%.
Décision : Libérez de l’espace immédiatement (rotation/compression des logs, suppression d’anciens backups), puis mettez en place de la surveillance/alertes. Un disque plein est un échec de politique, pas un mystère.
Task 8: Check MySQL availability and current load
cr0x@server:~$ mysqladmin -uroot -p ping
mysqld is alive
cr0x@server:~$ mysql -uroot -p -e "SHOW GLOBAL STATUS LIKE 'Threads_running';"
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| Threads_running | 58 |
+-----------------+-------+
Ce que ça signifie : MySQL est vivant, mais 58 threads en cours est souvent « on souffre » sur une petite instance.
Décision : Inspectez les requêtes lentes et les attentes de locks ; envisagez d’augmenter les ressources BD ou d’optimiser les requêtes/plugins qui génèrent de lourdes recherches meta.
Task 9: Identify slow queries during checkout window
cr0x@server:~$ sudo tail -n 20 /var/log/mysql/slow.log
# Time: 2025-12-27T11:02:13.123456Z
# Query_time: 3.812 Lock_time: 0.002 Rows_sent: 1 Rows_examined: 250000
SELECT post_id FROM wp_postmeta WHERE meta_key='_billing_email' AND meta_value='user@example.com';
Ce que ça signifie : Une requête meta scanne trop de lignes. Le checkout déclenche souvent ces recherches via des plugins (CRM, fraude, matching de compte).
Décision : Réduisez ou supprimez la fonctionnalité du plugin, ajoutez des index appropriés (avec précaution), ou réécrivez le chemin de requête. Mettre un cache sur des chemins d’écriture finit rarement bien.
Task 10: Confirm webhook endpoint is reachable externally
cr0x@server:~$ curl -s -o /dev/null -w "%{http_code}\n" https://example-shop.com/?wc-api=wc_stripe
200
cr0x@server:~$ sudo tail -n 50 /var/log/nginx/access.log | egrep 'wc-api=wc_stripe|webhook'
198.51.100.22 - - [27/Dec/2025:11:01:44 +0000] "POST /?wc-api=wc_stripe HTTP/2.0" 200 42 "-" "Stripe/1.0 (+https://stripe.com/docs/webhooks)"
Ce que ça signifie : L’endpoint répond et vous voyez les POST entrants.
Décision : Si vous ne voyez aucun POST, la passerelle ne vous atteint pas (DNS/firewall/WAF). Si vous voyez des 4xx/5xx, corrigez le traitement applicatif ou les règles WAF.
Task 11: Catch WAF or security plugin blocking POST bodies
cr0x@server:~$ sudo grep -iE 'modsecurity|access denied|waf|forbidden' /var/log/nginx/error.log | tail -10
2025/12/27 11:02:13 [error] 1234#1234: *8890 ModSecurity: Access denied with code 403 (phase 2). Matched "Operator `Rx' with parameter `(?i:select.+from)'" against variable `ARGS:billing_address_1'
Ce que ça signifie : Une règle WAF signale faussement les champs de checkout comme SQLi.
Décision : Ajoutez une exception ciblée pour les endpoints de checkout, pas une désactivation globale. Conservez la sécurité, mais apprenez-lui les bonnes manières.
Task 12: Validate WordPress site URLs and HTTPS settings via WP-CLI
cr0x@server:~$ cd /var/www/html
cr0x@server:~$ wp option get home
https://example-shop.com
cr0x@server:~$ wp option get siteurl
https://example-shop.com
Ce que ça signifie : WordPress croit être en HTTPS avec le bon hôte.
Décision : Si ces valeurs sont en HTTP ou sur le mauvais domaine, corrigez-les. Des URLs non appariées créent des boucles de redirection et des problèmes de portée de cookie.
Task 13: Check active plugins quickly (and spot risky ones)
cr0x@server:~$ wp plugin list --status=active
+---------------------------+--------+-----------+---------+
| name | status | update | version |
+---------------------------+--------+-----------+---------+
| woocommerce | active | available | 9.3.2 |
| woocommerce-gateway-stripe| active | none | 8.7.0 |
| wp-rocket | active | none | 3.16.0 |
| wordfence | active | none | 7.11.0 |
| some-minify-plugin | active | none | 2.4.1 |
+---------------------------+--------+-----------+---------+
Ce que ça signifie : Vous voyez des plugins de cache/sécurité/minify qui interfèrent souvent avec le checkout.
Décision : Si le checkout a cassé après une mise à jour, restaurez d’abord ce plugin précis. Si vous devez tester, désactivez l’optimisation/minify sur les URLs de checkout.
Task 14: Verify cron isn’t choking order completion emails and stock updates
cr0x@server:~$ wp cron event list | head
+-------------------+---------------------+---------------------+------------+
| hook | next_run_gmt | next_run_relative | recurrence |
+-------------------+---------------------+---------------------+------------+
| wc_cleanup_sessions | 2025-12-27 11:05:00 | in 2 minutes | hourly |
| woocommerce_scheduled_sales | 2025-12-27 12:00:00 | in 57 minutes | hourly |
+-------------------+---------------------+---------------------+------------+
cr0x@server:~$ wp cron test
Success: WP-Cron spawning is working as expected.
Ce que ça signifie : WP-Cron peut s’exécuter. S’il ne le peut pas, les tâches différées (comme la finalisation de capture de paiement dans certains setups) peuvent prendre du retard.
Décision : Si WP-Cron échoue, configurez un cron système réel pour appeler wp-cron.php, et assurez-vous que les connexions sortantes HTTP sont autorisées.
Trois mini-récits d’entreprise du terrain
Mini-récit 1 : la panne causée par une mauvaise hypothèse
L’entreprise avait migré vers un nouveau load balancer. TLS était terminé à la périphérie, le trafic vers l’origine était HTTP, et tout le monde acquiesçait comme si c’était normal. La vitrine semblait correcte. Les pages produits se chargeaient. L’ajout au panier fonctionnait. L’équipe a donc supposé que la migration était bonne.
Le checkout, cependant, a commencé à échouer de manière intermittente. Pas pour tout le monde, pas toujours. Le symptôme était un spinner puis une erreur générique. La console du navigateur n’affichait rien d’évident. Les tickets support arrivaient au compte-gouttes avec des captures d’écran qui se ressemblaient toutes : « Quelque chose s’est mal passé. » Classique.
Finalement, quelqu’un remarqua un motif : les clients utilisant des méthodes de paiement enregistrées échouaient plus souvent. C’était l’indice. Les méthodes enregistrées s’appuyaient davantage sur les sessions et les nonces, et ceux-ci étaient liés aux cookies. Les cookies, à leur tour, étaient définis de façon incohérente parce que WordPress ne pouvait pas détecter HTTPS de manière fiable à l’origine.
La mauvaise hypothèse était simple : « Si le site charge en HTTPS, WordPress sait que c’est HTTPS. » Derrière les proxies, ce n’est pas garanti. La correction fut tout aussi simple : corriger les headers forwarded, configurer l’origine pour leur faire confiance, et aligner les URLs canoniques. Le checkout s’est stabilisé instantanément, comme par magie. Ce n’était pas de la magie. C’était des maths plus HTTP.
Mini-récit 2 : l’optimisation qui s’est retournée contre eux
Une initiative performance avait un objectif noble : améliorer les Core Web Vitals. L’équipe a activé une optimisation JS agressive : minify, concat, defer, delay et « supprimer l’inutilisé ». La page d’accueil est devenue plus rapide. Les graphiques semblaient excellents. On a célébré dans le chat.
Puis les conversions ont chuté. Pas effondrées, juste assez pour déclencher la phase « on se fait des idées ? ». Le support signalait des échecs de paiement, mais pas de façon consistante. Certains clients finalisaient leur commande ; d’autres ne pouvaient pas charger le champ de carte ou le challenge 3DS. Les logs montraient des timeouts de passerelle occasionnels mais rien de décisif.
Le coupable était l’optimizer qui retardait des scripts qu’il jugeait « non-critiques », y compris les champs de paiement hébergés. Sur certains appareils, le client cliquait sur Passer la commande avant que l’élément de paiement ne s’initialise, donc la requête de checkout passait sans token de paiement. WooCommerce a fait ce qu’il pouvait : il a créé une commande, puis le paiement a échoué.
La solution n’était pas d’abandonner le travail de performance. C’était d’arrêter de traiter le checkout comme une page marketing. Ils ont exclu le checkout, le panier et les pages compte de la concaténation/délais JS, et ajouté une surveillance des erreurs de tokenisation. La performance est restée bonne là où ça comptait, et le checkout a cessé de perdre silencieusement des revenus.
Mini-récit 3 : la pratique ennuyeuse mais correcte qui a sauvé la mise
Une autre équipe faisait des « exercices incendie » du checkout chaque semaine. Pas des démonstrations dramatiques. Ils réalisaient simplement une transaction réelle pour chaque moyen de paiement dans un environnement de staging qui reproduisait la configuration de production : règles CDN/WAF, headers, tout. Ils vérifiaient aussi la livraison des webhooks et les transitions d’état des commandes.
Cette pratique semblait terne. Elle ne produisait pas de dashboards clinquants. Elle n’obtenait pas d’applaudissements. Mais elle a créé une mémoire musculaire : où se trouvent les logs, à quoi ressemble le « normal », et quels dashboards fournisseurs comptent pendant un incident.
Un vendredi, une mise à jour d’une règle managée du WAF a commencé à bloquer des POST contenant certains motifs d’adresse. Le premier symptôme fut une petite hausse des échecs de checkout. Parce que l’équipe avait une base de référence et savait précisément où regarder, ils ont repéré des blocs 403 en quelques minutes, ajouté une exception ciblée pour l’endpoint de checkout, et sont passés à autre chose.
Le salut n’a pas été des actes héroïques. C’était l’habitude ingrate de tester toute la boucle de paiement, y compris les webhooks, dans les opérations — pas seulement lors d’une panique annuelle.
Erreurs courantes : symptôme → cause racine → correction
1) Spinner infini après « Passer la commande »
Symptôme : le bouton checkout tourne ; aucune commande créée ; le réseau montre ?wc-ajax=checkout en attente ou échouant.
Cause racine : erreur JavaScript, endpoint AJAX bloqué, ou queue/timeouts PHP-FPM.
Correction : Vérifiez la console DevTools, puis les logs d’accès/erreur serveur. Excluez le checkout de l’optimisation JS. Augmentez la capacité PHP-FPM seulement après avoir identifié les requêtes lentes.
2) « Échec de vérification du nonce » / session perdue
Symptôme : échecs sporadiques ; souvent après un temps passé sur la page ; parfois seulement sur mobile.
Cause racine : mise en cache d’une page avec des nonces ; cookies bloqués ; mismatch HTTP/HTTPS ; domaines multiples.
Correction : désactivez le cache sur checkout/cart/account, imposez un seul hostname HTTPS, confirmez les cookies sécurisés et la cohérence de siteurl/home.
3) Boucle de redirection entre HTTP et HTTPS
Symptôme : le navigateur indique trop de redirections ; curl montre des 301/302 répétés.
Cause racine : réglages d’URL WordPress en désaccord avec la terminaison proxy ; règles de redirection conflictuelles dans Nginx/Apache, WordPress et le CDN.
Correction : choisissez une seule couche de redirection canonique (préférez le edge ou le serveur web), définissez correctement les URLs WordPress, passez X-Forwarded-Proto, et retirez les redirections redondantes.
4) Commandes créées mais bloquées « en attente de paiement »
Symptôme : le client affirme avoir été débité ; le dashboard de la passerelle montre le succès ; la commande WooCommerce reste en attente.
Cause racine : webhook non livré ou rejeté (désaccord de signature, 403 par WAF, timeout), ou le site ne peut pas traiter les callbacks asynchrones.
Correction : vérifiez la portée du endpoint de webhook, allowlistez les IP/user-agent de la passerelle si approprié, confirmez les secrets, et assurez-vous que le serveur ne timeout pas lors du traitement des webhooks.
5) Méthode de paiement n’apparaît pas au checkout
Symptôme : section passerelle vide ; la console montre des scripts bloqués.
Cause racine : contenu mixte, CSP trop strict, plugin de type ad-blocker, ou plugin de minify cassant l’ordre des scripts.
Correction : éliminez les assets HTTP ; ajustez le CSP pour autoriser les domaines de la passerelle ; excluez les scripts de passerelle de la minification/delay ; testez dans un profil navigateur propre.
6) Le checkout fonctionne pour les admins mais pas pour les clients
Symptôme : vous pouvez commander ; les clients non.
Cause racine : variations de cache selon cookie ; comportement basé sur le rôle ; règles de sécurité qui exemptent les utilisateurs connectés ; problèmes de checkout pour les invités.
Correction : testez en étant déconnecté en navigation privée ; désactivez le cache pour le checkout ; assurez-vous que le checkout invité est activé si prévu ; vérifiez les règles WAF appliquées aux utilisateurs anonymes.
7) « Il y a eu un problème lors du traitement de votre commande » aléatoire sous charge
Symptôme : échecs intermittents, souvent pendant des campagnes.
Cause racine : pm.max_children atteint, contention BD, timeouts d’API externes, ou limitation de débit côté passerelle.
Correction : observez la saturation des workers et les requêtes lentes ; ajoutez du queueing/retries lorsque pertinent ; réduisez les appels externes synchrones pendant le checkout.
8) Le panier se vide au checkout
Symptôme : les articles disparaissent ; « session expirée ».
Cause racine : cookies qui ne persistent pas (SameSite/secure), cache, ou mismatch de domaine entre www/apex.
Correction : standardisez le hostname, assurez HTTPS partout, ne mettez pas en cache cart/checkout, et validez les attributs de cookie.
Checklists / plan étape par étape
Étape par étape : stabiliser le checkout dans les 30–60 minutes suivantes
- Geler les changements : pas de mises à jour de plugins, pas de modifications de règles CDN, pas de déploiements de thème tant que le checkout n’est pas rétabli.
- Reproduire avec preuves : capture HAR + console DevTools, message d’erreur exact et timestamp.
- Vérifier les logs d’accès/erreur autour du timestamp pour
?wc-ajax=checkoutet les endpoints webhook. - Vérifier les logs WooCommerce pour la passerelle et les erreurs fatales.
- Désactiver le cache full-page pour checkout/cart/account à chaque couche : plugin cache, cache serveur, cache CDN.
- Désactiver temporairement l’optimisation JS sur le checkout : concat/minify/defer/delay.
- Confirmer la canonicalisation HTTPS : un seul hostname, pas de boucles, cookies sécurisés.
- Valider la configuration de la passerelle : clés API, secret webhook, endpoint atteignable, bon environnement.
- Réduire le périmètre : si un moyen de paiement spécifique échoue, désactivez-le temporairement et orientez les clients vers une alternative fonctionnelle pendant que vous corrigez la cause racine.
- Communiquer le statut : les parties prenantes internes ont besoin d’un signal clair « checkout impacté », pas de rumeurs.
Étape par étape : trouver la cause racine sans casser d’autres choses
- Baseliner le système : CPU, mémoire, disque, saturation PHP-FPM, threads BD, taux d’erreur.
- Diff du dernier changement : mise à jour de plugin, changement de thème, upgrade PHP, mise à jour de règle WAF, politique CDN.
- Isoler les conflits :
- Tester avec le thème par défaut en staging.
- Désactiver les plugins non essentiels en staging.
- Réactiver par lots jusqu’à la réapparition du problème.
- Valider les webhooks bout à bout : l’événement arrive, la signature valide, le statut de la commande évolue, l’email est envoyé.
- Rédiger une note postmortem : ce qui a échoué, pourquoi ça n’a pas été détecté, et ce que vous surveillerez la prochaine fois.
Checklist opérationnelle : rendre les futures pannes de checkout moins excitantes
- Alertes sur les pics de
4xx/5xxpour?wc-ajax=checkoutet les endpoints webhook. - Suivre le taux de succès des paiements par méthode (Stripe, PayPal, etc.), pas seulement le total des commandes.
- Exclure checkout/cart/account du caching et des outils d’« auto-optimisation » par politique.
- Maintenir un environnement de staging avec les mêmes politiques CDN/WAF que la production.
- Réaliser une transaction synthétique hebdomadaire incluant la confirmation webhook.
FAQ
Pourquoi le checkout WooCommerce marche pour moi mais pas pour les clients ?
Les administrateurs contournent souvent le cache et certaines règles de sécurité, et vous pouvez avoir des cookies/sessions différents. Testez en étant déconnecté en navigation privée. Si seuls les invités échouent, suspectez le cache, la portée des cookies ou les règles WAF ciblant le trafic anonyme.
Quelle est la façon la plus rapide de dire si c’est un conflit de plugin ?
Une erreur dans la console du navigateur plus une panne soudaine suite à une mise à jour est un signal fort. En staging, passez au thème par défaut et désactivez tous les plugins non essentiels. Si le checkout revient, vous avez la réponse.
Ai-je vraiment besoin de HTTPS partout ou seulement sur le checkout ?
Pratiquement : partout. Les schémas mixtes causent des problèmes de cookies et de sessions, et les navigateurs modernes vous pénalisent pour un HTTPS partiel. De plus, les passerelles attendent souvent des origines sécurisées pour plusieurs flux.
Pourquoi des commandes restent en « en attente de paiement » alors que Stripe dit payé ?
Parce que « payé » dans l’interface de la passerelle n’est pas la même chose que « commande marquée payée » dans WooCommerce. Les webhooks réconcilient l’état final. Si la livraison du webhook est bloquée ou que la validation de signature échoue, WooCommerce ne mettra pas à jour la commande.
Les plugins de cache peuvent-ils casser le checkout même s’ils disent l’exclure ?
Oui. Les exclusions peuvent être incomplètes, écrasées par les règles CDN, ou cassées par la normalisation des query-strings. Vérifiez avec les headers (cache hit/miss), et assurez-vous que le CDN ne met pas en cache de réponses personnalisées.
Pourquoi le checkout échoue seulement sur Safari mobile ?
Les protections anti-tracking et la gestion des cookies de Safari peuvent casser les champs de paiement embarqués tiers ou les redirections cross-site si les attributs SameSite et secure ne sont pas corrects. De plus, le retard agressif de scripts peut provoquer des courses d’initialisation des éléments de paiement sur des appareils plus lents.
Faut-il augmenter la limite mémoire PHP pour réparer le checkout ?
Seulement si vous avez des preuves d’épuisement mémoire (erreurs fatales, OOM kills). Augmenter la mémoire peut masquer des plugins inefficaces et aggraver la densité des processus. Corrigez d’abord le chemin de code lent/défaillant.
Comment savoir si mon WAF bloque le checkout ?
Cherchez des réponses 403 sur ?wc-ajax=checkout et des règles correspondantes dans les logs WAF ou les logs d’erreurs du serveur web. Si vous voyez des hits ModSecurity/règles managées sur les champs POST du checkout, vous devez ajouter une exception ciblée.
Quelle est la cause la plus courante du « ça marchait hier » ?
Un changement que vous n’avez pas relié au checkout : mise à jour automatique d’un plugin, mise à jour d’une règle managée CDN/WAF, ou une fonctionnalité d’« optimisation » activée. Le checkout est sensible ; traitez les changements comme suspects jusqu’à vérification.
Est-il sûr de désactiver les webhooks comme solution temporaire ?
Non. Les webhooks sont la façon fiable de synchroniser l’état des paiements. Si les webhooks échouent, corrigez la portée/signatures/timeouts. Les désactiver déplace juste le travail vers une réconciliation manuelle, qui échouera à grande échelle.
Conclusion : quoi faire ensuite (et ce qu’il faut arrêter)
Voici le plan d’actions pratique suivant :
- Obtenir des preuves : un essai de checkout raté avec timestamp, entrée réseau DevTools pour
?wc-ajax=checkout, et les logs WooCommerce/PHP pertinents. - Choisir la voie : SSL/cookies, passerelle/webhooks, plugin/thème, cache/WAF, ou limites serveur. Ne déboguez pas cinq voies en même temps.
- Stabiliser d’abord : exclure le checkout du cache/optimisation, annuler les changements récents, et garder au moins un moyen de paiement fonctionnel si possible.
- Corriger la cause racine : corriger HTTPS/headers proxy, réparer la config de la passerelle, dompter le WAF, ou éliminer le plugin en conflit.
- Rendre ça ennuyeux : ajoutez de la surveillance pour les échecs AJAX de checkout et la santé des webhooks, et réalisez une transaction synthétique hebdomadaire.
Arrêtez de basculer des plugins au hasard comme si vous essayiez d’ouvrir une combinaison. La fiabilité du checkout n’est pas un problème de superstition. C’est un problème d’observabilité — suivez la requête, lisez les logs, et ne faites qu’un changement à la fois.