FOX - WooCommerce Currency Switcher Professional

Show Prices in Local Currency, Charge in Base Currency in WooCommerce

Many shops want to show prices in local currency but charge in the base currency: visitors browse in euros, rupees or dollars, while every payment goes through one gateway account in one currency. WooCommerce can do this, with one rule that shapes every setup below: the currency shown on the checkout page is the currency the customer is charged in. This guide covers the three ways to arrange it with FOX, the side effects of each, and the opposite case, where customers pay in the currency they selected.

One order, one currency

A WooCommerce order stores a single currency. Whatever currency is active when the order is created is written into it, and the payment gateway receives the total as a number in that currency. FOX converts prices for display and decides which currency is active at checkout; it does not convert the amount on its way to the bank. That is why "show USD, quietly charge INR" cannot work: the gateway would take 30 USD as 30 INR. Instead, the checkout itself has to switch to the currency you charge in, and the customer sees the real amount before paying, which also prevents disputes over a surprise currency on the card statement.

The switch is controlled by Is multiple allowed in the Advanced tab of the FOX settings (WooCommerce → Settings → Currency).

Show prices in local currency but charge in base currency

When the currency you charge in is the WooCommerce base currency, no code is needed. Set Is multiple allowed to No and save; a fresh installation of FOX starts with Yes. Then:

  • the shop, product pages and cart show the visitor's currency, chosen by the switcher or by your GeoIP rules;
  • on the checkout page FOX resets the currency to the base currency, so the totals, the order and the payment are all in the base currency;
  • every order is stored in the base currency, which keeps reports and accounting in one currency.

Customers deserve to know this before they reach the payment step. Two built-in options in the Options tab show the local amount next to the real one: Show approximate amount adds an (Approx. ...) value to the cart and checkout totals, and Show approx. price does the same on shop and product pages. Both use the currency of the visitor's country from the GeoIP tab, so they need GeoIP rules, and both are calculated from exchange rates, not from fixed prices. The text can be changed with the woocs_get_approximate_amount_text filter. A plain notice on the classic cart page also helps:

/*
 * Cart notice when the shop is shown in a currency that is not charged.
 * Child theme functions.php or a code snippets plugin.
 */
add_action('woocommerce_before_cart', function () {
    global $WOOCS;
    if (!isset($WOOCS) || $WOOCS->current_currency === $WOOCS->default_currency) {
        return;
    }
    wc_print_notice(
        sprintf(
            'Prices in %s are shown for information. Your order will be charged in %s.',
            esc_html($WOOCS->current_currency),
            esc_html($WOOCS->default_currency)
        ),
        'notice'
    );
});

The side effect: the shop stays in the base currency after checkout

FOX remembers each visitor's last currency, and the reset on the checkout page is a currency change like any other. A visitor who opens the checkout and goes back to the shop sees the base currency, and the GeoIP rules do not bring the local currency back, because they apply only on the first visit. The snippet in the next section remembers the visitor's currency before checkout and restores it afterwards. With Is multiple allowed = No, use it with your base currency in both settings lines: the checkout behaves as before, and the visitor gets their currency back when they leave it.

Force one checkout currency that is not the base currency

When the gateway accepts a currency other than the base currency, or only some of your currencies, set Is multiple allowed to Yes and force the checkout currency with code. With No the reset to the base currency would win over the code. The snippet below forces the checkout currency only for currencies the gateway cannot charge, and gives the visitor their own currency back on the next page outside checkout:

/*
 * Charge only in currencies the payment gateway accepts.
 * Requires FOX: Advanced tab, Is multiple allowed = Yes.
 * Child theme functions.php or a code snippets plugin.
 */
add_action('template_redirect', function () {
    if (!class_exists('WOOCS') || !function_exists('WC')) {
        return;
    }
    global $WOOCS;

    $accepted = array('USD', 'EUR'); // currencies the gateway can charge
    $fallback = 'USD';               // checkout currency for all other currencies

    // Custom checkout page: is_checkout() || is_page('your-checkout-slug')
    if (is_checkout()) {
        if (!in_array($WOOCS->current_currency, $accepted, true)) {
            $WOOCS->storage->set_val('woocs_before_checkout', $WOOCS->current_currency);
            $WOOCS->set_currency($fallback);
            if (WC()->cart) {
                WC()->cart->calculate_totals();
            }
        }
        return;
    }

    // Outside checkout: restore the currency the visitor had before
    $previous = $WOOCS->storage->get_val('woocs_before_checkout');
    if (!empty($previous)) {
        $WOOCS->storage->set_val('woocs_before_checkout', '');
        $WOOCS->set_currency($previous);
    }
}, 1);

To force one currency for everybody, list only that currency in $accepted and use it as $fallback. Points to check:

  • Custom checkout pages. is_checkout() is true on the page set as checkout in WooCommerce → Settings → Advanced and on pages that contain the checkout shortcode. A checkout built by a funnel or checkout plugin may be neither; add the is_page() condition from the comment.
  • Checkout by GeoIP rules must be off. This option in the Advanced tab switches the checkout to the currency of the visitor's country and overrides the forced currency.
  • Cached shop pages. The restore runs when WordPress builds a page, so behind a page cache it happens on the first page that is not served from the cache.

The simpler one-line versions of this code on our force a currency on the checkout page FAQ do the forcing without the restore.

Switch the currency by payment method

FOX cannot react to a click on a payment method by itself: on the classic checkout, choosing a method does not reload anything. The two snippets below make WooCommerce refresh the order review when the method changes and switch the currency in that refresh. They work with the [woocommerce_checkout] shortcode checkout, not with the Checkout block, and need Is multiple allowed = Yes. A payment method ID is the value of its radio button on the checkout page, for example bacs for Direct bank transfer.

/*
 * Classic checkout: change currency when a payment method is chosen.
 * Child theme functions.php.
 */
add_action('woocommerce_checkout_update_order_review', function ($post_data) {
    if (!class_exists('WOOCS')) {
        return;
    }
    global $WOOCS;
    parse_str($post_data, $data);

    $currency_by_method = array(
        'bacs'   => 'EUR', // payment method ID => currency it charges in
        'stripe' => 'USD',
    );

    $method = isset($data['payment_method']) ? $data['payment_method'] : '';
    if (isset($currency_by_method[$method]) && $WOOCS->current_currency !== $currency_by_method[$method]) {
        if (!$WOOCS->storage->get_val('woocs_before_checkout')) {
            $WOOCS->storage->set_val('woocs_before_checkout', $WOOCS->current_currency);
        }
        $WOOCS->set_currency($currency_by_method[$method]);
    }
});

add_action('wp_footer', function () {
    if (!is_checkout()) {
        return;
    }
    ?>
    <script>
    jQuery(function ($) {
        $(document.body).on('payment_method_selected', function () {
            $(document.body).trigger('update_checkout');
        });
    });
    </script>
    <?php
});

The reverse is built in and needs no code: the Payments tab hides or shows each gateway for chosen currencies (Payments rules and Payments behavior), so a gateway is offered only in currencies it can charge. See how to hide a payment gateway by currency.

Let customers pay in the currency they selected

The opposite setup is Is multiple allowed = Yes without any forcing code. The checkout keeps the visitor's currency, the order is stored in it together with the exchange rate of that moment, and the gateway is asked to charge that currency. Your code can read the setting as $WOOCS->is_multiple_allowed.

Checkout or cart jumps back to the base currency

  • Is multiple allowed is still No. This is the cause in most cases; the currency switches back after checkout explains the default.
  • Checkout by GeoIP rules is on and the visitor's country belongs to another currency.
  • Code in the theme or a snippet calls $WOOCS->set_currency() on the checkout page. Search for it, including old versions of the snippets above.
  • Disable on pages in the Options tab switches FOX off for the site root. WooCommerce sends checkout refreshes to the root address (/?wc-ajax=update_order_review), so the order review is recalculated without FOX and shows the base currency a moment after the page loads.
  • The cart or checkout page is cached, so it shows the currency of whoever loaded it first. Exclude both from every cache.

The gateway must accept every checkout currency

FOX hands the gateway the currency of the order; whether the payment succeeds depends on the gateway account. PayPal and Stripe accept many presentment currencies, but each has its own list, and a payout in another currency is converted by the provider at its own rate and fees. Check the lists, for PayPal in accepted PayPal currencies, and use the Payments tab so a currency never reaches a gateway that cannot charge it. A single-currency gateway, common with local providers, must use one of the forcing setups above.

Test a foreign-currency payment safely

FOX has no payment test mode of its own; use the gateway's sandbox or test mode. Place one test order in each currency you accept, then compare three places: the Order currency in the FOX box on the order screen, the amount on the gateway's test dashboard, and the order e-mail. All three should show the same currency and amount.

What multi-currency orders mean for the back office

Orders, refunds and order e-mails are in the customer's currency, and WooCommerce reports do not convert them to one currency on their own. Each order keeps its Order currency rate, which is what the guides on multi-currency analytics and where the order currency is stored build on. Changing Is multiple allowed later does not convert existing orders; an individual order can be converted with Change order currency and Recalculate order in the FOX box on the order screen, which changes the order record, not the payment already taken.

Which setup to choose

Your situationSetup
The gateway charges in the base currency onlyIs multiple allowed = No, approximate amounts on, optional restore snippet
The gateway charges one currency that is not the baseYes + forcing snippet with one accepted currency
The gateway accepts some of your currenciesYes + forcing snippet with the accepted list
Different gateways for different currenciesYes + Payments tab rules, or the payment method snippet
Every currency can be chargedYes, no code

If the checkout still shows a currency you did not expect, test with a default theme and only WooCommerce and FOX active, then open a topic on the FOX support forum with your Is multiple allowed setting, the checkout type (shortcode or block) and any currency code you use, and we will look at it.