This document provides a complete reference for all PAD data handling functions.
Data handling functions transform data arrays before they are rendered in templates. They are applied as options on PAD tags:
{tagName sort="field", first="5", reverse}
Multiple handlers can be combined and are applied in sequence.
Sorts data by one or more fields with configurable direction and sort type.
{items sort}
{items sort="fieldName"}
{items sort="fieldName ASC"}
{items sort="fieldName DESC"}
{items sort="field1 ASC; field2 DESC"}
Parameters:
TRUE or empty - Sort by all fieldsfieldName - Sort by single field (ascending)fieldName ASC - Sort ascendingfieldName DESC - Sort descending;Sort Type Flags:
NUMERIC - Compare as numbersSTRING - Compare as stringsNATURAL - Natural order sortingLOCALE_STRING - Locale-aware string comparisonREGULAR - Standard comparisonExamples:
{users sort="name"}
{users sort="age DESC"}
{users sort="department ASC; name ASC"}
{products sort="price NUMERIC DESC"}
{files sort="name NATURAL ASC"}
Implementation: Uses array_multisort() for efficient multi-column sorting.
Reverses the order of data array.
{items reverse}
Parameters: None (boolean flag)
Example:
{users sort="date", reverse}
{-- Sort by date then reverse for newest first --}
Implementation: Uses array_reverse().
Randomly shuffles all elements.
{items shuffle}
Parameters: None (boolean flag)
Example:
{quotes shuffle, first="1"}
{-- Get one random quote --}
Implementation: Uses PHP shuffle().
Selects random elements with advanced options.
{items random}
{items random="5"}
{items random="3", orderly, duplicates}
Parameters:
random - Number of random items to select (default: all)orderly - Keep original order of selected itemsduplicates - Allow duplicate selectionsatLeastOnce, the third companion in handling/types/, is read by the sequence randomize
action only; on a data tag it has no effect.
Examples:
{products random="4"}
{-- Select 4 random products --}
{users random="3", orderly}
{-- Select 3 random users, maintain their original order --}
{colors random="10", duplicates}
{-- Select 10 colors, allowing repeats --}
Implementation: Uses pqRandom() function.
Keeps the rows for which an expression holds - on any data, not only on Select tables.
{staff where='$salary gt 2500'}
{orders where='$status eq "open" and $total gt $minimum'}
Parameters:
where=$cond is refused, a value goes in as
$name (where='$total gt $minimum'), and a field spliced into the quotes -
where='$status eq {$s}' - is compared as a string, never run as part of the expression.Examples:
{staff where='$salary gt 1500', first=2}
{-- The first two of the rows that pass --}
{staff where='$salary gt 2500', negative}
{-- Every row that does not pass --}
A Select table ({select:users}, or a declared table by its name) has a where of its own -
SQL, applied by the query - and is left alone by this handler.
Gets the first N elements.
{items first}
{items first="5"}
Parameters:
TRUE or 1 - Get first elementExamples:
{news first="3"}
{-- Show first 3 news items --}
{users sort="score DESC", first="10"}
{-- Top 10 users by score --}
Implementation: Uses array_slice($data, 0, $count).
Gets the last N elements.
{items last}
{items last="5"}
Parameters:
TRUE or 1 - Get last elementExamples:
{logs last="20"}
{-- Show last 20 log entries --}
{orders sort="date", last="5"}
{-- Last 5 orders --}
Implementation: Uses array_slice($data, -$count).
Gets a specific row by number.
{items row="3"}
Parameters:
Example:
{users row="1"}
{-- Get first user --}
Implementation: Uses padHandGo() with start=end.
Paginates data into pages.
{items page="1", rows="10"}
{items page="2", rows="25"}
Parameters:
page - Page number (1-based, default: 1; a page below 1, or one that is no number, is page 1)rows - Items per page (default: 10)Calculation:
Examples:
{users page="1", rows="20"}
{-- First 20 users --}
{products page="3", rows="12"}
{-- Products 25-36 (page 3 with 12 per page) --}
Page links: a tag written with page books its page, rows and total - the rows the
options written before page left - under its name, and {pager 'products'} after it
writes the links to the other pages (see TAGS.md). Write the page as a
request variable, page=$pg ?? 1, and the links set pg.
Gets a specific number of rows (shorthand for pagination).
{items rows="10"}
Parameters:
Behavior:
page is not set, triggers pagination with default page 1start is set, limits rows from that positionend is set, calculates start based on end - rowsExample:
{users rows="5"}
{-- First 5 users --}
{logs end="-1", rows="10"}
{-- The 10 log entries before the last one --}
Sets the starting position for data selection.
{items start="5"}
{items start="-3"}
Parameters:
Examples:
{users start="11", rows="10"}
{-- Users 11-20 --}
{items start="-5"}
{-- Last 5 items --}
Sets the ending position for data selection.
{items end="10"}
{items end="-1"}
Parameters:
Examples:
{users start="1", end="10"}
{-- Users 1-10 --}
{items end="-1"}
{-- All items except the last one --}
Extracts a portion of the array (keeps selected elements).
{items slice="5"}
{items slice="3|7"}
Parameters:
offset|count - Offset counted from 0, and number of elementsExamples:
{items slice="10"}
{-- Keep first 10 items --}
{items slice="-5"}
{-- Keep last 5 items --}
{items slice="5|3"}
{-- Keep 3 items starting at offset 5, the sixth --}
Implementation: Uses array_slice().
Removes a portion of the array (removes selected elements).
{items splice="5"}
{items splice="3|2"}
Parameters:
start|count - Start position and number to removeExamples:
{items splice="2"}
{-- Remove first 2 items --}
{items splice="-3"}
{-- Remove last 3 items --}
{items splice="5|2"}
{-- Remove 2 items starting at offset 5, the sixth --}
Implementation: Uses array_splice().
Removes duplicate entries from single-field arrays.
{items dedup}
Parameters: None (boolean flag)
Behavior:
Example:
{tags dedup}
{-- Remove duplicate tags --}
Trims elements from the beginning and/or end of the array.
{items trim}
{items trim="2"}
{items trim="3", left}
{items trim="3", right}
{items trim="2", both}
Parameters:
both - Trim from both ends (default if no direction specified)left - Trim from beginning onlyright - Trim from end onlyExamples:
{items trim="1"}
{-- Remove first and last item --}
{items trim="2", left}
{-- Remove first 2 items --}
{items trim="3", right}
{-- Remove last 3 items --}
Implementation: Uses pqTruncate() function.
Folds the rows into one occurrence per distinct value of a field, with a count, aggregated fields and the group’s own rows as nested data.
{orders group='customer', sum='total'}
<h2>{$customer}: {$count} orders, {$total}</h2>
{rows}
<p>{$number}: {$total}</p>
{/rows}
{/orders}
Each group occurrence holds:
count - the number of rows in the grouprows - the group’s rows; {rows} iterates them, and inside it a field is the row’s own
value againParameters:
group='year, month' - group on the
combination.Aggregates - options read by group, each naming one or more fields:
| Option | Gives |
|---|---|
sum |
The numeric values added - other values are left out; rounded to the most decimals among them, so 10.10 + 20.20 is 30.3 |
avg |
That sum divided by the number of numeric values, '' when there were none |
min |
The lowest value - numbers compared as numbers, other text as text; missing and empty values left out |
max |
The highest value, the same way |
The aggregate is stored under the field’s own name - {$total} - and under the aggregate
joined to it - {$sum_total}, {$avg_total}, {$min_total}, {$max_total} - so one field
can be summed and averaged at once; the own name holds the aggregate written first. A field
named count or rows keeps only the joined name - {$sum_rows} - as those two names are the
group’s own; grouping on such a field is an error under the strict check.
Examples:
{orders sort='customer', group='customer'}
{-- Groups in customer order, the rows inside them too --}
{orders group='customer', sum='total', sort='total DESC', first=3}
{-- The three customers with the highest total --}
{orders group='customer', where='$count gt 1'}
{-- The customers with more than one order --}
{orders group='year'}{$year}{rows group='month', sum='total'}{$month}: {$total}{/rows}{/orders}
{-- Grouped again inside a group --}
Groups come in the order their first row appears; negative leaves a group alone. A Select
table ({select:users}, or a declared table by its name) has a group of its own - SQL’s
group by, applied by the query - and is left alone by this handler.
When the tag found rows and the handling options left none - a where nothing passes, a
first=0 - the level is treated as a tag that came back empty: a notOk=, error= or
else= option stands in with its content, otherwise the level shows its @else@ branch, and
demand is an error unless an option stood in:
{staff where='$salary gt 9999'}{$name}@else@Nobody earns that much{/staff}
{staff where='$salary gt 9999', else='nobody'}{$name}{/staff}
The negative option inverts the selection - keeping items that would normally be removed.
An option that selects nothing - sort, reverse, shuffle, group - is left alone by it,
so {staff where='$salary gt 2500', sort='name', negative} is every row that does not pass,
sorted.
{items first="3", negative}
{-- Gets all items EXCEPT the first 3 --}
How it works:
The handlers that select nothing are left alone: sort, reverse and shuffle only put the
rows in another order, group folds them, and rows beside page, start or end (and
end beside start) is read by that partner - {staff where='$salary gt 2500', sort='name',
negative} is every row that does not pass, sorted by name.
Examples:
{users first="5", negative}
{-- All users except first 5 --}
{items random="3", negative}
{-- All items except 3 random ones --}
| Function | Purpose | Parameters |
|---|---|---|
sort |
Sort by field(s) | field [ASC|DESC] [; …] |
reverse |
Reverse order | (none) |
shuffle |
Random order | (none) |
random |
Random selection | count, orderly, duplicates |
where |
Rows an expression holds for | quoted expression |
group |
One occurrence per value, with count and rows | field(s); sum, avg, min, max |
first |
First N items | count |
last |
Last N items | count |
row |
Specific row | row number |
page |
Pagination | page, rows |
rows |
Row count | count |
start |
Start position | position |
end |
End position | position |
slice |
Keep portion | start|count |
splice |
Remove portion | start|count |
dedup |
Remove duplicates | (none) |
trim |
Trim ends | count, left, right, both |
Functions can be combined and are applied in sequence:
{users sort="name", first="10"}
{-- Sort by name, then get first 10 --}
{products sort="price DESC", page="1", rows="20"}
{-- Sort by price descending, paginate --}
{items shuffle, first="5"}
{-- Shuffle then get first 5 (5 random items) --}
{tags sort, dedup, first="100"}
{-- Sort, drop repeated tags, limit to 100 --}
Handlers are processed in the order they appear in the tag parameters. Consider the order carefully:
{-- Different results: --}
{items first="10", shuffle} {-- First 10, then shuffled --}
{items shuffle, first="10"} {-- Shuffled, then first 10 --}
Recommended order:
dedup - Remove duplicates firstsort - Sort the clean datashuffle / random - Randomize if neededfirst / last / page - Limit results last