woocommerce_wpml = $woocommerce_wpml; $this->woocommerce = $woocommerce; $this->install = new WCML_Multi_Currency_Install( $this, $woocommerce_wpml ); $this->init_currencies(); $this->load_filters = $this->are_filters_need_loading(); $this->prices = new WCML_Multi_Currency_Prices( $this, $woocommerce_wpml->get_setting( 'currency_options' ) ); $this->prices->add_hooks(); if ( $this->load_filters ) { $table_rate_shipping_multi_currency = new WCML_Multi_Currency_Table_Rate_Shipping(); $table_rate_shipping_multi_currency->add_hooks(); $this->coupons = new WCML_Multi_Currency_Coupons(); $this->shipping = new WCML_Multi_Currency_Shipping( $this, $sitepress, $wpdb ); $this->shipping->add_hooks(); } $this->reports = new WCML_Multi_Currency_Reports( $woocommerce_wpml, $sitepress, $wpdb ); $this->reports->add_hooks(); $this->orders = new WCML_Multi_Currency_Orders( $this, $woocommerce_wpml, $wp ); $this->admin_currency_selector = new WCML_Admin_Currency_Selector( $woocommerce_wpml, new WCML_Admin_Cookie( '_wcml_dashboard_currency' ) ); $this->admin_currency_selector->add_hooks(); $this->custom_prices = new WCML_Custom_Prices( $woocommerce_wpml, $wpdb ); $this->custom_prices->add_hooks(); $this->currency_switcher = new WCML_Currency_Switcher( $woocommerce_wpml, $sitepress ); $this->currency_switcher->add_hooks(); $this->currency_switcher_ajax = new WCML_Currency_Switcher_Ajax( $woocommerce_wpml ); $this->exchange_rate_services = new WCML_Exchange_Rates( $this->woocommerce_wpml, $wp_locale ); $this->exchange_rate_services->initialize_settings(); $this->exchange_rate_services->add_actions(); $this->exchange_rate_services->add_service( 'fixerio', new WCML_Exchange_Rates_Fixerio() ); $this->exchange_rate_services->add_service( 'currencylayer', new WCML_Exchange_Rates_Currencylayer() ); $this->currencies_payment_gateways = make( WCML_Currencies_Payment_Gateways::class ); $this->currencies_payment_gateways->add_hooks(); if ( defined( 'W3TC' ) ) { $this->W3TC = new WCML_W3TC_Multi_Currency(); } WCML_Multi_Currency_Resources::set_up( $this, $this->woocommerce_wpml ); WCML_Multi_Currency_Configuration::set_up( $this, $woocommerce_wpml ); add_filter( 'init', [ $this, 'init' ], 5 ); if ( is_ajax() ) { add_action( 'wp_ajax_nopriv_wcml_switch_currency', [ $this, 'switch_currency' ] ); add_action( 'wp_ajax_wcml_switch_currency', [ $this, 'switch_currency' ] ); } } public function are_filters_need_loading() { $load = false; if ( ! is_admin() && $this->get_client_currency() !== wcml_get_woocommerce_currency_option() ) { $load = true; } else { if ( is_ajax() && $this->get_client_currency() !== wcml_get_woocommerce_currency_option() ) { $ajax_actions = apply_filters( 'wcml_multi_currency_ajax_actions', [ 'woocommerce_get_refreshed_fragments', 'woocommerce_update_order_review', 'woocommerce_checkout', 'woocommerce_add_to_cart', 'woocommerce_update_shipping_method', 'woocommerce_json_search_products_and_variations', 'woocommerce_add_coupon_discount', ] ); if ( ( isset( $_POST['action'] ) && in_array( $_POST['action'], $ajax_actions ) ) || ( isset( $_GET['action'] ) && in_array( $_GET['action'], $ajax_actions ) ) ) { $load = true; } } } /** * @deprecated 3.9.2 */ $load = apply_filters( 'wcml_load_multi_currency', $load ); /** * @since 3.9.2 */ $load = apply_filters( 'wcml_load_multi_currency_in_ajax', $load ); return $load; } public function init() { add_filter( 'wcml_get_client_currency', [ $this, 'get_client_currency' ] ); add_action( 'wp_footer', [ $this, 'maybe_show_switching_currency_prompt_dialog' ] ); add_action( 'wp_footer', [ $this, 'maybe_reset_cart_fragments' ] ); if( WCML\Rest\Functions::isRestApiRequest() ){ add_filter( 'rest_request_before_callbacks', [ $this, 'set_request_currency' ], 10, 3 ); } } public function enable() { $this->woocommerce_wpml->settings['enable_multi_currency'] = WCML_MULTI_CURRENCIES_INDEPENDENT; $this->woocommerce_wpml->update_settings(); } public function disable() { $this->woocommerce_wpml->settings['enable_multi_currency'] = WCML_MULTI_CURRENCIES_DISABLED; $this->woocommerce_wpml->update_settings(); } public function init_currencies() { global $sitepress; $this->default_currency = wcml_get_woocommerce_currency_option(); $this->currencies = $this->woocommerce_wpml->settings['currency_options']; // Add default currency if missing (set when MC is off). if ( ! empty( $this->default_currency ) && ! isset( $this->currencies[ $this->default_currency ] ) ) { $this->currencies[ $this->default_currency ] = []; } $save_to_db = false; $active_languages = $sitepress->get_active_languages(); $currency_defaults = [ 'rate' => 0, 'position' => 'left', 'thousand_sep' => ',', 'decimal_sep' => '.', 'num_decimals' => 2, 'rounding' => 'disabled', 'rounding_increment' => 1, 'auto_subtract' => 0, 'location_mode' => 'all', 'countries' => [], ]; foreach ( $this->currencies as $code => $currency ) { foreach ( $currency_defaults as $key => $val ) { if ( ! isset( $currency[ $key ] ) ) { $this->currencies[ $code ][ $key ] = $val; $save_to_db = true; } } foreach ( $active_languages as $language ) { if ( ! isset( $currency['languages'][ $language['code'] ] ) ) { $this->currencies[ $code ]['languages'][ $language['code'] ] = 1; $save_to_db = true; } } } $this->currency_codes = array_keys( $this->currencies ); // default language currencies. foreach ( $active_languages as $language ) { if ( ! isset( $this->woocommerce_wpml->settings['default_currencies'][ $language['code'] ] ) ) { $this->woocommerce_wpml->settings['default_currencies'][ $language['code'] ] = 0; $save_to_db = true; } } // sanity check. if ( isset( $this->woocommerce_wpml->settings['default_currencies'] ) ) { foreach ( $this->woocommerce_wpml->settings['default_currencies'] as $language => $value ) { if ( ! isset( $active_languages[ $language ] ) ) { unset( $this->woocommerce_wpml->settings['default_currencies'][ $language ] ); $save_to_db = true; } if ( ! empty( $value ) && ! in_array( $value, $this->currency_codes ) && $value !== 'location' ) { $this->woocommerce_wpml->settings['default_currencies'][ $language ] = 0; $save_to_db = true; } } } // add missing currencies to currencies_order. if ( isset( $this->woocommerce_wpml->settings['currencies_order'] ) ) { foreach ( $this->currency_codes as $currency ) { if ( ! in_array( $currency, $this->woocommerce_wpml->settings['currencies_order'] ) ) { $this->woocommerce_wpml->settings['currencies_order'][] = $currency; $save_to_db = true; } } } if ( $save_to_db ) { $this->woocommerce_wpml->update_settings(); } // force disable multi-currency when the default currency is empty. if ( empty( $this->default_currency ) ) { $this->woocommerce_wpml->settings['enable_multi_currency'] = WCML_MULTI_CURRENCIES_DISABLED; } } /** * * @return string * @since 3.9.2 */ public function get_default_currency() { return $this->default_currency; } public function get_currencies( $include_default = false ) { // by default, exclude default currency. $currencies = []; $default_currency = wcml_get_woocommerce_currency_option(); foreach ( $this->currencies as $key => $value ) { if ( $default_currency != $key || $include_default ) { $currencies[ $key ] = $value; } } return $currencies; } public function get_currency_codes() { return $this->currency_codes; } /** * @param string $code * * @return bool */ public function is_currency_active( $code ) { return in_array( $code, $this->get_currency_codes(), true ); } /** * @return mixed|string */ public function get_currency_code() { $currency_code = wcml_get_woocommerce_currency_option(); $currency_codes = $this->get_currency_codes(); if ( ! in_array( $currency_code, $currency_codes, true ) ) { $currency_code = $this->woocommerce_wpml->multi_currency->get_default_currency(); } return $currency_code; } public function get_currency_details_by_code( $code ) { if ( isset( $this->currencies[ $code ] ) ) { return $this->currencies[ $code ]; } return false; } public function delete_currency_by_code( $code, $settings = false, $update = true ) { $settings = $settings ? $settings : $this->woocommerce_wpml->get_settings(); unset( $settings['currency_options'][ $code ] ); if ( isset( $settings['currencies_order'] ) ) { foreach ( $settings['currencies_order'] as $key => $cur_code ) { if ( $cur_code == $code ) { unset( $settings['currencies_order'][ $key ] ); } } } if ( $update ) { $this->woocommerce_wpml->update_settings( $settings ); } return $settings; } public function get_exchange_rates() { if ( empty( $this->exchange_rates ) ) { $this->exchange_rates = [ wcml_get_woocommerce_currency_option() => 1 ]; $woo_currencies = get_woocommerce_currencies(); $currencies = $this->get_currencies(); foreach ( $currencies as $code => $currency ) { if ( ! empty( $woo_currencies[ $code ] ) ) { $this->exchange_rates[ $code ] = $currency['rate']; } } } return apply_filters( 'wcml_exchange_rates', $this->exchange_rates ); } public function get_client_currency() { global $sitepress; if( \WCML\Rest\Functions::isRestApiRequest() ){ return $this->get_rest_currency(); } if ( ! empty( $_REQUEST['woocommerce_quick_edit'] ) ) { return wcml_get_woocommerce_currency_option(); } $current_language = $sitepress->get_current_language(); $current_language = ( $current_language !== 'all' && ! is_null( $current_language ) ) ? $current_language : $sitepress->get_default_language(); if ( ! $this->client_currency && isset( $this->woocommerce_wpml->settings['display_custom_prices'] ) && $this->woocommerce_wpml->settings['display_custom_prices'] && is_product() ) { $product_obj = wc_get_product(); $current_product_id = get_post()->ID; $original_product_language = $this->woocommerce_wpml->products->get_original_product_language( $current_product_id ); $default = false; if ( $product_obj->get_type() === 'variable' ) { foreach ( $product_obj->get_children() as $child ) { if ( ! get_post_meta( apply_filters( 'translate_object_id', $child, get_post_type( $child ), true, $original_product_language ), '_wcml_custom_prices_status', true ) ) { $default = true; break; } } } elseif ( ! get_post_meta( apply_filters( 'translate_object_id', $current_product_id, get_post_type( $current_product_id ), true, $original_product_language ), '_wcml_custom_prices_status', true ) ) { $default = true; } if ( $default ) { $this->client_currency = wcml_get_woocommerce_currency_option(); } } if ( isset( $_GET['pay_for_order'] ) && $_GET['pay_for_order'] == true && isset( $_GET['key'] ) ) { $cache_group = 'wcml_client_currency'; $cache_key = 'order' . sanitize_text_field( $_GET['key'] ); $order_currency = wp_cache_get( $cache_key, $cache_group ); if ( $order_currency ) { $this->client_currency = $order_currency; } else { $order_id = wc_get_order_id_by_order_key( wc_clean( wp_unslash( $_GET['key'] ) ) ); if ( $order_id ) { $this->client_currency = get_post_meta( $order_id, '_order_currency', true ); wp_cache_set( $cache_key, $this->client_currency, $cache_group ); } } } if ( isset( $_GET['action'] ) && $_GET['action'] === 'woocommerce_json_search_products_and_variations' && ! empty( $_COOKIE['_wcml_order_currency'] ) ) { $this->client_currency = $_COOKIE['_wcml_order_currency']; } $this->client_currency = $this->maybe_get_currency_by_geolocation( $this->client_currency ); $client_currency_language = wcml_user_store_get( self::CURRENCY_LANGUAGE_STORAGE_KEY ); if ( is_null( $this->client_currency ) && $current_language !== $client_currency_language ) { $language_default_currency = $this->get_language_default_currency( $current_language ); if ( $language_default_currency ) { $current_currency = wcml_user_store_get( self::CURRENCY_STORAGE_KEY ); $prevent_switching = apply_filters( 'wcml_switch_currency_exception', false, $current_currency, $language_default_currency, true ); $this->client_currency = $language_default_currency; if ( ! array_key_exists( 'force_switch', $_POST ) && $prevent_switching ) { $this->switching_currency_html = $prevent_switching['prevent_switching']; } } } // edit order page. if ( isset( $_SERVER['HTTP_REFERER'] ) ) { $arg = parse_url( $_SERVER['HTTP_REFERER'] ); if ( isset( $arg['query'] ) ) { parse_str( $arg['query'], $arg ); if ( isset( $arg['post'] ) && get_post_type( $arg['post'] ) == 'shop_order' ) { $this->client_currency = get_post_meta( $arg['post'], '_order_currency', true ); } } } // client currency in general / if enabled for this language. if ( is_null( $this->client_currency ) ) { $storage_currency = wcml_user_store_get( self::CURRENCY_STORAGE_KEY ); if ( $storage_currency && ! empty( $this->currencies[ $storage_currency ]['languages'][ $current_language ] ) ) { $this->client_currency = $storage_currency; } } if ( is_null( $this->client_currency ) ) { $woocommerce_currency = wcml_get_woocommerce_currency_option(); // fall on WC currency if enabled for this language. if ( ! empty( $this->currencies[ $woocommerce_currency ]['languages'][ $current_language ] ) ) { $this->client_currency = $woocommerce_currency; } else { // first currency enabled for this language. foreach ( $this->currencies as $code => $data ) { if ( ! empty( $data['languages'][ $current_language ] ) ) { $this->client_currency = $code; break; } } } } $this->client_currency = apply_filters( 'wcml_client_currency', $this->client_currency ); if ( $this->client_currency ) { wcml_user_store_set( self::CURRENCY_STORAGE_KEY, $this->client_currency ); wcml_user_store_set( self::CURRENCY_LANGUAGE_STORAGE_KEY, $current_language ); } return $this->client_currency; } /** * @param null|string $client_currency * * @return null|string */ public function maybe_get_currency_by_geolocation( $client_currency ) { if( Geolocation::MODE_BY_LOCATION !== $this->woocommerce_wpml->get_setting( 'currency_mode' ) ){ return $client_currency; } $currency_not_in_storage = is_null( $client_currency ) && ! wcml_user_store_get( self::CURRENCY_STORAGE_KEY ); $is_checkout_ajax = is_ajax() && isset( $_GET['wc-ajax'] ) && 'update_order_review' === $_GET['wc-ajax']; if ( $currency_not_in_storage || $is_checkout_ajax ) { $location_currency = $this->get_currency_by_geolocation(); if ( $location_currency ) { return $location_currency; } } return $client_currency; } /** * @return bool|string */ private function get_currency_by_geolocation() { $cache_group = 'WCML_Multi_Currency'; $wpml_cache = new WPML_WP_Cache( $cache_group ); wp_cache_add_non_persistent_groups( $cache_group ); $cache_key = 'location_currency'; $found = false; $location_currency = $wpml_cache->get( $cache_key, $found ); if ( ! $found ) { $location_currency = Geolocation::getCurrencyCodeByUserCountry(); if ( ! $this->is_currency_active( $location_currency ) || ! Geolocation::isCurrencyAvailableForCountry( $this->woocommerce_wpml->settings['currency_options'][ $location_currency ] ) ) { $location_currency = Geolocation::getFirstAvailableCountryCurrencyFromSettings( $this->woocommerce_wpml->settings['currency_options'] ); } $wpml_cache->set( $cache_key, $location_currency ); } return $location_currency; } public function maybe_show_switching_currency_prompt_dialog() { if ( $this->switching_currency_html ) { echo $this->switching_currency_html; } } public function maybe_reset_cart_fragments() { global $woocommerce; if ( ! empty( $woocommerce->session ) && $woocommerce->session->get( 'client_currency_switched' ) ) { ?> session->set( 'client_currency_switched', false ); } } public function set_client_currency( $currency ) { global $sitepress; $this->client_currency = $currency; wcml_user_store_set( self::CURRENCY_STORAGE_KEY, $currency ); wcml_user_store_set( self::CURRENCY_LANGUAGE_STORAGE_KEY, $sitepress->get_current_language() ); do_action( 'wcml_set_client_currency', $currency ); } public function switch_currency() { /** * @global SitePress $GLOBALS['sitepress'] * @name $sitepress */ global $sitepress; $currency = filter_input( INPUT_POST, 'currency', FILTER_SANITIZE_FULL_SPECIAL_CHARS ); $force_switch = filter_input( INPUT_POST, 'force_switch', FILTER_SANITIZE_FULL_SPECIAL_CHARS ); parse_str( filter_input( INPUT_POST, 'params', FILTER_SANITIZE_STRING ), $params ); $from_currency = $this->client_currency; do_action( 'wcml_before_switch_currency', $currency, $force_switch ); if ( ! $force_switch && apply_filters( 'wcml_switch_currency_exception', false, $from_currency, $currency ) ) { die(); } $lang = Obj::prop( 'lang', $params ); if ( $lang ) { $sitepress->switch_lang( $lang ); } $this->set_client_currency( $currency ); // force set user cookie when user is not logged in. global $woocommerce, $current_user; if ( empty( $woocommerce->session->data ) && empty( $current_user->ID ) ) { $woocommerce->session->set_customer_session_cookie( true ); } $woocommerce->session->set( 'client_currency_switched', true ); do_action( 'wcml_switch_currency', $currency ); $response = $this->prices->filter_pre_selected_widget_prices_in_new_currency( [], $currency, $from_currency, $params ); wp_send_json_success( $response ); } public function get_currencies_without_cents() { return apply_filters( 'wcml_currencies_without_cents', $this->currencies_without_cents ); } /** * @param string $language * * @return string|bool */ public function get_language_default_currency( $language ) { $default_currencies = $this->woocommerce_wpml->settings['default_currencies']; if ( isset( $default_currencies[ $language ] ) ) { if ( 'location' === $default_currencies[ $language ] ) { $location_currency = $this->get_currency_by_geolocation(); if ( $location_currency ) { return $location_currency; } } else { return $default_currencies[ $language ]; } } return false; } /** * Set reports currency for REST request. * * @param WP_REST_Response|WP_HTTP_Response|WP_Error|mixed $response Result to send to the client. Usually a WP_REST_Response or WP_Error. * @param array $handler Route handler used for the request. * @param WP_REST_Request $request Request used to generate the response. * * @return WP_REST_Response|WP_HTTP_Response|WP_Error|mixed */ public function set_request_currency( $response, $handler, $request ) { $this->rest_currency = Obj::prop( 'currency', $request->get_params() ); return $response; } /** * Get REST currency * * @return string */ public function get_rest_currency() { return $this->rest_currency ? $this->rest_currency : wcml_get_woocommerce_currency_option(); } }