| 1 |
<?php |
| 2 |
|
| 3 |
namespace Better_Payment\Lite\Campaign\Support; |
| 4 |
|
| 5 |
if ( ! defined( 'ABSPATH' ) ) { |
| 6 |
exit; |
| 7 |
} |
| 8 |
|
| 9 |
/** |
| 10 |
* Amount formatting for everything a campaign puts on screen. |
| 11 |
* |
| 12 |
* One rule, applied everywhere: **decimals appear only when there is a fraction |
| 13 |
* to show.** A goal of 10000 reads "10,000", a raised total of 3750 reads |
| 14 |
* "3,750", and 3750.50 still reads "3,750.50". A column of ".00" says nothing |
| 15 |
* except that the site is running software that cannot tell the difference. |
| 16 |
* |
| 17 |
* It lives here rather than at each call site because there were six of them |
| 18 |
* across two plugins — the progress goal, the summary total, the minimum-donation |
| 19 |
* notice, the amount chips, the campaign-list column and Pro's donors wall — and |
| 20 |
* they already disagreed: some used `number_format`, Pro used `number_format_i18n`, |
| 21 |
* and the amount chips used bare float interpolation, which printed "€10.5" for |
| 22 |
* ten pounds fifty and "€1000" with no separator at all. |
| 23 |
*/ |
| 24 |
class Money { |
| 25 |
|
| 26 |
/** |
| 27 |
* Format an amount for display, dropping decimals that are all zero. |
| 28 |
* |
| 29 |
* @param mixed $amount Numeric amount. |
| 30 |
* @param int $decimals Decimals to show when a fraction is present. |
| 31 |
* @return string |
| 32 |
*/ |
| 33 |
public static function format( $amount, int $decimals = 2 ): string { |
| 34 |
$amount = (float) $amount; |
| 35 |
|
| 36 |
if ( $decimals < 0 ) { |
| 37 |
$decimals = 0; |
| 38 |
} |
| 39 |
|
| 40 |
// Decide on the ROUNDED value, not the raw one: 3750.004 displays as |
| 41 |
// "3,750.00" at two decimals, which is exactly the string this exists to |
| 42 |
// avoid, so it must count as having no fraction. |
| 43 |
$rounded = round( $amount, $decimals ); |
| 44 |
|
| 45 |
if ( abs( $rounded - floor( $rounded ) ) < 0.0000001 ) { |
| 46 |
$decimals = 0; |
| 47 |
} |
| 48 |
|
| 49 |
// number_format_i18n applies the site's separators; the plain fallback |
| 50 |
// keeps this callable from a unit test with no WordPress loaded. |
| 51 |
return function_exists( 'number_format_i18n' ) |
| 52 |
? number_format_i18n( $amount, $decimals ) |
| 53 |
: number_format( $amount, $decimals ); |
| 54 |
} |
| 55 |
|
| 56 |
/** |
| 57 |
* Format an amount with its currency symbol in front. |
| 58 |
* |
| 59 |
* @param string $symbol Currency symbol, already resolved. |
| 60 |
* @param mixed $amount Numeric amount. |
| 61 |
* @param int $decimals Decimals to show when a fraction is present. |
| 62 |
* @return string |
| 63 |
*/ |
| 64 |
public static function with_symbol( string $symbol, $amount, int $decimals = 2 ): string { |
| 65 |
return $symbol . self::format( $amount, $decimals ); |
| 66 |
} |
| 67 |
} |
| 68 |
|