The code in this article is to be considered a customisation. As such, it's outside the scope of our support service. Should you need assistance implementing the code, please feel free to contact us to request a consultation.



The processing of payments depends entirely on the payment gateways. It might be possible to convert order totals to another currency on the fly, just before payment. This, however, is outside the scope of the Currency Switcher, and it requires some customisation to alter how the payment plugins work. 


An alternative solution could be to force the whole checkout process in a specific currency. Normally we don't recommend this approach, as it might impact on conversion rates, but it could be simpler to implement than customising a payment plugin. You can read how you can force the checkout to a specific currency in the following article: How to change the selected currency via code - Forcing checkout in a specific currency.


If you wish to allow customers to place orders in their currency of choice, and just change the payment currency, please keep reading below.


Important

The possibility to convert payment amounts on the fly is dependent on the architecture of the payment plugins and gateways. Some payment plugins may be altered, others may not.


Below you can find how to implement such modification with our PayPal Standard Multi-account plugin installed (the PayPal gateway included with WooCommerce doesn't support this modification). Please feel free to use it as a reference to modify other payment gateways.


How to alter the flow of PayPal Standard plugin

WooCommerce 2.3 and later. Requires Aelia PayPal Standard Multi-account plugin.


The following instructions show how to alter the flow of the PayPal Standard plugin included with WooCommerce, so that the order amounts are converted to a different currency before being processed.


Step 1 - Install the Aelia PayPal Standard Multi-account plugin

Even though the plugin was designed to allow using multiple PayPal accounts, you can still use a single account with it. To do so, simply install and enable the plugin, no further configuration is needed.


Step 2 - Ensure that the payment gateway won't disable itself

Since we are trying to force a payment in a specific currency, chances are that the source currency is not supported by the payment gateway. For example, we might want to accept orders in Indian Rupees, which are not accepted by PayPal, but force the payment in Euro. The PayPal Basic plugin, however, would detect that the active currency at checkout is "Indian Rupees" and it would disable itself. The code below will "trick" it into thinking that the active currency is always a supported currency.    

/**
 * Adds the active currency to the ones considered valid by the PayPal Basic
 * gateway. This will ensure that the gateway will appear at checkout, regardless
 * of the active currency. NOTE: this won't guarantee that payments will be
 * processed correctly. If the PayPal gateway will receive an unsupported currency,
 * the payment will fail.
 *
 * @param array currencies The array of currencies supported by PayPal.
 * @return array The array of currencies, with the active currency added to it.
 * @author Aelia <support@aelia.co>
 */
function paypal_basic_add_valid_currency($currencies) {
  $currencies[] = get_woocommerce_currency();
  return $currencies;
}
add_filter('woocommerce_paypal_supported_currencies', 'paypal_basic_add_valid_currency', 10, 1);

    

Step 3 - Convert order totals before payment

Now the PayPal Basic gateway is going to accept order in Indian Rupees (INR). However, if such totals were to be sent to PayPal servers, the payment would fail, because they don't support INR. The code below converts the totals from INR to EUR, before passing them to the remote servers. It can be easily adapted to convert any source currency to any destination currency.           

/**
 * Processs the arguments that will be used by PayPal basic gateway, converting
 * the totals that will be passed to the gateway into a different currency.
 *
 * @param array paypal_args The original arguments used by the PayPal Basic
 * gateway.
 * @return array The arguments, with the totals eventually converted to another
 * currency.
 * @author Aelia <support@aelia.co>
 */
function aelia_paypal_standard_convert_order_currency($paypal_args) {
  // Get the active currency
  $source_currency = get_woocommerce_currency();
  /* An array of currencies which should be converted to a target currency. The
   * key is the currency to convert, the value is the target currency. For
   * example, 'INR' => 'USD' will convert Indian Rupees to US Dollars.
   */
  $currencies_to_convert = array(
    // Convert Indian Rupees to Euro
    'INR' => 'USD',
  );

  if(isset($currencies_to_convert[$source_currency])) {
    // All order amounts will be converted to this currency
    $destination_currency = $currencies_to_convert[$source_currency];

    $amount_idx = 1;
    while(isset($paypal_args['amount_' . $amount_idx])) {
      $paypal_args['amount_' . $amount_idx] = apply_filters('wc_aelia_cs_convert',
                                                            $paypal_args['amount_' . $amount_idx],
                                                            $source_currency,
                                                            $destination_currency);
      $amount_idx++;
    }

    if(!empty($paypal_args['discount_amount_cart'])) {
      $paypal_args['discount_amount_cart'] = apply_filters('wc_aelia_cs_convert',
                                                           $paypal_args['discount_amount_cart'],
                                                           $source_currency,
                                                           $destination_currency);
    }

    if(!empty($paypal_args['tax_cart'])) {
      $paypal_args['tax_cart'] = apply_filters('wc_aelia_cs_convert',
                                               $paypal_args['tax_cart'],
                                               $source_currency,
                                               $destination_currency);
    }
    
    // WooCommerce 2.6 and later may or may not be using the shipping_1 argument
    if(!empty($paypal_args['shipping_1'])) {
      $paypal_args['shipping_1'] = apply_filters('wc_aelia_cs_convert',
                                                 $paypal_args['shipping_1'],
                                                 $source_currency,
                                                 $destination_currency);
    }

    // Change the currency to the target one
    $paypal_args['currency_code'] = $destination_currency;
  }

  return $paypal_args;
}
add_filter('woocommerce_paypal_args', 'aelia_paypal_standard_convert_order_currency', 10, 1);

   

Step 4 - Handle Instant Payment Notifications (IPN) received by PayPal

PayPal is going to send an Instant Payment Notification (IPN) as soon as a payment is successful. The IPN contains the total paid by the client, which is going to be checked against the order total saved in WooCommerce. Since we converted the payment total to another currency in step 3, the two amounts don't match, and that would cause the payment notification to be rejected by WooCommerce. To prevent this, we must alter the received data, so that the totals will match again.  

/**
 * Processes the data sent with PayPal Instant Payment Notifications, ensuring
 * that the payment totals match the amounts saved in WooCommerce.
 *
 * @param array payment_data The data contained in PayPal IPN.
 * @param WC_Order order The order to which the IPN data refers.
 * @author Aelia <support@aelia.co>
 */
function aelia_pre_process_payment_status_completed_data($payment_data, $order) {
  // Set the list of currencies for which the IPN data should be processed.
  // IPN data related to other currencies will be left untouched
  $currencies_to_process = array('INR');

  WC_Gateway_Paypal_MultiAccount::log('PRE PROCESSING PAYMENT DATA');
  if(in_array($order->get_order_currency(), $currencies_to_process)) {
    /* Replace the total passed by PayPal with the one from the order.
     *
     * WHY
     * The amount passed to PayPal during payment was converted to a different
     * currency, and it doesn't match the one stored with the order. Replacing
     * the total will lower the security a bit, but it will allow the cross-checks
     * to pass.
     */
    $payment_data['mc_gross'] = $order->get_total();
    // Also replace the currency with the one from the order
    $payment_data['mc_currency'] = $order->get_order_currency();
  }
  return $payment_data;
}
add_filter('payment_status_completed_data', 'aelia_pre_process_payment_status_completed_data', 10, 2); 

       

Step 5 - Install the code on your site

Now that we have the code, we just need to add it to our site. To do, simply follow the instructions below.

  1. Go to your site's folder, then go to /wp-content/themes/<your theme>/ folder.
  2. To be on the safe side, make a copy of file functions.php, that you will find in the theme folder. That is the file that you will be modifying, having a copy will allow you to roll back any change, if needed.
  3. Open file functions.php.
  4. Paste the code from the previous steps at the bottom of the file and save the file.
The PayPal Basic gateway will now appear at checkout when any currency is active, and the totals will be converted from INR to EUR before they are passed to PayPal. 


Disclaimer

The above solution is provided as is, as a guideline, without any implicit or explicit warranty. It's your responsibility to review, alter and test the code before using it on your site(s). We will not be able to provide free assistance for any issue deriving from the use of the code. 


Not a coder?

If you don't feel comfortable working with code, we can implement this modification on your site for a fee. To avail of such service, please contact us and we will get back to you with further details.


You can purchase the Currency Switcher from our online shop.