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.01.0.
exclude list&lt;string&gt; 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&lt;string&gt; 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&lt;string&gt; Content type names to include. When omitted, all non-excluded pages are included.
exclude list&lt;string&gt; 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&lt;string&gt; 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.