WooCommerce Shipping Cost in the Wrong Currency: Causes and Fixes
A WooCommerce shipping cost in the wrong currency shows up in three ways after a visitor switches currency: the symbol changes but the number stays the same, the cost is converted twice and comes out far too high or too low, or shipping drops to zero or disappears. Product prices are usually fine at the same time, because the cause is where the shipping cost comes from. Below is how FOX converts shipping, how to tell the three cases apart with one test, and the fix for flat rates, carrier plugins and fixed amounts per currency.
How FOX converts shipping costs
WooCommerce assumes that every amount it stores is in the base currency, shipping costs included. Shipping methods build their rates, WooCommerce passes the list through the woocommerce_package_rates filter, and FOX converts it there at priority 9999: each rate cost and its taxes are multiplied by the exchange rate of the selected currency and rounded to that currency's decimals.
- This conversion runs only with Is multiple allowed = Yes in the Advanced tab of the FOX settings, the mode in which customers pay in the currency they selected.
- With Is multiple allowed = No, rates stay in the base currency. The cart shows them converted for information, and the checkout recalculates everything in the base currency, which is what the customer pays. This setup is explained in show local currency, charge in base currency.
- Formulas in the Flat rate cost field, such as
[qty] * 2or[fee percent="10" min_fee="5"], are evaluated with the cart total converted back to the base currency, so percentages and minimum fees work in base-currency terms and the result is then converted with the other rates.
One rule follows from this: whatever reaches woocommerce_package_rates before priority 9999 must be in the base currency. A cost that is already in the visitor's currency gets converted a second time; a cost that a plugin sets after FOX has finished is not converted at all.
Shipping cost in the wrong currency: find out which case you have
Take one shipping method and a known cost in the base currency, for example 10.00 USD, and a currency with a known rate, for example EUR at 0.92 in the FOX currencies table. Switch to EUR, change the cart quantity once (WooCommerce keeps calculated rates in the session and reuses them until the cart or the address changes) and compare:
| Shipping in EUR | What it means |
|---|---|
| 9.20 € | Converted correctly |
| 10.00 € | Not converted: the rate was set after FOX, or by a plugin that bypasses WooCommerce rates |
| 8.46 € | Converted twice: the plugin already returned 9.20 in EUR and FOX multiplied it again |
| Some other amount | The carrier returned a price in its own account currency, which was treated as base currency |
| 0.00 € or no shipping methods | A rate of 0 for this currency, or a currency code the carrier does not recognise |
While testing, the Debug mode option in WooCommerce → Settings → Shipping turns off the shipping rate cache, so every page load calculates fresh rates. Switch it off again afterwards.
Set an exact shipping cost per currency
Converting by the exchange rate gives amounts like 9.20 € or 1,486 ₹. When you want round numbers, a different price level per market (18 € for Europe, 32 $ for the rest of the world), or a shipping cost that does not follow a markup you added to the exchange rate, set the amount per currency instead:
- In the Advanced tab of the FOX settings set Is multiple allowed to Yes. The option Individual fixed amount for shipping is hidden until you do.
- Switch Individual fixed amount for shipping on and save.
- Open WooCommerce → Settings → Shipping, a shipping zone, and edit its Flat rate method. Below the WooCommerce fields there is now a Fixed cost field for every currency except the base one, for example Fixed cost EUR.
- Enter the amount in that currency. An empty field (placeholder auto) means "convert by the exchange rate".
A fixed amount replaces the whole converted cost of that flat rate, including any shipping class costs or formula result, and the shipping tax is recalculated from it. Only amounts greater than 0 are used: a 0 counts as empty, so for free delivery in one currency use a Free shipping method. The same option adds Minimum order amount in EUR fields to Free shipping methods, so the free shipping threshold can be set per currency too; without them, FOX compares the cart subtotal converted back to the base currency with the base-currency minimum.
The fields exist only for WooCommerce's own Flat rate and Free shipping methods. Table rate plugins and carrier rates are always converted by the exchange rate. If you do not see the fields, check that the option is still on after saving and that the shipping method settings window opens without JavaScript errors in the browser console.
For converted costs you only want tidier, a rounding filter is the better tool; rounding converted prices includes one for shipping that runs after the FOX conversion.
Carrier plugins that return rates in another currency
Plugins for UPS, DHL, FedEx, Printful, Easyship and local delivery services ask the carrier's API for a live price. The API answers in the currency it was asked for, or in the currency of the carrier account. Many of these plugins ask for "the store currency" with get_woocommerce_currency(), and FOX answers that function with the visitor's currency, so the API returns, say, 9.20 EUR. The plugin hands 9.20 to WooCommerce as if it were dollars, and FOX converts it again. Some plugins compare the account currency with the store currency and return no rates at all when they differ.
There are three ways to fix it, from cleanest to most general:
- Make the plugin request the base currency. Look for a currency setting in the carrier plugin. If there is none, its request can be changed to use
$WOOCS->default_currency; this is the fix for Printful. - Use a ready adaptation. Ready code exists for UPS Shipping Method, the official UPS plugin, DHL Express Commerce, Printful, Easyship, Aramex and Ingrid. Packeta converts its rates through FOX itself and needs no code, as long as it is up to date. Edits inside another plugin's files are lost when that plugin updates, so note them.
- Convert the rates back to the base currency before FOX converts them. It works for any carrier and survives plugin updates.
/*
* Carrier rates that arrive in a currency other than the base currency:
* turn them back into the base currency before FOX converts all rates (priority 9999).
* Child theme functions.php or a code snippets plugin.
*/
add_filter('woocommerce_package_rates', function ($rates, $package) {
if (!class_exists('WOOCS')) {
return $rates;
}
global $WOOCS;
$methods = array('ups'); // method IDs of the carrier plugins (see below)
$rate_currency = $WOOCS->current_currency; // or a fixed code, e.g. 'GBP' for the account currency
$currencies = $WOOCS->get_currencies();
if ($rate_currency === $WOOCS->default_currency || empty($currencies[$rate_currency]['rate'])) {
return $rates;
}
$factor = (float) $currencies[$rate_currency]['rate'];
foreach ($rates as $rate) {
if (!in_array($rate->get_method_id(), $methods, true)) {
continue;
}
$rate->set_cost((float) $rate->get_cost() / $factor);
$taxes = $rate->get_taxes();
if (!empty($taxes)) {
foreach ($taxes as $key => $tax) {
$taxes[$key] = (float) $tax / $factor;
}
$rate->set_taxes($taxes);
}
}
return $rates;
}, 100, 2);
To find a method ID, inspect the shipping method's radio button on the cart page: its value looks like ups:4:03 or flat_rate:2, and the part before the first colon is usually the method ID. Keep $rate_currency as the visitor's currency when the carrier quotes in whatever currency it is asked for; set a fixed code when it always quotes in the account currency. That currency must exist in the FOX currencies table with a current rate, otherwise the snippet leaves the rates untouched. The same snippet also answers "do not convert shipping for this method": the amount the method returns is then shown unchanged in every currency.
Shipping that is not converted at all
When the number stays the same and only the symbol changes, the cost never passed through the FOX conversion. Typical reasons:
- The plugin changes its rates in its own
woocommerce_package_ratescallback with a priority above 9999, after FOX has converted them. - The price is set by the plugin's own checkout widget or added as a cart fee instead of a shipping rate.
- Rules in the shipping plugin compare the cart total with thresholds entered in the base currency, so rules based on cart value pick the wrong band in other currencies.
These need a change on the plugin's side: it has to pass its amounts through FOX with apply_filters('woocs_exchange_value', $amount), described on the woocs_exchange_value page, or compare base-currency values. Ask the plugin's authors, or see FOX Labs for adaptations of other plugins.
Shipping becomes zero or disappears after switching currency
- A rate of 0. FOX multiplies the shipping cost by the currency's rate, so a rate saved as 0 makes every rate free in that currency. It happens when an aggregator returns no data, often after the base currency was changed. Check the Rate column in the Currencies tab; exchange rates not updating covers the causes.
- A currency code the carrier does not know. Carrier APIs quote by ISO code, so a currency added as
UKinstead ofGBPreturns no rates and the checkout shows no shipping methods. Use the real ISO code for any currency a carrier or gateway sees; custom currency codes explains when a non-ISO code is safe. - The carrier rejects the currency. Some carrier plugins return rates only when the store currency equals the account currency. Use one of the three fixes in the carrier section above.
Checklist
- Is multiple allowed is set as intended: Yes to charge in the visitor's currency, No to charge in the base currency.
- Every currency has a non-zero rate and a real ISO code.
- Flat rates that need exact amounts have Fixed cost values for each currency, with Individual fixed amount for shipping on.
- Carrier plugins request the base currency, use their adaptation, or are covered by the back-conversion snippet.
- Tested in a private window, with the cart changed or shipping Debug mode on, in each currency.
If a shipping method is still wrong in one currency, open a topic on the FOX support forum with the name of the shipping plugin, your Is multiple allowed setting, and the cost you see in the base currency and in the other currency, and we will look at it.