Change currency format in Drupal Commerce

Sun, 14/08/2016 - 13:14

Defaults shipped with Drupal Commerce should work fine for most stores. However, exactly because of this, some of the details can be annoying and unnecessary for a specific project. The way currencies are formatted is one of those things.

By default, Commerce shows all values with the decimals separated by a period. For projects that need large amounts (e.g. high end jewelry or fashion pieces, aircraft parts, cars, etc.), the decimals have no place and it's better to remove them.

There are two ways to achieve this:

  1. Use the Commerce Currency Settings module.
  2. Implement hook_commerce_currency_info_alter() in your custom module.

Since the task is very simple and will most likely never need to be updated after initial setup, there is no need to install another module. This means less components to think about and update in the long run, and less pages in the admin.

By implementing this in your custom module you will also get complete freedom to change the format in which the values are displayed. You can replace the dollar sign with USD, move it before / after the value or add custom labels.

Here's the code you need to use:

/**
 * Implements hook_commerce_currency_info_alter().
 */
function YOUR_MODULE_commerce_currency_info_alter(&$currencies) {
  // Get the abbreviation of the default currency. This will return "USD" for
  // US Dollars, "EUR" for Euros, etc.
  // If your site is using multiple currencies, you can skip this and just use
  // the abbreviation of the currency you want to change the format for.
  $default_currency = commerce_default_currency();
  $currencies[$default_currency]['format_callback'] = 'YOUR_MODULE_commerce_currency_format';
}

/**
 * Commerce currency format callback.
 */
function YOUR_MODULE_commerce_currency_format($amount, $currency, $currency_code, $object = NULL, $convert = TRUE) {
  // Format the price as a number.
  $price = number_format(commerce_currency_round(abs($amount), $currency), 0, $currency['decimal_separator'], $currency['thousands_separator']);

  // Establish the replacement values to format this price for its currency.
  $replacements = array(
    '@code_before' => $currency['code_placement'] == 'before' ? $currency['code'] : '',
    '@symbol_before' => $currency['symbol_placement'] == 'before' ? $currency['symbol'] : '',
    '@price' => $price,
    '@symbol_after' => $currency['symbol_placement'] == 'after' ? $currency['symbol'] : '',
    '@code_after' => $currency['code_placement'] == 'after' ? $currency['code'] : '',
    '@negative' => $amount < 0 ? '-' : '',
    '@symbol_spacer' => $currency['symbol_spacer'],
    '@code_spacer' => $currency['code_spacer'],
  );

  return trim(t('@code_before@code_spacer@negative@symbol_before@price@symbol_spacer@symbol_after@code_spacer@code_after', $replacements));
}

Do note: if you place the hook_commerce_currency_info_alter() implementation in YOUR_MODULE.commerce.inc file, the callback will still need to be placed in the .module file, because the .commerce.inc file will not be automatically loaded everywhere.

That's it - all prices will be displayed now without the decimals.

See also: