This page documents every front matter key Sculpin – PHP Static Site Generator itself recognises and acts on – what each one defaults to, what reads it, and what happens if you leave it out.
Front matter is the YAML block at the top of a source file, delimited by ---. Everything in it is parsed and exposed as page.KEY to templates; nested structures are reachable with dot notation (page.something.here).
A source without front matter still builds, but loses the computed <title> tag and any key-driven behaviour below.
This reference covers the Sculpin 3.x series, cross-checked against sculpin/sculpin at commit bff3efa.
How the Block Gets Parsed
Sculpin splits a source on the first 2 --- lines and hands the middle section to a YAML parser; everything after the second --- becomes the page’s content. Two details are easy to miss:
- A
datevalue that isn’t already numeric is run through PHP’sstrtotime(), sodate: March 15, 2024anddate: 2024-03-15both work. - Malformed YAML in the front matter block doesn’t fail the build. Sculpin catches the parse error, logs it to the console, and treats the whole file as plain content instead.
Source in code: FileSource::init(). Docs: Sources.
Content and Presentation Keys
- title
- Free text. Feeds the
:titleand:slug_titlepermalink tags (see Configuring sculpin_kernel.yml) and, per Sculpin’s own advice, is what keeps your page’s<title>element from being empty. No key means no default is generated for you. - slug
- A manual override for the auto-slugified title. Read directly by the permalink factory; if you don’t set it, permalink tags fall back to a slugified
titleor, failing that, the filename. - date
- Sets the source’s publish date. If omitted, Sculpin tries to read one out of the file’s path instead (next section).
- permalink
- Overrides the content type’s or the kernel’s default permalink pattern for this one source only.
- layout
- Names the template that wraps this source’s content, using Twig’s
extends/blockmechanism rather than simple string injection – see Layouts for how that inheritance actually works.
---
layout: default
title: Hello World
slug: custom-slug-here
---
Source in code: title and slug are both read in SourcePermalinkFactory::generatePermalinkPathname(), permalink in getPermaLinkTemplate().
Dates Without a date Key
If a source has no explicit date, Sculpin looks for a date-shaped pattern anywhere in its relative path – YYYY-MM-DD or YYYY/MM/DD, optionally followed by digits it will try to read as a time – and uses the first match it finds. The result is stored as calculated_date, and copied into date only if date wasn’t already set.
This is why a post filed under _posts/2024-03-15-hello-world.md doesn’t need a date key at all, and why a stray four-digit number elsewhere in a folder name can occasionally be misread as one.
Source in code: CalculatedDateFromFilenameMap::process().
The draft key
- draft
- Marks a source unpublished. Whether it’s actually skipped depends on the owning content type’s
publish_draftssetting (default:falsein theprodenvironment,trueeverywhere else).
When a draft is suppressed, it’s flagged to be skipped by the rest of the build entirely, not just hidden from listings.
When a draft is allowed through, Sculpin quietly adds drafts to its tags array (creating the array if none exists), which makes „show me only drafts“ a one-line tags filter in a template rather than a separate mechanism.
Source in code: DraftsFilter::match(), DraftsMap::process().
The tags and categories keys
The two taxonomies enabled by default for the built-in posts type. Both are plain arrays; a content type can define entirely different taxonomy names in its own sculpin_kernel.yml configuration (covered in Configuring sculpin_kernel.yml).
---
tags: [howto, php]
categories: [tutorials]
---
Keys That Talk to Templates: use, generator, pagination
These 3 don’t describe the source itself so much as tell Sculpin what role the source plays in generating other pages. They mostly appear in view templates, not in ordinary content sources.
- use
- An array of registered data provider names. Every name listed gets its full collection loaded into
data.<name>for that template – for example,use: [posts]makes every post available asdata.postsfor a listing page to loop over. - generator
- Names one or more registered generators that should act on this source, turning a single template into a factory for many generated pages. An unrecognised name fails loudly with an exception naming the offending file, rather than silently producing nothing.
- pagination
- Configuration read only by the
paginationgenerator, so it has no effect unlessgenerator: paginationis also set. 2 sub-keys:provider(defaultdata.posts; writedata.<name>for a data provider orpage.<key>for another array on the same source) andmax_per_page(defaults to the project-widesculpin_pagination.max_per_page, itself defaulting to 10).
---
generator: pagination
pagination:
provider: data.posts
max_per_page: 5
use:
- posts
---
Each page the pagination generator produces gets its own computed values: pagination.items, pagination.page, pagination.total_pages, pagination.total_items, pagination.previous_page and pagination.next_page. Pages beyond the first also get an automatically rewritten permalink, typically ending in /page/2.html, /page/3.html and so on – none of this is something you set, only something you read back.
Source in code: use in FormatterManager::buildBaseFormatContext(), generator in GeneratorManager::generate(), pagination in PaginationGenerator::generate(). Docs: Custom Types.
Computed, Not Set
A handful of page.* values you’ll see in templates are never front matter – Sculpin fills them in itself, and setting them yourself has no effect:
| Value | What it holds |
|---|---|
page.url |
The final generated URL for this source |
page.blocks.content |
The source’s rendered body, for a layout to place |
page.calculated_date |
The date Sculpin derived, whether or not you set date |
page.next_<type> / page.previous_<type> |
Neighbouring items in a content type’s collection |
page.pagination.* |
Per-page pagination state, described above |
Any Other Key You Like
Front matter isn’t limited to the keys above. Anything else you add is stored as-is and reachable as page.yourKey, including nested structures reached with dot notation:
---
something:
here:
very: deep
---
{{ page.something.here.very }} renders deep. Source: Sources.
Where to look in the source
| Topic | Class / file | Lines |
|---|---|---|
| Front matter parsing itself | FileSource | 54-123 |
| title / slug / permalink | SourcePermalinkFactory | 70-182 |
| Date from filename | CalculatedDateFromFilenameMap | 20-39 |
| draft | DraftsFilter, DraftsMap | 27-42, 20-43 |
| use | FormatterManager | 82-86 |
| generator | GeneratorManager | 65-86 |
| pagination | PaginationGenerator | 58-157 |
Sources
- Sources – sculpin.io
- Layouts – sculpin.io
- Content Types: Custom Types – sculpin.io
- Content Types: Posts – sculpin.io
- sculpin/sculpin source code (commit
bff3efa) – sculpin, GitHub
License
This document is © Robert Wetzlmayr and licensed under Creative Commons Attribution-ShareAlike 4.0 International. Reuse, adaptation and redistribution are welcome, including commercially, as long as attribution is given and any adapted version carries the same license. Sculpin itself remains under its own MIT license; this notice covers the text and structure of this page only, not the software it describes.