Shape the site
Data files
Data files hold what belongs to no one page, such as a site’s navigation or the people who write for it.
Put values in data/
data/
links.yaml
people.json
lists/
books.yaml
data/ sits at the top of the site’s folder. A template reaches each
file under site.data:
| File | In a template |
|---|---|
data/links.yaml |
site.data.links |
data/people.json |
site.data.people |
data/lists/books.yaml |
site.data.lists.books |
Statac reads files ending .yaml, .yml or .json. A value is what
YAML or JSON makes of it: 42 is a number, true is true, and anything
in quotes is text. A date is text too, except on a
page made from data, where it is the page’s
date.
Show them in a template
data/links.yaml:
- title: Link 1
address: https://example.org/
- title: Link 2
address: /about/
templates/base.html:
<ul>
{% for link in site.data.links %}
<li><a href="{{ link.address }}">{{ link.title }}</a></li>
{% endfor %}
</ul>
A name that can’t follow a dot goes in brackets:
site.data.words["en-GB"].
How a name with dots is read
| Written | Read as |
|---|---|
site.data.people |
data/people.yaml, .yml or .json |
site.data.people.staff |
data/people/staff.yaml where data/people/ is a folder; else the key staff: in data/people.yaml |
A template, an each: line and a declaration such as
one of data.people.staff all read a name this way.
What Statac won’t read
In data/ |
What happens |
|---|---|
A file with another ending, such as .csv |
It is left out. |
| A file whose name starts with a dot | It is passed over without a word. |
Two things at one name: people.yaml beside people/, or beside people.json |
The build stops. |
YAML’s merge key, << |
The build stops. Write the fields out in full. |
| A key written twice in one object | The build stops. |
Records and their fields
data/people.yaml:
person-1:
title: Person 1
role: Role 1
person-2:
title: Person 2
role: Role 2
A table such as this holds records, each under a name of its own. A
table written as a list, as data/links.yaml is, holds its records in
order, with no names.
The fields statac.yaml declares
for pages, such as fields.role: required text, hold for each page made
from a record.
A field that names a record
In statac.yaml:
fields.author: one of data.people
In content/post-1.md:
---
title: Post 1
author: person-1
---
Each author: is checked against the names in data/people.yaml. A
template is handed the name as written, so
site.data.people[page.author].role gives the record’s role.
Records in order have no names to check. Front matter has fields that name a page.
Make a page for each item
In content/people.md:
---
title: People
each: data.people
permalink: /people/{key}/
layout: person
---
The people who write here.
This makes /people/person-1/ and /people/person-2/, each built with
templates/person.html. The page itself is published at /people/, and
speaks for the list of the pages it made: page.posts holds
those with a date, and page.list.pages all of them.
| Line | What it does |
|---|---|
each |
data. and the table’s name, read as a template reads it: data.people, data.people.staff. |
permalink |
Needed: the pattern for each made page’s address, with at least one piece. A record’s own permalink: is its address instead. |
layout |
The template of the pages made, not the page’s own. |
type |
The page’s own template. Otherwise the page is built with folder.html, or home.html for content/index.md. |
pages. lines |
Handed down to the pages made. pages.layout: counts only where the page has no layout:, and pages.permalink: is never the pattern. |
index_page |
false publishes nothing at the page’s own address. |
A made page is built with the first of:
- the record’s own
layout:; - a template named by
type:, the record’s own or one handed down withpages.type:; - the
each:page’slayout:; - a
pages.layout:from theeach:page, the folders above it, orstatac.yaml; templates/page.html.
Pieces of the address
| Piece | Filled with |
|---|---|
{key} |
The record’s name, made ready for an address. |
{name} |
The record’s name, exactly as written. |
{slug} |
The record’s name, or else its title, made ready for an address. |
{year}, {month}, {day} |
Its date. |
{folder} |
The folder holding the each: page, and nothing at the top of content/. |
Any field, such as {isbn} or {title} |
Its text or number, made ready for an address. {date} gives 2026-01-05. |
Records in order have no names, so no {key} or {name}.
What a made page is
- A
date:makes it a post, in theeach:page’s list, the lists of the folder holding that page and every folder above it,site.posts, the site’s feed, and its tags and series. On anindex.mdwitheach:,page.postsholds the made posts alone, andpage.folder.postsholds them with the folder’s own. - A draft, or a record dated after today, gets a page only where the
run builds drafts: under
statac serve, or with--drafts. page.keyis its record’s name, andpage.sourcethe data file.
each: site.posts makes a page for each post instead: see
a page for each post.
Where next?
- Templates: what a template sees, and its filters and functions
- Front matter: declaring fields, and fields that name a record or a page
- Lists, tags and series: a page for each post, and lists in templates
- Dates and languages: the words
in
data/words.yaml
Something unclear or wrong? Open an issue on GitHub.