{ifchanged}
Renders its content when a value differs from the previous row of the loop around it - a heading per group.
Syntax
{ifchanged value} ... {/ifchanged}
{ifchanged value, value} ... {/ifchanged}
{ifchanged value} ... @else@ ... {/ifchanged}
Parameters
-
value - One or more values, usually fields of the current row. The content renders when any of them differs from what it was on the previous row.
Description
{ifchanged $customer} compares its value with the value it had the previous time it ran in the same loop. The content renders when the value is different - and always on the first row - so in a list sorted on that field it renders once at the start of every group: the classic group heading. When the value is the same as before, the @else@ part renders instead, if the tag has one.
With several values - {ifchanged $year, $month} - the content renders when any of them changed. Sort the rows first (the sort option, or in the query): the tag only looks one row back, so an unsorted list gets a heading every time the value flips.
The memory belongs to one run of the enclosing loop - the nearest level that is not an {if}, a {case} or another {ifchanged} - so the tag may stand inside an {if} in the loop, and a loop that runs again (an inner loop on the next outer row) starts afresh. Several {ifchanged} tags in one row are kept apart by position: the second one of a row is compared with the second one of the row before.
Under the strict syntax check an {ifchanged} without a value, or without its closing tag, is an error. The {case} and {if} tags compare with fixed values; {ifchanged} compares with the row before.
Examples
A heading per group
Sorted on the city, the heading renders once at the start of each city.
{offices sort='city'}
{ifchanged $city}<h4>{$city}</h4>{/ifchanged}
<p>{$person}</p>
{/offices}
<?php
$offices = [
[ 'city' => 'Utrecht', 'person' => 'Anna' ],
[ 'city' => 'Lisbon', 'person' => 'Bruno' ],
[ 'city' => 'Utrecht', 'person' => 'Carla' ],
[ 'city' => 'Lisbon', 'person' => 'Dinis' ],
[ 'city' => 'Oslo', 'person' => 'Eirik' ] ];
?>
Lisbon
Bruno
Dinis
Oslo
Eirik
Utrecht
Anna
Carla
Several values and @else@
A change in either value renders the heading; an unchanged row renders the @else@ part.
{data 'ifchangedPosts'}
year,month,post
2026,September,Launch
2026,September,First fix
2026,October,Autumn release
2027,October,Next year
{/data}
<ul>
{ifchangedPosts}
<li>{ifchanged $year, $month}<strong>{$month} {$year}</strong>@else@— same month{/ifchanged}: {$post}</li>
{/ifchangedPosts}
</ul>
- September 2026: Launch
- โ same month: First fix
- October 2026: Autumn release
- October 2027: Next year