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 (
langparameter), 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.
Recommended: Honor the Customer's Currency Choice
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:
- Add a product to the cart in one currency, switch the currency, reload: the cart shows the new currency without manual cache clearing.
- Complete a checkout in a non-default currency and confirm the Stripe Payment Intent currency matches the displayed currency.
- Browse a secondary-language archive with facets and confirm results render in that language for guests (logged-out).
- View source on a product page in each currency and confirm the JSON-LD
priceCurrencymatches the displayed currency.