I'm working on a site with many free products, and we want to display the price as "Free" instead of $0.00.

I was hoping to get away with something like this, but this causes loops, and makes everything free, because commerce_currency_format() calls the callback.

/**
 * Implements hook_commerce_currency_info_alter().
 */
function mymodule_commerce_commerce_currency_info_alter(&$currencies, $langcode) {
  $currencies['CAD']['format_callback'] = 'mymodule_commerce_currency_format';
}

function mymodule_commerce_currency_format($amount, $currency, $object = NULL) {
  $rounded_amount = commerce_currency_amount_to_decimal($amount, $currency['code']);
  $rounded_amount = commerce_currency_round(abs($amount), $currency);
  if ($rounded_amount == 0) {
    return t('Free');
  }
  else {
    return commerce_currency_format($amount, $currency['code'], $object);
  }
}

I ended up with the following. mymodule_commerce_currency_format_standard() is a copy and paste of commerce_currency_format() with the callback deleted.

/**
 * Implements hook_commerce_currency_info_alter().
 */
function mymodule_commerce_commerce_currency_info_alter(&$currencies, $langcode) {
  $currencies['CAD']['format_callback'] = 'mymodule_commerce_currency_format';
}

function mymodule_commerce_currency_format($amount, $currency, $object = NULL) {
  $rounded_amount = commerce_currency_amount_to_decimal($amount, $currency['code']);
  $rounded_amount = commerce_currency_round(abs($amount), $currency);
  if ($rounded_amount == 0) {
    return t('Free');
  }
  else {
    return mymodule_commerce_currency_format_standard($amount, $currency['code'], $object, FALSE);
  }
}

function mymodule_commerce_currency_format_standard($amount, $currency_code, $object = NULL, $convert = TRUE) {
  // First load the currency array.
  $currency = commerce_currency_load($currency_code);

  // Then convert the price amount to the currency's major unit decimal value.
  if ($convert == TRUE) {
    $amount = commerce_currency_amount_to_decimal($amount, $currency_code);
  }

  // Format the price as a number.
  $price = number_format(commerce_currency_round(abs($amount), $currency), $currency['decimals'], $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));
}

I'm not yet familiar enough with the internals to make any suggestions. I'm just hoping there's an easier way to do this, or maybe this is more of a support request.

Comments

rszrama’s picture

Status: Active » Fixed

Yeah, I'm not a huge fan of the system as is, but you're using it as expected. Basically, it's assuming you're going to do everything, so you have to copy / paste if you want to pass through to the core formatting method. Would've been better if we had another function to serve as the default format callback, but instead the callback is functioning more like an override now. This should get fixed in 2.x, but we can't change the API too radically in 1.x.

The alternative would be to change it afterwards through an alter hook or to develop your own field display formatter. That's probably the route I would take - create a new field formatter that shows Free if it's $0.00 or calls commerce_currency_format() if not.

star-szr’s picture

Thanks for the reply Ryan! I'll take a look at the field display formatter option at some point.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

sano’s picture

There is a module for creating formatters and it works in the use case described here.