Currency Conversion Between WooCommerce Shops Using 3rd Exchange Rates
17982
wp-singular,documentation-template-default,single,single-documentation,postid-17982,wp-theme-awake,wp-child-theme-awake-child,theme-awake,eltd-core-1.1,woocommerce-no-js,awake child-child-ver-1.0.0,awake-ver-1.8,eltd-smooth-scroll,eltd-smooth-page-transitions,eltd-mimic-ajax,eltd-grid-1200,eltd-blog-installed,eltd-default-style,eltd-fade-push-text-top,eltd-header-standard,eltd-sticky-header-on-scroll-down-up,eltd-default-mobile-header,eltd-sticky-up-mobile-header,eltd-menu-item-first-level-bg-color,eltd-dropdown-slide-from-top,eltd-,wpb-js-composer js-comp-ver-8.1,vc_responsive
 

Currency Conversion Between WooCommerce Shops Using 3rd Exchange Rates

WP Global Cart / Currency Conversion Between WooCommerce Shops Using 3rd Exchange Rates
Share on FacebookTweet about this on TwitterShare on Google+Share on LinkedInShare on TumblrPin on PinterestEmail this to someonePrint this page

Currency Conversion Between WooCommerce Shops Using 3rd Exchange Rates

When using WP Global Cart with multiple WooCommerce shops, each shop can use its own currency. This is useful when your stores operate in different countries or markets, but it also means that product prices may need to be converted when products are synchronized between shops.

WP Global Cart includes the WOOGC_Currency_Converter class, which provides a simple way to convert product prices between currencies using the European Central Bank (ECB) reference exchange rates.

The ECB publishes its exchange rates against the Euro. The converter uses these rates to calculate conversions between any two supported currencies. For example, a product priced in RON can be converted to USD by first converting the RON value to EUR and then converting the EUR value to USD.

The conversion can be performed with a simple function call:

$value = WOOGC_Currency_Converter::convert(
    $amount,
    $from_currency,
    $to_currency
);

For example:

$value = WOOGC_Currency_Converter::convert(
    100,
    'EUR',
    'USD'
);

The exchange rates are stored in WordPress options and updated periodically. Previously stored rates remain available if the ECB does not publish new rates or the ECB service is temporarily unavailable.

No Additional Currency Plugin Required

For stores that only need programmatic currency conversion, using the built-in converter can avoid the need for an additional currency plugin such as Aelia Currency Switcher, FOX – Currency Switcher for WooCommerce, or other WooCommerce multi-currency solutions.

These plugins can provide additional functionality such as displaying multiple currencies to customers, currency switching, pricing rules, and payment-related features. However, they are not necessary when the only requirement is to convert synchronized product prices from one shop currency to another.

Ideal for Multi-Currency WP Global Cart Shops

This makes WOOGC_Currency_Converter particularly useful when WP Global Cart connects WooCommerce shops using different currencies. The original product price and currency can be retained, while the destination shop calculates the corresponding local price using the latest available ECB exchange rates.

As a result, currency conversion can be handled directly as part of the WP Global Cart product synchronization process, without introducing another plugin dependency.

The code should be placed inside a custom file in the /wp-content/mu-plugins/ folder.

    /**
     * WP Global Cart - ECB Currency Converter
     *
     * Retrieves Euro foreign exchange reference rates from the ECB
     * and converts amounts between currencies using EUR as the base.
     */
    class WOOGC_Currency_Converter {

        /**
         * ECB daily XML feed.
         */
        const ECB_FEED_URL = 'https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml';

        /**
         * WordPress option used to store the rates.
         */
        const OPTION_RATES = 'woogc_ecb_currency_rates';

        /**
         * WordPress option used to store the date of the last
         * successfully downloaded ECB rates.
         */
        const OPTION_DATE = 'woogc_ecb_currency_rates_date';

        /**
         * WordPress option used to store the last update timestamp.
         */
        const OPTION_UPDATED = 'woogc_ecb_currency_rates_updated';

        /**
         * Convert an amount from one currency to another.
         *
         * Example:
         * 100 EUR -> USD
         * 100 RON -> USD
         *
         * @param float  $amount
         * @param string $from_currency
         * @param string $to_currency
         *
         * @return float|false
         */
        public static function convert( $amount, $from_currency, $to_currency ) {

            $amount = (float) $amount;

            $from_currency = strtoupper( trim( $from_currency ) );
            $to_currency   = strtoupper( trim( $to_currency ) );

            // Nothing to convert.
            if ( $from_currency === $to_currency ) {
                return $amount;
            }

            // Make sure we have current rates, or the latest available rates.
            $rates = self::get_rates();

            if ( ! is_array( $rates ) || empty( $rates ) ) {
                return false;
            }

            /*
             * EUR is the base currency.
             *
             * Example:
             * EUR = 1
             * USD = 1.1551
             * RON = 5.2568
             */
            $from_rate = 1.0;
            $to_rate   = 1.0;

            /*
             * Currency other than EUR must exist in the ECB rates.
             */
            if ( 'EUR' !== $from_currency ) {

                if ( ! isset( $rates[ $from_currency ] ) ) {
                    return false;
                }

                $from_rate = (float) $rates[ $from_currency ];
            }

            if ( 'EUR' !== $to_currency ) {

                if ( ! isset( $rates[ $to_currency ] ) ) {
                    return false;
                }

                $to_rate = (float) $rates[ $to_currency ];
            }

            /*
             * Convert:
             *
             * source currency -> EUR -> target currency
             *
             * Example RON -> USD:
             *
             * 100 / 5.2568 * 1.1551
             */
            return ( $amount / $from_rate ) * $to_rate;
        }

        /**
         * Get the currently stored ECB rates.
         *
         * This will attempt to update the rates once per day.
         * If today's update is unavailable, the previously stored
         * successful rates are returned.
         *
         * @return array|false
         */
        public static function get_rates() {

            $stored_rates = get_option( self::OPTION_RATES, array() );
            $stored_date  = get_option( self::OPTION_DATE, '' );

            /*
             * If we already have rates downloaded today, use them.
             */
            $today = current_time( 'Y-m-d' );

            if (
                ! empty( $stored_rates ) &&
                $stored_date === $today
            ) {
                return $stored_rates;
            }

            /*
             * Try to download fresh ECB rates.
             */
            $new_rates = self::update_rates();

            /*
             * Successful update.
             */
            if ( is_array( $new_rates ) && ! empty( $new_rates ) ) {
                return $new_rates;
            }

            /*
             * ECB unavailable / no new rates today.
             *
             * Fall back to the last successful rates.
             */
            if ( ! empty( $stored_rates ) ) {
                return $stored_rates;
            }

            return false;
        }

        /**
         * Download and store the latest ECB rates.
         *
         * @return array|false
         */
        public static function update_rates() {

            $response = wp_remote_get(
                self::ECB_FEED_URL,
                array(
                    'timeout'     => 15,
                    'redirection' => 3,
                    'sslverify'   => true,
                    'headers'     => array(
                        'Accept' => 'application/xml,text/xml',
                    ),
                )
            );

            if ( is_wp_error( $response ) ) {
                return false;
            }

            $status_code = wp_remote_retrieve_response_code( $response );

            if ( 200 !== $status_code ) {
                return false;
            }

            $body = wp_remote_retrieve_body( $response );

            if ( empty( $body ) ) {
                return false;
            }

            /*
             * Prevent XML external entity processing.
             */
            libxml_use_internal_errors( true );

            $xml = simplexml_load_string(
                $body,
                'SimpleXMLElement',
                LIBXML_NONET | LIBXML_NOCDATA
            );

            if ( false === $xml ) {
                libxml_clear_errors();
                return false;
            }

            libxml_clear_errors();

            $rates = array(
                'EUR' => 1.0,
            );

            /*
             * ECB XML structure:
             *
             * <Cube currency="USD" rate="1.1551"/>
             */
            $currency_nodes = $xml->xpath(
                '//*[local-name()="Cube"][@currency and @rate]'
            );

            if ( empty( $currency_nodes ) ) {
                return false;
            }

            foreach ( $currency_nodes as $node ) {

                $currency = strtoupper( (string) $node['currency'] );
                $rate     = (float) $node['rate'];

                if ( empty( $currency ) || $rate <= 0 ) {
                    continue;
                }

                $rates[ $currency ] = $rate;
            }

            /*
             * Make sure we got a reasonable set of rates.
             */
            if ( count( $rates ) < 2 ) {
                return false;
            }

            /*
             * Save only after successfully parsing the complete feed.
             *
             * This is important: a failed/invalid request must never
             * overwrite the last known-good rates.
             */
            $today = current_time( 'Y-m-d' );

            update_option(
                self::OPTION_RATES,
                $rates,
                false
            );

            update_option(
                self::OPTION_DATE,
                $today,
                false
            );

            update_option(
                self::OPTION_UPDATED,
                time(),
                false
            );

            return $rates;
        }

        /**
         * Get information about the currently stored rates.
         *
         * Useful for debugging/admin UI.
         *
         * @return array
         */
        public static function get_status() {

            return array(
                'date'    => get_option( self::OPTION_DATE, '' ),
                'updated' => get_option( self::OPTION_UPDATED, 0 ),
                'rates'   => get_option( self::OPTION_RATES, array() ),
            );
        }
    } 

0
Would love your thoughts, please comment.x
()
x