Reference - PAD functions - currency


App: htmx - Page: examples/cart
PHP
examples/cart.php
HTML
examples/cart.pad
Result
<?php

// The cart is the session's: product id => quantity. A button posts its product - op=add
// or op=remove - and the answer is the {fragment 'item'} of that product: the card with its
// new count, then the parts elsewhere on the page that changed too, each marked
// hx-swap-oob - htmx puts the card back where the button was and the rest where their ids
// are: the count in the header, the summary beside the shelf. Emptying the cart is an
// ordinary {form} post that ends in a redirect, the page coming back whole.

$counts = padSession ( 'htmxCart', [] );
$products = array_slice ( htmxData ( 'products' ), 0, 8 );
$posted = padRequestIs ( 'POST' );

if (
$posted ) {

$id = (int) padRequest ( 'id', 0 );
$op = htmxText ( 'op' );
$stock = array_column ( $products, 'stock', 'id' );

if (
$op == 'clear' ) {
padSessionPut ( 'htmxCart', [] );
padRedirect ();
}

if (
$op == 'add' and ( $stock [$id] ?? 0 ) > ( $counts [$id] ?? 0 ) )
$counts [$id] = ( $counts [$id] ?? 0 ) + 1;
elseif (
$op == 'remove' and isset ( $counts [$id] ) and --$counts [$id] <= 0 )
unset (
$counts [$id] );

padSessionPut ( 'htmxCart', $counts );

$products = array_values ( array_filter ( $products, fn ( $product ) => $product ['id'] == $id ) );

// A product the shelf does not have - a stale or made-up request - has no card to
// answer: a 404, which htmx swaps nothing for, where the empty loop rendered no
// {fragment 'item'} and the answer was a 500, "there is no fragment named 'item'".

if ( ! $products )
padAbort ( 404, 'There is no such product' );

}

foreach (
$products as $at => $product )
$products [$at] ['inCart'] = $counts [ $product ['id'] ] ?? 0;

$cart = htmxCart ( $counts );
$cartCount = $cart ['count'];
$lines = $cart ['lines'];
$total = $cart ['total'];

?>
<div class="shop">
<div id="shelf" class="grid shelf">
{products}
{fragment 'item'}
<div class="card item" id="item-{$id}">
<div class="item-top"><span class="item-emoji">{$emoji}</span>{if $inCart}<span class="badge is-accent">{$inCart} in cart</span>{/if}</div>
<strong>{$name}</strong>
<div class="muted small">{$price | currency('EUR')} &middot; {if $stock}{$stock} in stock{else}sold out{/if}</div>
<div class="item-buttons">
<button class="btn-sm" hx-post="?examples/cart&id={$id}&op=add&padFragment=item" hx-target="#item-{$id}" hx-swap="outerHTML">+ Add</button>
{if $inCart}<button class="btn-sm btn-ghost" hx-post="?examples/cart&id={$id}&op=remove&padFragment=item" hx-target="#item-{$id}" hx-swap="outerHTML">โˆ’</button>{/if}
</div>
</div>
{if $posted}
<span id="cart-count" hx-swap-oob="true">{$cartCount}</span>
{cartSummary}
{/if}
{/fragment}
{/products}
</div>
{cartSummary}
</div>


App: htmx - Page: examples/scroll
PHP
examples/scroll.php
HTML
examples/scroll.pad
Result
<?php

// Ninety orders, fifteen at a time. The page shows the first fifteen; the last row of every
// batch carries hx-get for the next batch, sent when the row scrolls into view. That row
// has no id, so the request names its fragment itself: &padFragment=rows - the answer is
// the next rows, the last of them asking for the batch after it, and hx-swap="afterend"
// puts them below the row that asked.

$page = max ( 1, (int) padRequest ( 'p', 1 ) );
$per = 15;
$total = 90;
$pages = (int) ceil ( $total / $per );
$page = min ( $page, $pages );

$people = [ 'Ada', 'Bram', 'Chen', 'Dalia', 'Emeka', 'Freya', 'Goran', 'Hana' ];
$states = [ 'paid', 'shipped', 'open', 'paid', 'returned' ];

$orders = [];

for (
$n = ( $page - 1 ) * $per + 1; $n <= min ( $total, $page * $per ); $n++ )
$orders [] = [ 'number' => 1000 + $n,
'customer' => $people [ ( $n * 3 ) % count ( $people ) ],
'amount' => 20 + ( $n * 37 ) % 480,
'status' => $states [ $n % count ( $states ) ],
'next' => ( $n == $page * $per and $page < $pages ) ? $page + 1 : 0 ];

?>
<table class="table">
<thead><tr><th>Order</th><th>Customer</th><th>Status</th><th class="num">Amount</th></tr></thead>
<tbody>
{fragment 'rows'}
{orders}
<tr{if $next} hx-get="?examples/scroll&p={$next}&padFragment=rows" hx-trigger="revealed" hx-swap="afterend"{/if}>
<td>#{$number}</td>
<td>{$customer}</td>
<td><span class="badge status-{$status}">{$status}</span></td>
<td class="num">{$amount | currency('EUR')}</td>
</tr>
{/orders}
{/fragment}
</tbody>
</table>
<p class="muted small">Scroll down - every fifteenth row asks for the next fifteen. Ninety in all.</p>


App: htmx - Page: examples/search
PHP
examples/search.php
HTML
examples/search.pad
Result
<?php

// The products whose name, category or text holds the query. The same PHP serves the page
// and every answer to htmx: the input's hx-target="#results" sends HX-Target: results,
// and PAD answers the {fragment 'results'} of search.pad alone. The query stands in the
// address (hx-push-url), so a reload - or a link - shows the same results whole.

$q = trim ( htmxText ( 'q' ) );

$found = array_values ( array_filter ( htmxData ( 'products' ), fn ( $product ) =>
$q === '' or stripos ( $product ['name'] . ' ' . $product ['category'] . ' ' . $product ['blurb'], $q ) !== FALSE ) );

$count = count ( $found );

?>
<div class="toolbar">
<div class="search">
<input class="input" type="search" name="q" value="{$q}" placeholder="Search - try lamp, audio or usb" autocomplete="off"
aria-label="Search the products" hx-get="?examples/search" hx-trigger="input changed delay:250ms, search"
hx-target="#results" hx-push-url="true" hx-indicator="#searching">
</div>
<span id="searching" class="htmx-indicator spinner" aria-hidden="true"></span>
</div>

<div id="results">
{fragment 'results'}
<p class="muted small">{$count} {if $count eq 1}product{else}products{/if}{if $q} for <mark>{$q}</mark>{/if}</p>
<table class="table">
<thead><tr><th>Product</th><th>Category</th><th class="num">Price</th></tr></thead>
<tbody>
{found}
<tr><td>{$emoji} {$name}</td><td><span class="badge">{$category}</span></td><td class="num">{$price | currency('EUR')}</td></tr>
{/found}
</tbody>
</table>
{if $count eq 0}<div class="empty-state"><span class="big">๐Ÿ”Ž</span>Nothing in the catalogue matches.</div>{/if}
{/fragment}
</div>


App: manual - Page: fragments/locale_1
PHP
fragments/locale_1.php
HTML
fragments/locale_1.pad
Result
<?php

// The page picks Dutch; an application listing $padLocales lets the visitor's
// Accept-Language or ?lang= choose instead.

$padLocale = 'nl';

$count = 3;
$user = 'Ann';
$total = 1234.5;
$when = '2026-10-05';

?>
<h4>{trans 'cart.title'}</h4>
<p>{trans 'cart.items', count=$count} - {trans 'cart.owner', name=$user}</p>
<p>{$total | currency('EUR', 'nl_NL')} - {$when | localDate('d MMMM y')}</p>


App: regression/errors - Page: syntax/a_currency_locale_intl_does_not_know
PHP
HTML
syntax/a_currency_locale_intl_does_not_know.pad
Result
{echo 5 | currency('EUR', 'xx_YY')}


App: regression/framework - Page: functions/currency_of_an_empty_value_is_empty
PHP
HTML
functions/currency_of_an_empty_value_is_empty.pad
Result
{data 'rows'}[{"price":null},{"price":12.5}]{/data}{rows}[{$price | currency('EUR', 'en')}]{/rows}[{echo '' | currency}]


App: regression/framework - Page: functions/currency_writes_an_amount_the_locale_s_way
PHP
HTML
functions/currency_writes_an_amount_the_locale_s_way.pad
Result
[{echo 1234.5 | currency('USD', 'en_US')}][{echo 99 | currency('EUR', 'en')}]


App: regression/framework - Page: lenient/a_locale_intl_does_not_know_falls_back_to_the_plain_form
PHP
lenient/a_locale_intl_does_not_know_falls_back_to_the_plain_form.php
HTML
lenient/a_locale_intl_does_not_know_falls_back_to_the_plain_form.pad
Result
<?php

// The lenient walk under test: with the syntax check off, what cannot run passes the
// value through or yields empty, and the walk carries on.

$padCheckSyntax = FALSE;

?>
[{echo 1234.5 | currency('EUR', 'xx_YY')}][{echo '2026-10-05' | localDate('long', 'none', 'zz')}]


App: regression/framework - Page: tags/datatable_sums_the_totals_columns_and_aligns_the_numbers
PHP
HTML
tags/datatable_sums_the_totals_columns_and_aligns_the_numbers.pad
Result
{datatable totals='qty, amount', labels='Item, Qty, Amount, Code', format="amount:currency('EUR')", caption='Lines <b>', striped}
item,qty,amount,zip_code
Chair <b>,2,10.5,1234
Table,1,120,98765
Lamp,10,3.25,5000
{/datatable}


App: showcase - Page: datatable/expenses
PHP
HTML
datatable/expenses.pad
Result
{meta title='A table from inline CSV', about='As a pair the content is the data - CSV, JSON, YAML or XML - here a budget with a pipe formatting the amounts and a totals row.'}
{datatable totals='budget, spent', format="budget:currency('EUR'), spent:currency('EUR')", caption='Marketing budget, third quarter'}
channel,budget,spent
Search ads,12000,11380.40
Social media,8500,9120.15
Newsletter,1500,960
Trade fair,15000,14215.80
Print,3000,2410.25
{/datatable}


App: showcase - Page: pdf/invoice
PHP
pdf/invoice.php
HTML
pdf/invoice.pad
Result
<?php

$invoice
= '2026-114';
$issued = '8 October 2026';
$due = '7 November 2026';
$customer = [ 'name' => 'Noordkaap Sailing School', 'street' => 'Havenkade 12', 'city' => '1781 AB Den Helder' ];

$lines = [
[
'item' => 'Mooring rope, 12 mm, per 20 m', 'qty' => 4, 'price' => 38.50 ],
[
'item' => 'Fender, inflatable, large', 'qty' => 6, 'price' => 27.95 ],
[
'item' => 'Life jacket 150 N, adult', 'qty' => 10, 'price' => 64.00 ],
[
'item' => 'Shackle, stainless, 8 mm', 'qty' => 24, 'price' => 3.20 ],
[
'item' => 'Delivery to the harbour', 'qty' => 1, 'price' => 45.00 ] ];

$subtotal = 0;

foreach (
$lines as $key => $line ) {
$lines [$key] ['amount'] = $line ['qty'] * $line ['price'];
$subtotal += $lines [$key] ['amount'];
}

$vat = round ( $subtotal * 0.21, 2 );
$total = $subtotal + $vat;

?>
{meta title='An invoice as PDF', about='An order rendered on a sheet, the same template one click away as an A4 PDF made in plain PHP.'}
{pdf preview, file='invoice-{$invoice}', title='Invoice {$invoice}'}
<img src="photos/logo.jpg" width="56" height="56" alt="Harbour Supplies">
<h1>Invoice {$invoice}</h1>
<p><b>Harbour Supplies</b><br>Kaai 3, 1781 AA Den Helder<br>info@harbour.example</p>
<p>To: <b>{$customer.name}</b><br>{$customer.street}<br>{$customer.city}</p>
<p>Issued {$issued} - due {$due}</p>
<table>
<tr><th>Item</th><th align="right">Qty</th><th align="right">Price</th><th align="right">Amount</th></tr>
{lines}
<tr><td>{$item}</td><td align="right">{$qty}</td><td align="right">{$price | currency('EUR', 'nl_NL')}</td><td align="right">{$amount | currency('EUR', 'nl_NL')}</td></tr>
{/lines}
<tr><td colspan="3" align="right">Subtotal</td><td align="right">{$subtotal | currency('EUR', 'nl_NL')}</td></tr>
<tr><td colspan="3" align="right">VAT 21%</td><td align="right">{$vat | currency('EUR', 'nl_NL')}</td></tr>
<tr><td colspan="3" align="right"><b>Total</b></td><td align="right"><b>{$total | currency('EUR', 'nl_NL')}</b></td></tr>
</table>
<p>Please pay within 30 days to <b>NL91 ABNA 0417 1643 00</b>, quoting invoice {$invoice}.</p>
{/pdf}


App: tags - Page: examples/datatable/2-csv
PHP
HTML
examples/datatable/2-csv.pad
Result
{meta title='Rows as content', about='As a pair the content is the data - here CSV - with a currency pipe and a totals row.'}
{datatable totals='budget, spent', format="budget:currency('EUR'), spent:currency('EUR')", caption='Marketing budget'}
channel,budget,spent
Search ads,12000,11380.40
Social media,8500,9120.15
Newsletter,1500,960
{/datatable}