Skip to main content

Multilingual and Multicurrency (WPML/WCML)

OME works with WPML + WooCommerce Multilingual & Multicurrency (WCML). This page describes what OME handles automatically, what WCML controls, and the recommended setup when customers should be able to pick their own currency.

What OME Handles Automatically​

  • Cart session context. Persisted Store API cart sessions are stamped with the page currency and language. When a customer switches either, the stale session is dropped at boot and the cart re-syncs from the classic session — no manual token clearing needed.
  • Cart totals currency. The classic cart session records the currency its totals were computed in. On a currency change, OME recalculates the cart under the current currency so server-rendered cart surfaces match what the customer sees, and Store API snapshots (including Stripe Payment Intents) always pair amounts with the currency they were computed in.
  • Facet cache dimensions. Facet response and availability caches are keyed per language and per currency, so a guest on the EN page never receives a cached PL/PLN render.
  • Facet language requests. Facet REST requests carry the current language (lang parameter), which WPML uses to resolve the request language.
  • Product structured data. Product pages built with Etch blocks still ship WooCommerce Product JSON-LD (price, currency, availability), computed under the current currency.

Currency Modes: Pick One Intent​

WCML multicurrency has two different intents, and mixing them causes the "currency resets when I switch language" behavior:

  • Currency per language. Each language is pinned to one currency (for example EN → EUR, PL → PLN). Switching language resets the currency. This is WCML working as designed. Choose this when currency should follow language.
  • Customer-selectable currencies. Customers can switch between currencies independently of language (per session/cookie). Choose this when you want a currency switcher with more currencies than languages.

If you need a customer-selected currency that survives language switches, configure WCML multicurrency for customer switching rather than fighting the per-language resolution with code.

When you accept a customer's currency choice yourself (your own switcher or a cookie), expose it through the official WCML filter. This makes the classic front-end and REST/Store API contexts agree on one currency:

<?php
/**
* Plugin Name: OME — Customer Currency Choice
* Description: Restores the customer's chosen currency via the official WCML filter.
*/

declare( strict_types=1 );

add_action( 'plugins_loaded', static function (): void {
add_filter( 'wcml_client_currency', static function ( string $currency ): string {
if ( empty( $_COOKIE['ome_customer_currency'] ) ) {
return $currency;
}

$requested = sanitize_text_field( wp_unslash( $_COOKIE['ome_customer_currency'] ) );

// Only allow currencies you actually sell in.
$allowed = array( 'PLN', 'EUR', 'USD', 'GBP', 'CZK' );

return in_array( $requested, $allowed, true ) ? $requested : $currency;
} );
}, 20 );

Your currency switcher writes the ome_customer_currency cookie. WCML's own recommendation applies: when the currency changes through this filter, force a page reload so every rendered price agrees.

Keep the allow-list strict — the cookie is client input and must never select an arbitrary currency.

Structured Data Snippets​

Older setups added their own WC_Structured_Data::generate_product_data() call in wp_footer because OME product pages had no Product JSON-LD. OME now generates it automatically, guarded against duplication. Remove custom snippets after upgrading so there is a single source of truth.

Testing Checklist​

After changing currencies or languages on a staging store:

  1. Add a product to the cart in one currency, switch the currency, reload: the cart shows the new currency without manual cache clearing.
  2. Complete a checkout in a non-default currency and confirm the Stripe Payment Intent currency matches the displayed currency.
  3. Browse a secondary-language archive with facets and confirm results render in that language for guests (logged-out).
  4. View source on a product page in each currency and confirm the JSON-LD priceCurrency matches the displayed currency.