v0.4.0
Minor Changes
-
Markdown block elements support
{.class #id key=value}attribute syntax beyond headings. Fenced code blocks accept attributes on the opening fence line. Blockquotes and tables accept them on the trailing line.```go {.highlight #example} fmt.Println("hello") ``` > This is important {.callout}Render hooks expose attributes via
markup.attributesfor all block element types. When no attributes are present,markup.attributesis an empty map. Block-level attributes activate whenautoHeadingIDis true (the default). -
Add
includefunction to the Go template engine, matching Liquid’s{% include %}for cross-file template inclusion.{{ include "partials/header" }} {{ include "partials/card" (dict "item" . "compact" true) }}Includes resolve from the layouts directory (
.htmlextension, then raw name) and support nested calls. -
Add
limitarray filter that returns the first N elements, giving Go templates parity with Liquid.{{ range limit .collections.blog 5 }} <h2>{{ .data.title }}</h2> {{ end }} -
Liquid layout resolution falls back to bare extensions when
.liquidfiles are missing. The engine tries.liquidfirst, then the bare extension (e.g.,default.html,single.json) and parses the result as Liquid.Layout names with a recognized extension (e.g.,
layout: "base.html") serve as literal filenames. Bare names without an extension get the.liquid→.htmlfallback. -
Breaking: Remove filename-based layout matching. Alloy no longer matches
content/docs/getting-started.mdtolayouts/getting-started.liquid. Layouts resolve via three mechanisms:- Explicit
layout:in front matter or_data.yamlcascade - Date-based convention (
post.liquidfor section children,<section>.liquidfor index pages) default.liquidfallback
Add an explicit
layout:to your front matter or_data.yamlif you relied on filename matching. - Explicit
-
Breaking: Remove the
permalinks:key fromalloy.config.yaml. Set permalink patterns via_data.yamlcascade files in each section directory. Config files with a stalepermalinks:key load without error.# content/blog/_data.yaml permalink: "/:year/:month/:slug/" -
Render hooks receive richer context. Link hooks get
markup.titlefrom[text](url "title"). Heading hooks getmarkup.inner(rendered HTML),markup.text(plain text), andmarkup.attributes(goldmark attribute map).markup.iduses the explicit{#custom-id}attribute when present, falling back to the auto-generated slug.<h{{ markup.level }} id="{{ markup.id }}" class="{{ markup.attributes.class }}"> {{ markup.inner }} </h{{ markup.level }}> -
Disable sitemap generation site-wide with
sitemap: falsein the config file. Alloy generates sitemaps by default when omitted.# alloy.config.yaml sitemap: false -
Front matter permalinks accept full template syntax with
{{ }}expressions. Alloy renders these through the configured template engine with apage.*context containing front matter fields, date, slug, summary, and collection.--- permalink: "/{{ page.lang }}/{{ page.slug }}/" ---Template and token syntax are separate modes. When
{{appears, token syntax (:year,:slug) does not resolve. A template permalink that renders to empty or whitespace is a fatal build error. Pagination template permalinks respect the configured engine. -
Disable TOC generation site-wide with
content.markdown.toc: false. Alloy populatespage.tocfor all Markdown pages by default when omitted.# alloy.config.yaml content: markdown: toc: false -
Format layouts (JSON, XML, etc.) follow the same lookup order as HTML layouts. Alloy inserts the format name before the template extension, so a single bare layout name drives all output formats.
layout: article outputs: [html, json]Extension-bearing layout names (e.g.,
article.liquid) with format outputs produce a build error. Setlayoutto a bare name.
Patch Changes
-
Accept
"go"as an alias for"gotemplate"in thetemplates.engineconfig field. Alloy rejects unknown engine values with a clear error instead of falling through to Liquid. -
Remove the extensionless (raw name) fallback from partial/include resolution. Both engines try recognized extensions only: Liquid checks
widget.liquidthenwidget.html; Go templates checkwidget.html. -
Fix Go template format layouts resolving to
name.format.html(e.g.,default.json.html) instead of the bare format extension (default.json,feed.xml). -
Fix language-specific
_data.yamlpermalink patterns being ignored in multi-language builds. Apermalinkincontent/es/blog/_data.yamlapplies to pages in that directory instead of falling back to the default path-based URL. -
Tighten
{% inline %}tag validation. Paths must start with./or../. Alloy accepts text-based extensions only (.svg,.html,.css,.js,.json,.xml,.yaml,.mdand others). Binary types like.pngproduce an error pointing to<img>. -
Fix nested
_data.yamlpermalink patterns being ignored. Alloy resolves permalinks from the nearest_data.yamlin the directory tree, so subdirectories override their parent’s URL pattern.# content/blog/_data.yaml permalink: "/blog/:slug/" # content/blog/posts/_data.yaml permalink: "/blog/:year/:month/:slug/" -
Remove the broken
fingerprinttemplate filter. It hashed the path string instead of file contents and emitted no renamed file, so fingerprinted URLs would 404. Usecachebustfor query-string cache busting. -
absolute_urlprepends the site’s configuredbaseURLwhen called without an argument. Theurlfilter prepends the path portion ofbaseURLto relative paths.