Extensions #
Extensions let you attach custom PHP logic to your Glaze project. There are two independent mechanisms, both activated by the #[GlazeExtension] attribute:
-
Template helpers — invokable classes callable as
$this->extension('name')from any Sugar template. -
Build event subscribers — classes with methods decorated with
#[ListensTo]that react to specific moments in the build pipeline.
A single class can do both at the same time.
Auto-discovery #
Create an extensions/ directory at your project root. Any class decorated with #[GlazeExtension] placed there is discovered and registered automatically.
The directory is extensions/ by default. Override it in glaze.neon:
extensionsDir: src/Extensions
Classes that do not carry #[GlazeExtension] are silently skipped, so helper files can live alongside extension classes without issue.
Template helpers #
A template helper is a named, invokable class. Provide a non-empty name in the attribute and implement __invoke().
extensions/LatestRelease.php:
<?php
use Glaze\Template\Extension\GlazeExtension;
#[GlazeExtension('version')]
final class LatestRelease
{
public function __invoke(): string
{
return trim((string)file_get_contents(__DIR__ . '/../VERSION'));
}
}
Call it from any Sugar template:
<footer>Version <?= $this->extension('version') ?></footer>
Extension results are memoized per build – however many templates call the same extension, the underlying PHP runs exactly once.
Arguments are forwarded to __invoke() on its first invocation:
#[GlazeExtension('asset')]
final class AssetExtension
{
public function __invoke(string $path): string
{
return '/assets/' . ltrim($path, '/');
}
}
<link rel="stylesheet" href="<?= $this->extension('asset', 'css/site.css') ?>">
Note: Because results are cached after the first call, passing different arguments on subsequent calls returns the result from the first invocation. Design extensions that take arguments as single-invocation helpers.
Calling an unregistered name throws a RuntimeException:
Glaze extension "versin" is not registered. Available: version, asset
Build event subscribers #
Extensions can also listen to events fired during the static build. Add one or more public methods decorated with #[ListensTo(BuildEvent::X)].
A class that only subscribes to events does not need a name or __invoke() – omit the name argument entirely:
<?php
use Glaze\Build\Event\BuildCompletedEvent;
use Glaze\Build\Event\BuildEvent;
use Glaze\Build\Event\PageWrittenEvent;
use Glaze\Template\Extension\GlazeExtension;
use Glaze\Template\Extension\ListensTo;
#[GlazeExtension]
final class SitemapGenerator
{
private array $urls = [];
#[ListensTo(BuildEvent::PageWritten)]
public function collect(PageWrittenEvent $event): void
{
$this->urls[] = $event->page->urlPath;
}
#[ListensTo(BuildEvent::BuildCompleted)]
public function write(BuildCompletedEvent $event): void
{
$sitemap = $this->buildSitemap($this->urls, $event->config->site->baseUrl);
file_put_contents($event->config->outputPath() . '/sitemap.xml', $sitemap);
}
}
A class with both a name and event listeners is valid – it registers as both a template helper and a subscriber:
#[GlazeExtension('stats')]
final class StatsExtension
{
private int $pageCount = 0;
#[ListensTo(BuildEvent::PageWritten)]
public function count(PageWrittenEvent $event): void
{
$this->pageCount++;
}
public function __invoke(): int
{
return $this->pageCount;
}
}
Build events reference #
| Event | Payload | Mutable fields | When |
|---|---|---|---|
BuildEvent::BuildStarted |
BuildStartedEvent |
— | Before content discovery |
BuildEvent::ContentDiscovered |
ContentDiscoveredEvent |
$pages |
After discovery, before rendering |
BuildEvent::PageRendered |
PageRenderedEvent |
$html |
After each page renders, before writing |
BuildEvent::PageWritten |
PageWrittenEvent |
— | After each page is written to disk |
BuildEvent::BuildCompleted |
BuildCompletedEvent |
— | After all pages and assets are written |
Mutable fields let you modify the build in place. Set ContentDiscoveredEvent::$pages to inject or remove pages, or set PageRenderedEvent::$html to post-process rendered output.
BuildStartedEvent #
$event->config — BuildConfig
Useful for opening file handles, recording a start time, or validating external prerequisites.
ContentDiscoveredEvent #
$event->pages — ContentPage[] (mutable)
$event->config — BuildConfig
Mutate $pages to inject virtual pages, reorder, augment metadata, or filter the list.
PageRenderedEvent #
$event->page — ContentPage
$event->html — string (mutable)
$event->config — BuildConfig
Mutate $html to minify output, inject analytics snippets, or extract content for a search index.
PageWrittenEvent #
$event->page — ContentPage
$event->destination — string (absolute output path)
$event->config — BuildConfig
Useful for accumulating sitemap entries, search-index records, or per-page statistics.
BuildCompletedEvent #
$event->writtenFiles — string[] (absolute paths)
$event->config — BuildConfig
$event->duration — float (seconds)
Useful for writing derived files (sitemap, search index, RSS feed) and triggering post-build hooks.