This document provides a complete reference for all PAD constructs - special @something@ markers used in PAD templates.
PAD constructs are special placeholder markers that control template structure and content flow. They use the @name@ syntax and are processed during template building and rendering.
@page@
@content@
@start@
@end@
@else@
@tidy@
The main content placeholder that marks where page content should be inserted.
Purpose: Central insertion point for page content in the template hierarchy.
Usage:
<!DOCTYPE html>
<html>
<head><title>My App</title></head>
<body>
@page@
</body>
</html>
Behavior:
_inits.pad and _exits.pad files to wrap page content@page@ is replaced with the actual page content@page@Build Process (see build/base.php and build/build.php):
@page@ as the base_inits.pad and _exits.pad wrap around it@page@Example with Init/Exit:
<!-- _inits.pad -->
<html><body>
@page@
<!-- _exits.pad -->
</body></html>
<!-- Result: <html><body> [page content] </body></html> -->
Content merge placeholder for inserting content into parent templates.
Purpose: Marks where child content should be merged into parent content.
Usage:
<!-- _tags/article.pad - used as {article}<p>child</p>{/article} -->
<article>
<header>Article Header</header>
@content@
<footer>Article Footer</footer>
</article>
Behavior:
lib/content.php): a custom tag’s template, the
content= option, a {slot} frame - written in a page with nothing merging into it, the
strict check stops it (“an @content@ stands where nothing merges content into it”)@content@ becomes the prefix@content@ becomes the suffix@content@ position - at every one the template has at
its own level, <a>@content@</a><b>@content@</b> showing it twiceMerge Options (merge=, when neither side holds an @content@):
merge="top" - the merged content above the tag’s own (the default)merge="bottom" - below itmerge="replace" - instead of itStart marker: what stands before it is a prelude, rendered once before the rows.
Purpose: Splits a tag’s content into a prelude, the body that renders per row, and - with
@end@ - a coda.
Usage:
{myTag}
<header>once, before the rows</header>
@start@
<li>per row</li>
@end@
<footer>once, after the rows</footer>
{/myTag}
Behavior:
padOpenCloseOk() (see level/start.php, level/start_end/)@start@ renders once, before the first row@start@ and @end@ renders for each row@start@ and @end@ go together: the strict check refuses one without the other (“an
@start@ needs its @end@ behind it”) or the two in the wrong orderUse Cases:
End marker: what stands after it is a coda, rendered once after all rows.
Purpose: Closes the per-row body that @start@ opened.
Usage: see @start@ above - the two are written together.
Behavior:
padOpenCloseOk() (see level/start.php, level/start_end/)@end@ renders once, after the last row: count@ gives the number of
rows there, while the position properties no longer stand on a row - current@ reads one
past the last@start@ the strict check refuses it (“an @end@ needs its @start@ before it”)Use Cases:
True/false branch separator inside a tag’s content.
Purpose: Splits a tag’s content into a “truthy” part and a fallback part - a compact alternative to the {else} tag.
Usage:
{if $hasEntries}
{entries}
<div>{$name}: {$comment}</div>
{/entries}
@else@
<p>No entries yet. Be the first to sign!</p>
{/if}
Behavior:
level/split.php (and at build time in build/split.php)@else@ at the current tag’s own nesting level splits the content (markers inside nested open/close tag pairs are ignored)@else@ renders when the tag’s condition/data is truthy@else@ renders when it is falsy or emptyTidy marker that triggers HTML output formatting.
Purpose: Signals that HTML tidying should be applied to the output.
Usage:
@tidy@
<html>
<head><title>Page</title></head>
<body>
<div><p>Content</p></div>
</body>
</html>
Behavior:
@tidy@ in output triggers HTML tidyingexits/tidy.php: strpos($padOutput, '@tidy@')$padTidy variableTidying Effects:
| Construct | Purpose | Replaced With |
|---|---|---|
@page@ |
Main content placeholder | Page content |
@content@ |
Content merge point | Child content |
@start@ |
End of the prelude, start of the per-row body | Split marker |
@end@ |
End of the per-row body, start of the coda | Split marker |
@else@ |
True/false branch separator | Split marker |
@tidy@ |
HTML formatting trigger | Removed (triggers tidy) |
Constructs are registered by files in PAD/constructs/:
| File | Construct |
|---|---|
page.php |
@page@ |
content.php |
@content@ |
start.php |
@start@ |
end.php |
@end@ |
else.php |
@else@ |
tidy.php |
@tidy@ |
The files are a registry, never included: under the strict check, when the page is built
(build/build.php), an @word@ of the template without its file here is an error -
“there is no @foo@ construct”. Text inside {ignore} is not read.
_inits.pad:
<!DOCTYPE html>
<html>
<head>
<title>{$pageTitle}</title>
<link rel="stylesheet" href="/css/style.css">
</head>
<body>
<nav>{include:navigation}</nav>
<main>
@page@
_exits.pad:
</main>
<footer>{include:footer}</footer>
</body>
</html>
Parent template (_tags/layout.pad):
<div class="container">
<aside class="sidebar">{include:sidebar}</aside>
<article class="content">
@content@
</article>
</div>
Child content, in a page:
{layout}
<h1>Page Title</h1>
<p>Page content goes here...</p>
{/layout}
{entries}
<div>{$name}: {$comment}</div>
@else@
<p>No entries found.</p>
{/entries}
{users}
{-- Header processed first --}
<table>
<tr><th>Name</th><th>Email</th></tr>
@start@
{-- Rows processed with data --}
<tr><td>{$name}</td><td>{$email}</td></tr>
@end@
{-- Footer processed last --}
</table>
<p>Total: {count@users} users</p>
{/users}
{if $debug eq 1}
@tidy@
{/if}
<html>
<!-- HTML will be tidied only in debug mode -->
</html>
@page@@page@ replaced with page content@start@, @end@ and @else@ splitting@content@ merging@tidy@ detection and HTML tidying