Core extensions #
Glaze ships with built-in extensions that are opt-in — they do nothing unless explicitly enabled in glaze.neon. This keeps every project lean: no sitemap, no extra files, unless you ask for them.
Enabling core extensions #
Add an extensions key to glaze.neon with the names of the extensions you want:
extensions:
- sitemap
- llms-txt
- search-index
Each entry matches the name declared in the extension’s #[GlazeExtension] attribute.
You can mix core names, project extension names (from your extensions/ directory), and fully-qualified class names in the same list:
extensions:
- sitemap
- my-project-hook
- App\Extensions\AnalyticsExtension
Passing options #
Extensions that implement ConfigurableExtension accept per-extension options. Switch from list to map syntax for any extension that needs them:
extensions:
- llms-txt
my-extension:
apiKey: abc123
endpoint: https://example.com/hook
List and map entries can be mixed freely.
Available extensions #
sitemap #
Generates a sitemap.xml file in the output directory after each successful build.
The sitemap is built from all written pages. Last-modified dates are resolved from frontmatter keys (lastmod, lastModified, updatedAt, date), falling back to the source file’s modification time.
extensions:
- sitemap
The sitemap URL is constructed from site.baseUrl and site.basePath in glaze.neon. Configure your site metadata for correct absolute URLs:
site:
baseUrl: https://example.com
basePath: /docs
Options #
Switch to map syntax to pass options:
extensions:
sitemap:
changefreq: weekly
priority: 0.8
exclude:
- /drafts
| Option | Type | Description |
|---|---|---|
changefreq |
string | <changefreq> value added to every URL entry. One of: always, hourly, daily, weekly, monthly, yearly, never. |
priority |
float | <priority> value added to every URL entry. Clamped to the range 0.0–1.0. |
exclude |
list<string> | URL path prefixes whose pages are omitted from the sitemap. |
llms-txt #
Generates an llms.txt file in the output directory — a lightweight machine-readable index intended for LLM ingestion workflows.
The file lists all built pages with their title, description, and canonical URL, following the llms.txt convention.
extensions:
- llms-txt
Page descriptions are resolved from the description frontmatter field, falling back to the first paragraph of the page body.
Options #
Switch to map syntax to pass options:
extensions:
llms-txt:
title: My Project
pitch: A static site generator for PHP developers.
context: Browse the links below for complete documentation.
exclude:
- /drafts
| Option | Type | Description |
|---|---|---|
title |
string | Overrides the # heading line. Falls back to site.title. |
pitch |
string | Overrides the > quote line. Falls back to the auto-resolved project pitch. |
context |
string | Overrides the context paragraph below the quote. |
exclude |
list<string> | URL path prefixes whose pages are omitted from the listing. |
rss #
Generates an RSS 2.0 feed.xml in the output directory after each successful build.
Each built page becomes an <item> with a title, canonical link, description, publication date, and a permalink <guid>. Items are sorted newest-first by publication date; pages with no resolvable date appear at the end in URL-path order.
extensions:
- rss
Dates are resolved from frontmatter keys date, pubDate, and publishedAt (in that order). Descriptions come from description, summary, or excerpt.
Use site.baseUrl and site.basePath in glaze.neon to produce correct absolute URLs and the <atom:link rel="self"> element required by feed readers:
site:
baseUrl: https://example.com
extensions:
- rss
Options #
Switch to map syntax to pass options:
extensions:
rss:
filename: blog.xml
title: My Blog
description: Latest posts from My Blog.
types:
- blog
- news
exclude:
- /drafts
- /private
| Option | Type | Description |
|---|---|---|
filename |
string | Output filename written in the build output directory. Default: feed.xml. |
title |
string | Overrides the feed channel <title>. Falls back to site.title. |
description |
string | Overrides the channel <description>. Falls back to site.description. |
types |
list<string> | Content type names to include. When omitted, all non-excluded pages are included. |
exclude |
list<string> | URL path prefixes whose pages are omitted from the feed. |
Feed discovery #
Add a <link rel="alternate"> tag to your layout template so browsers and feed readers can auto-discover the feed:
<link rel="alternate" type="application/rss+xml"
title="<?= h($site->title) ?>"
href="<?= $site->baseUrl ?>/feed.xml">
search-index #
Generates a search-index.json file in the output directory — a MiniSearch-compatible JSON array of page documents.
Each document includes:
-
id -
title -
description -
url -
content(plain text extracted from rendered HTML)
extensions:
- search-index
Options #
Switch to map syntax to pass options:
extensions:
search-index:
filename: site-search.json
toc: true
exclude:
- /drafts
- /private
| Option | Type | Description |
|---|---|---|
filename |
string | Output filename written in the build output directory. Default: search-index.json. |
toc |
bool | Include heading-level anchor documents from page TOC entries. Default: true. |
exclude |
list<string> | URL path prefixes whose pages are omitted from the index. |
MiniSearch pseudo example #
import MiniSearch from 'minisearch'
// 1) Load generated index from Glaze output
const docs = await fetch('/search-index.json').then((r) => r.json())
// 2) Create MiniSearch with fields produced by the extension
const mini = new MiniSearch({
idField: 'id',
fields: ['title', 'description', 'content'],
storeFields: ['title', 'description', 'url'],
})
// 3) Index and search
await mini.addAllAsync(docs)
const results = mini.search('glaze extension')
// 4) Render result links (pseudo)
for (const hit of results) {
console.log(hit.title, hit.url)
}
When toc is enabled, heading-level entries are included and can produce
results like Installation > New project setup that link directly to
/installation#New-project-setup.
The docs site itself uses this extension to power the built-in client-side search dialog.
Writing your own named extension #
Any extension class in your extensions/ directory with a name in its #[GlazeExtension] attribute can be opted into from glaze.neon the same way:
// extensions/Analytics.php
#[GlazeExtension('analytics')]
final class Analytics
{
#[ListensTo(BuildEvent::BuildCompleted)]
public function run(BuildCompletedEvent $event): void { ... }
}
extensions:
- analytics
See Extensions for the full extension authoring guide.