Slots are the core processing units of Templex. Each slot handles a specific type of template directive, performing replacement and hydration to produce the final rendered output.
Templex includes four built-in slots, processed in this order:
- IncludeSlot — includes another template's content
- ControlSlot — processes control flow (if/else, foreach, for, switch)
- TernarySlot — resolves ternary and null coalescing expressions
- VariableSlot — replaces variable placeholders
You can extend Templex with custom slots that implement SlotInterface:
$templex->setSlots([
CustomSlot::class,
IncludeSlot::class,
ControlSlot::class,
VariableSlot::class,
]);Include another template by its name to create reusable partials:
<{ include partials.header }>
<{ include layouts.base }>
Dot notation maps to subdirectories, so partials.header resolves to partials/header.stub.
Variables are replaced when matching placeholders are found. They can be passed in at render time, or created by other slots such as loops.
Hello <{ $name }>, welcome to <{ $siteName }>!
$templex->render('greeting', [
'name' => 'Fred',
'siteName' => 'Templex',
]);If/else statements support variables, numbers, booleans, and literal strings with the usual comparison operators.
<{ if( $role === 'admin' ) }>
<p>Welcome, administrator.</p>
<{ endif }>
With an else branch:
<{ if( $authenticated ) }>
<p>You are logged in.</p>
<{ else }>
<p>Please log in.</p>
<{ endif }>
With elseif for chained conditions:
<{ if( $role === "admin" ) }>
<p>Administrator</p>
<{ elseif( $role === "editor" ) }>
<p>Editor</p>
<{ else }>
<p>Guest</p>
<{ endif }>
Multiple elseif branches are supported — the first matching condition wins.
==, ===, !=, !==, >, <, >=, <=, &&, ||, !
A variable on its own evaluates as truthy or falsy:
<{ if( $hasAccess ) }>
Granted
<{ endif }>
<{ if( true ) }>
Always shown
<{ endif }>
Combine conditions with && (and) and || (or):
<{ if( $isLoggedIn && $isAdmin ) }>
Admin panel
<{ endif }>
<{ if( $role === "admin" || $role === "editor" ) }>
Can edit
<{ endif }>
Negate any condition with !:
<{ if( !$banned ) }>
Welcome
<{ endif }>
Conditions can be nested and combined with other control structures. For more examples including nested conditions, logical operators, and operator usage, see the Condition Examples.
Foreach loops iterate over an array variable:
<ul>
<{ foreach( $users as $user ) }>
<li><{ $user }></li>
<{ endforeach }>
</ul>
Key-value iteration is also supported using $key => $value syntax:
<dl>
<{ foreach( $settings as $key => $value ) }>
<dt><{ $key }></dt>
<dd><{ $value }></dd>
<{ endforeach }>
</dl>
The loop variables are scoped to the loop body and have access to all parent variables. Loop metadata variables ($loop_index, $loop_first, $loop_last, $loop_count) are also available. For more examples including nested loops and key-value patterns, see the Foreach Examples.
For loops use C-style syntax with initialization, condition, and increment:
<{ for( $i = 0; $i < 5; $i++ ) }>
Item <{ $i }>
<{ endfor }>
Variables can be used for dynamic bounds:
<{ for( $i = $start; $i <= $end; $i++ ) }>
Value: <{ $i }>
<{ endfor }>
$i++/$i--$i += 2/$i -= 1
<, <=, >, >=, ==, ===, !=, !==
For more examples including nested loops, tables, and pagination patterns, see the For Loop Examples.
Why no while loop? Templex variables are immutable within a template, so a while loop condition can never change between iterations. Use
forloops with a counter orforeachloops over a collection instead.
Both foreach and for loops expose metadata variables inside the loop body:
| Variable | Description |
|---|---|
$loop_index |
Zero-based iteration index (0, 1, 2, ...) |
$loop_count |
Total number of iterations |
$loop_first |
true on the first iteration |
$loop_last |
true on the last iteration |
<{ foreach( $items as $item ) }>
<{ if( $loop_first ) }>First: <{ endif }><{ $item }>
<{ if( $loop_last ) }> (last of <{ $loop_count }>)<{ endif }>
<{ endforeach }>
These work identically in for loops:
<{ for( $i = 0; $i < 5; $i++ ) }>
<{ $loop_index }>: <{ $i }><{ if( $loop_last ) }> [done]<{ endif }>
<{ endfor }>
Switch statements match a variable against multiple cases:
<{ switch( $status ) }>
<{ case( "active" ) }>
Account is active
<{ case( "suspended" ) }>
Account is suspended
<{ default }>
Unknown status
<{ endswitch }>
Cases support strings, numbers, booleans, and variables. Matching uses strict comparison (===). There is no fallthrough — each case is independent.
<{ switch( $level ) }>
<{ case( 1 ) }>
Beginner
<{ case( $maxLevel ) }>
Expert
<{ default }>
Intermediate
<{ endswitch }>
For more examples including nested switches and variable cases, see the Switch Statement Examples.
Inline expressions for simple conditional output without full if/else blocks.
Output different values based on a variable's truthiness:
<{ $active ? "Enabled" : "Disabled" }>
<{ $count ? "Has items" : "Empty" }>
Truthy: true, 1, non-empty strings (except "false" and "0").
Falsy: false, 0, "", "false", "0", or missing variables.
Provide a default value when a variable doesn't exist:
<{ $title ?? "Untitled" }>
<{ $theme ?? "light" }>
If the variable exists, its value is used. If it doesn't exist, the default is used.
Both ternary and null coalescing support string literals, numbers, and variable references:
<{ $name ?? $defaultName }>
<{ $role ? $adminLabel : $guestLabel }>
<{ $port ?? 8080 }>
Ternary and null coalescing work inside loops and other control structures.