FOX - WooCommerce Currency Switcher Professional

Sélecteur de devises WooCommerce derrière Cloudflare : APO, cache et GeoIP

Un sélecteur de devises WooCommerce derrière Cloudflare dépend de deux choses : les pages que Cloudflare met en cache et distribue sous forme de HTML fini, et ce qu'il indique à WordPress sur le visiteur. Quand l'une des deux est incorrecte, les symptômes se ressemblent : tout le monde obtient la même devise, le sélecteur semble ne rien faire, Cloudflare APO cesse de mettre la boutique en cache, ou les règles GeoIP choisissent le mauvais pays. Voici la configuration de FOX propre à Cloudflare ; le conflit général entre les prix et les caches de page est expliqué dans pourquoi un sélecteur de devises et un cache de page se battent.

Ce que Cloudflare fait des pages de votre boutique

Commencez par identifier laquelle des trois configurations est la vôtre, car les solutions diffèrent.

ConfigurationPages HTML mises en cache chez Cloudflare ?Ce qui compte pour FOX
Proxy seul (nuage orange, mise en cache par défaut)Non. Cloudflare ne met pas le HTML en cache par défaut, seulement les fichiers statiques comme le CSS, le JavaScript et les images.L'adresse IP et le pays du visiteur qui parviennent à WordPress. Un plugin de cache sur le serveur est une autre question.
Cache Rules qui rendent le HTML éligible à la mise en cacheOui, une copie par URL pour tout le monde.Le mode cache de FOX, un stockage sans cookies, et les bonnes exclusions.
APO (Automatic Platform Optimization for WordPress)Oui, en périphérie.La même chose que pour les Cache Rules, plus les règles propres à APO pour les cookies et les chaînes de requête.

Pour voir ce qui arrive à une page, ouvrez deux fois une page de catégorie dans une fenêtre de navigation privée, avec l'onglet Réseau (Network) des outils de développement ouvert, et lisez les en-têtes de réponse de la requête de la page elle-même :

  • cf-cache-status: HIT signifie que la page provient du cache de Cloudflare ; MISS, EXPIRED ou BYPASS signifient qu'elle a été construite par WordPress ; DYNAMIC signifie que Cloudflare ne la considère pas du tout comme pouvant être mise en cache.
  • Avec APO, cf-apo-via: cache signifie que la page provient du cache d'APO ; toute valeur commençant par origin signifie qu'APO l'a récupérée sur votre serveur.
  • Un en-tête set-cookie dans la réponse de la page est la raison habituelle pour laquelle une page qui devrait être mise en cache ne l'est jamais.

Depuis un terminal, curl -s -o /dev/null -D - https://example.com/product-category/shoes/ affiche les mêmes en-têtes pour une requête GET normale ; exécutez-la deux fois.

Réglages du sélecteur de devises pour Cloudflare APO et le HTML en cache

Quand Cloudflare met le HTML en cache, la même copie d'une page parvient à tout le monde : FOX doit donc corriger les prix dans le navigateur et ne doit rien mettre de personnel dans la réponse de la page. Dans les réglages de FOX (WooCommerce → Réglages → Devise), onglet Options :

  1. Stockage de la devise (Currency storage) = Transient. Session FOX (FOX Session) définit un cookie de session (wp_woocs_session_…) dans la première réponse envoyée à un visiteur, et Session PHP (PHP Session) en définit un aussi, tandis que la gestion des sessions de PHP ajoute en plus des en-têtes Cache-Control: no-store, no-cache. Cloudflare ne stocke pas une réponse qui définit un cookie ou interdit la mise en cache : avec l'un ou l'autre stockage de session, les pages continuent donc de venir de votre serveur et le taux de succès d'APO s'effondre : cf-apo-via: origin,resnok dans les en-têtes. Transient ne définit aucun cookie. Renommer le cookie de session avec le filtre woocs_cookie n'y change rien : la première réponse porte toujours un en-tête Set-Cookie.
  2. J'utilise un plugin de cache sur mon site (I am using cache plugin on my site) = Oui. FOX redessine alors les prix dans la devise du visiteur après le chargement de la page en cache. Avec Transient, il active aussi le mode clé de navigateur (depuis FOX 2.5.0) : le navigateur conserve une clé aléatoire dans le localStorage et l'envoie avec les requêtes AJAX jQuery (le paramètre woocs_sk) et avec les requêtes fetch() de même origine, comme le paiement par blocs et les boutons PayPal (l'en-tête X-WOOCS-SK). La clé n'apparaît jamais dans l'URL d'une page ; elle ne divise donc pas le cache par visiteur. Gardez FOX à jour : les premières versions de ce mode n'envoyaient la clé qu'avec les requêtes jQuery, si bien que les commandes PayPal créées via fetch() sortaient dans la devise de base et échouaient avec CANNOT_MIX_CURRENCIES.
  3. Pas de données GET dans le lien (No GET data in link) = Non. En mode clé de navigateur, un changement de devise enregistre d'abord la devise pour la clé du navigateur, puis ouvre la page avec ?currency= dans l'adresse. Cette requête va à votre serveur (APO ne la met jamais en cache, voir plus bas), qui rend la page dans la nouvelle devise et l'enregistre aussi sous l'adresse IP du visiteur, la clé que FOX utilise pour les pages rendues sans AJAX, comme une page de panier classique.

Préchargeur de prix (Prices preloader) change peu de chose ici : dans FOX 2.5.5, son animation de chargement est retirée dès l'envoi de la requête de redessin, et non à l'arrivée de la réponse ; elle ne masque donc pas le court instant pendant lequel les prix en cache sont visibles.

APO ajoute ses propres règles. Il contourne le cache pour les visiteurs qui portent des cookies commençant par wp-, wordpress, woocommerce_ et quelques autres préfixes ; les utilisateurs connectés et les visiteurs qui ont quelque chose dans leur panier obtiennent donc de toute façon des pages fraîches. Il contourne aussi le cache pour toute URL contenant un paramètre de requête en dehors de sa courte liste autorisée de paramètres de suivi. Deux conséquences pour une boutique multidevise :

  • Les liens avec ?currency=EUR parviennent toujours à votre serveur, ce dont le changement de devise a besoin.
  • L'option de WooCommerce Emplacement client par défaut (Default customer location) = Géolocaliser (avec prise en charge de la mise en cache des pages) (Geolocate (with page caching support)) ajoute un paramètre ?v= aux URL de la boutique, et APO ne sert aucune de ces URL depuis son cache. FOX n'a pas besoin de ce réglage : il demande le pays directement à WooCommerce, quelle que soit la valeur de Emplacement client par défaut (Default customer location), et sur une page en cache il le fait dans la requête de redessin (avec une lacune, comblée par l'extrait plus bas). Avec APO, choisissez Géolocaliser (Geolocate) ou Adresse de base de la boutique (Shop base address) selon la manière dont vous voulez que WooCommerce estime les taxes et la livraison.

Cache Rules : ce qu'il faut exclure

Avec les Cache Rules, vous décidez vous-même de ce que Cloudflare stocke, et une règle trop large provoque les pires problèmes de devise : un panier ou une page de paiement en cache montre les totaux d'un visiteur à un autre. Gardez ces éléments hors du cache avec une règle réglée sur Contourner le cache (Bypass cache), ou excluez-les de votre règle de mise en cache :

  • les pages panier, paiement et mon compte (utilisez vos propres slugs de pages) et /wp-admin/ ;
  • /wp-json/ et les requêtes avec wc-ajax= dans la chaîne de requête ;
  • les URL dont la chaîne de requête contient currency=, afin qu'un changement de devise soit toujours traité par WordPress.

Pour la règle qui met en cache les pages de la boutique, réglez TTL en périphérie (Edge TTL) sur l'une des options qui utilisent l'en-tête Cache-Control s'il est présent. WooCommerce envoie des en-têtes no-cache sur les pages définies comme panier, paiement et mon compte dans ses réglages (un paiement construit sur une autre page par un plugin d'entonnoir de vente n'en reçoit aucun), et avec Ignorer l'en-tête cache-control et utiliser ce TTL (Ignore cache-control header and use this TTL), Cloudflare les mettrait quand même en cache si votre règle les capte par erreur. Les requêtes propres à FOX vers admin-ajax.php sont des requêtes POST, que Cloudflare ne met pas en cache.

Mauvais pays ou une seule devise pour tout le monde

FOX n'a pas de base de données de géolocalisation propre. Il appelle WC_Geolocation::geolocate_ip(), applique ses règles GeoIP au pays renvoyé par WooCommerce, et ne le fait qu'une fois par visiteur. Quand WordPress rend une page, cela se passe en PHP ; sur une page servie depuis le cache de Cloudflare, cela ne peut se produire que dans la requête de redessin, un POST vers admin-ajax.php qui parvient toujours à votre serveur. La géolocalisation derrière Cloudflare demande donc trois choses : le bon pays dans chaque requête, la bonne adresse du visiteur, et un redessin qui applique les règles. Pour voir ce que WooCommerce détecte, placez [woocs_geo_hello] sur une page de test non mise en cache ; la procédure complète figure dans la géolocalisation de WooCommerce affiche la mauvaise devise.

Laisser Cloudflare envoyer le pays

Activez Géolocalisation IP (IP Geolocation) dans les réglages Réseau (Network) de votre zone Cloudflare, ou la Managed Transform Ajouter les en-têtes de localisation du visiteur (Add visitor location headers), qui l'inclut. Cloudflare ajoute alors un en-tête CF-IPCountry à chaque requête, et WooCommerce le lit (sous la forme HTTP_CF_IPCOUNTRY, parmi quelques variables serveur de pays) avant de tenter la moindre recherche par IP. Aucune clé MaxMind et aucun code ne sont alors nécessaires pour les règles GeoIP de FOX. L'ancien conseil d'injecter le pays de Cloudflare via le filtre woocommerce_geolocate_ip est inutile aujourd'hui ; gardez ce filtre pour les sources de pays que WooCommerce ne connaît pas. Deux valeurs spéciales existent : XX pour les adresses sans données de pays et T1 pour le réseau Tor. Aucune ne correspond à une règle GeoIP ; ces visiteurs obtiennent donc la Devise de bienvenue (Welcome currency).

Restaurer l'adresse IP du visiteur

WordPress a tout de même besoin de la vraie adresse du visiteur : FOX indexe le stockage Transient par IP pour les pages rendues sans AJAX (et pour tout lorsque l'option de cache est désactivée), et WooCommerce se rabat sur l'IP lorsqu'aucun en-tête de pays n'arrive. Derrière Cloudflare, la connexion provient d'une adresse Cloudflare ; l'adresse du visiteur voyage dans les en-têtes CF-Connecting-IP et X-Forwarded-For.

  • FOX lit lui-même CF-Connecting-IP, de sorte que son stockage voit le visiteur même lorsque rien d'autre n'est configuré.
  • WooCommerce lit d'abord X-Real-IP, puis X-Forwarded-For, puis l'adresse de la connexion. Une défaillance courante est un proxy nginx placé devant Apache qui transmet X-Real-IP avec l'adresse de la connexion, qui, derrière Cloudflare, est celle d'un serveur Cloudflare. Sans l'en-tête de pays, WooCommerce recherche alors l'adresse de Cloudflare au lieu de celle du visiteur, et la plupart des visiteurs obtiennent le même pays, souvent les États-Unis.
  • La solution se trouve au niveau du serveur : le module real IP de nginx avec set_real_ip_from pour chaque plage Cloudflare et real_ip_header CF-Connecting-IP;, ou mod_remoteip d'Apache avec RemoteIPHeader CF-Connecting-IP et des lignes RemoteIPTrustedProxy. Cloudflare publie ses plages et les instructions complètes dans restauration des adresses IP d'origine des visiteurs ; sur un hébergement géré, demandez à l'hébergeur de le configurer.
  • Laissez la Managed Transform Supprimer les en-têtes IP du visiteur (Remove visitor IP headers) désactivée. Elle supprime CF-Connecting-IP, et FOX se rabat alors sur les mêmes en-têtes que WooCommerce : sur un serveur comme celui décrit plus haut, les visiteurs qui passent par la même adresse Cloudflare partagent une seule devise stockée sur les pages rendues par le serveur.

Règles GeoIP sur les pages en cache

Dans FOX 2.5.5, la requête de redessin compare d'abord la devise de la copie en cache avec la devise actuelle du visiteur, et lorsqu'elles sont identiques, elle répond « rien à changer » sans atteindre l'étape GeoIP. Un nouveau visiteur commence dans la Devise de bienvenue (Welcome currency) ; sur chaque page mise en cache dans la Devise de bienvenue (Welcome currency), les règles GeoIP sont donc ignorées : avec une règle Allemagne → EUR, un visiteur allemand garde la Devise de bienvenue (Welcome currency) et n'obtient des euros que sur la première page qui se trouve être mise en cache dans une autre devise. C'est le schéma « GeoIP ne fonctionne que sur certaines pages » derrière un cache de page complète. L'extrait ci-dessous exécute l'étape GeoIP avant la comparaison, une fois par visiteur, et laisse la priorité à une devise choisie dans le sélecteur :

<?php
/**
 * FOX behind a full-page cache (Cloudflare APO or Cache Rules):
 * apply the GeoIP rules in a new visitor's first price redraw,
 * also when the cached copy is already in the Welcome currency.
 * Add to the child theme's functions.php or a code snippets plugin.
 */
function my_fox_geoip_in_redraw() {
    global $WOOCS;
    if ( ! is_object( $WOOCS ) || empty( $WOOCS->storage ) ) {
        return;
    }
    // Once per visitor: FOX sets this flag when it has applied the GeoIP rules.
    if ( ! intval( $WOOCS->storage->get_val( 'woocs_first_unique_geoip' ) ) ) {
        $WOOCS->init_geo_currency();
    }
}

function my_fox_geoip_after_manual_choice() {
    global $WOOCS;
    // A currency chosen in the switcher before the first redraw must win.
    if ( is_object( $WOOCS ) && ! empty( $WOOCS->storage ) ) {
        $WOOCS->storage->set_val( 'woocs_first_unique_geoip', 1 );
    }
}

foreach ( array( 'woocs_get_products_price_html', 'woocs_get_variation_products_price_html', 'woocs_get_custom_price_html' ) as $my_fox_action ) {
    add_action( 'wp_ajax_' . $my_fox_action, 'my_fox_geoip_in_redraw', 1 );
    add_action( 'wp_ajax_nopriv_' . $my_fox_action, 'my_fox_geoip_in_redraw', 1 );
}
add_action( 'wp_ajax_woocs_set_currency_ajax', 'my_fox_geoip_after_manual_choice', 1 );
add_action( 'wp_ajax_nopriv_woocs_set_currency_ajax', 'my_fox_geoip_after_manual_choice', 1 );

Omettez la ligne d'ouverture <?php si votre fichier en comporte déjà une. Les gestionnaires de redessin de FOX s'exécutent à la priorité par défaut 10, ce code s'exécute donc en premier, et la comparaison voit alors la devise de la règle GeoIP du visiteur. Le redessin ne s'exécute que sur les pages comportant des prix de produits ; un visiteur qui arrive sur un article de blog obtient donc la devise GeoIP sur la première page de la boutique. Pour le tester, purgez le cache de Cloudflare, chargez une page de catégorie depuis un pays sans règle GeoIP jusqu'à ce qu'elle soit mise en cache (un HIT) dans la Devise de bienvenue (Welcome currency), puis ouvrez-la via un VPN depuis un pays disposant d'une règle, dans un profil de navigateur qui n'a jamais visité la boutique : les prix doivent passer à la devise de ce pays. Avec les réglages ci-dessus, c'est la clé du navigateur, et non l'adresse IP, qui détermine qui est un nouveau visiteur.

Purger et tester après chaque modification

Une page en cache conserve les prix avec lesquels elle a été construite, et le redessin de FOX ne les remplace que lorsque la devise du visiteur diffère de celle de la copie en cache. Après avoir modifié des devises, des taux, des décimales ou des symboles dans FOX, les visiteurs dont la devise correspond à une copie en cache voient les anciens montants jusqu'à l'expiration de cette copie. Le plugin WordPress de Cloudflare purge les pages APO lorsque vous modifiez du contenu, et non lorsque les réglages ou les taux de FOX changent ; utilisez donc Tout purger (Purge Everything) dans la configuration de mise en cache de Cloudflare, et purgez le plugin de cache de votre serveur, après de tels changements. Avec des mises à jour automatiques des taux et des Cache Rules, un TTL en périphérie (Edge TTL) qui ne dépasse pas l'intervalle de mise à jour maintient les prix convertis à jour ; avec APO, purgez après de fortes variations de taux.

Testez ensuite dans cet ordre :

  1. Exécutez deux fois la commande curl ci-dessus pour une page de catégorie : la seconde réponse affiche cf-cache-status: HIT (et cf-apo-via: cache avec APO) et aucun en-tête set-cookie.
  2. Ouvrez la page dans deux navigateurs qui n'ont jamais visité la boutique. Changez la devise dans l'un : elle change dans celui-là, et l'autre garde sa propre devise après un rechargement.
  3. Ajoutez un produit au panier dans la seconde devise et passez à la page de paiement : les totaux restent dans cette devise.
  4. Si quelque chose échoue, retirez le cache de Cloudflare du test : désactivez APO ou votre Cache Rule un instant, ou activez le Mode développement (Development Mode) dans la configuration de mise en cache, qui suspend la mise en cache en périphérie pendant trois heures, puis purgez et recommencez. Si le problème persiste, la cause se trouve sur votre serveur, par exemple un plugin de cache, un cache serveur ou un optimiseur JavaScript, et non chez Cloudflare. L'optimisation de scripts propre à Cloudflare, Rocket Loader, retarde les scripts comme le font ces optimiseurs ; si les prix continuent de tourner, testez avec lui désactivé et voyez sélecteur de devises bloqué en chargement après l'optimisation JS.

Checklist

  • Vous savez, grâce aux en-têtes de réponse, si Cloudflare met votre HTML en cache (proxy seul, Cache Rules ou APO).
  • Avec du HTML en cache : Stockage de la devise (Currency storage) = Transient, J'utilise un plugin de cache sur mon site (I am using cache plugin on my site) = Oui, Pas de données GET dans le lien (No GET data in link) = Non, FOX à jour.
  • Panier, paiement, compte, /wp-json/, wc-ajax et URL avec currency= jamais mis en cache ; TTL en périphérie (Edge TTL) respecte Cache-Control.
  • Avec APO : Emplacement client par défaut (Default customer location) non réglé sur la variante avec prise en charge du cache de page.
  • Géolocalisation IP (IP Geolocation) activée ; vraie adresse IP du visiteur restaurée sur le serveur ; Supprimer les en-têtes IP du visiteur (Remove visitor IP headers) désactivée.
  • Avec des règles GeoIP et des pages en cache : l'extrait de redessin en place.
  • Caches de Cloudflare et du serveur purgés après toute modification des réglages ou des taux de FOX.

Si la devise est toujours incorrecte avec tout cela en place, ouvrez un sujet sur le forum de support de FOX en indiquant un lien de page, les en-têtes de réponse de cette page et vos réglages de stockage et de cache de FOX, et nous l'examinerons.