Fields
Field definitions, field types, and reading fields in templates and PHP.
Fields and field types
A field (site/fields/{name}/index.json) is a named, reusable definition: a label, a type and default options. A field type (phlat/fieldtypes/{type}/ or site/fieldtypes/{type}/) is the PHP class that gives a type its decode, encode and validate behaviour. A field picks a type; a type has no name of its own.
// site/fields/body/index.json
{
"label": "Body",
"type": "markdown",
"options": { "required": false }
}
Declaring fields for a view
A view's index.json lists the fields it uses under fields, keyed by name. The values override the field's options for that view; the type always comes from the field's own definition.
// site/views/post/index.json
{
"fields": {
"title": { "required": true, "max_length": 40 },
"body": {}
}
}
Reading fields
Record::__get, inherited by Page, resolves any undeclared property against data.json and returns a FieldValue:
{$page->title} decoded string
{$page->body|render} via the field type's render template
{if !$page->cover->empty()}
<img src="{$page->cover}">
{/if}
A FieldValue is always truthy in PHP, so check ->empty() before rendering optional fields.
$field = $page->body; // FieldValue
$raw = $field->value; // raw stored value
$out = $field->decode(); // decoded value (HTML for markdown, etc.)
$empty = $field->empty();
Built-in field types
| Type | Description |
|---|---|
text |
Plain string |
markdown |
Markdown source rendered to HTML via CommonMark |
code |
Source code, syntax-highlighted with Tempest Highlight. Stored as {language, code} |
image |
Image file reference, decodes to a PageImage (see Images) |
datetime |
ISO 8601 timestamp |
richtext |
HTML content, passed through unescaped |
repeater |
An ordered list of same-shape rows |
number |
Int or float, null if unset |
boolean |
True or false; an unchecked checkbox encodes to false |
select |
A string chosen from the declared options |
checkboxes |
Any subset of the declared options (a list, or a map of value to label), stored as a JSON list |
list |
A JSON array of strings, decodes to a PHP array |
object |
A JSON object, keys read as properties |
url |
An external URL, validated with San::url() |
color |
A hex color, #rgb normalized to #rrggbb |
password |
A hashed password, always blank on decode |
file |
A file stored on the page, decodes to a PageFile |
relation |
A UUID reference to another page, decodes to a Page |
datafile |
A companion JSON data file in the same directory |
blocks |
An ordered list of typed blocks, each a named group of sub-fields |
stack |
An ordered list where each entry references one global field by name |
collection |
Structured items stored alongside the page, queryable via the registry |
Repeaters
A repeater stores an ordered list of rows that share one shape, inline in data.json. The shape is declared under options.fields, naming other global fields:
// site/fields/nav/index.json
{
"label": "Navigation",
"type": "repeater",
"options": {
"fields": { "label": [], "href": [] }
}
}
Each row decodes to a mini page, so sub-fields read like page fields:
{foreach $page->nav->decode() as $item}
<a href="{$item->href}">{$item->label}</a>
{/foreach}
For rows of several shapes use blocks. For rows that need their own identity or queries, like comments, use collection.
Custom field types
Create site/fieldtypes/{type}/{type}.php, extending the primitive base that matches the JSON shape the type stores: FieldTypeText, FieldTypeNumber, FieldTypeList or FieldTypeObject.
<?php
namespace Phlat;
class FieldTypeRating extends FieldTypeNumber
{
public function decode(): mixed
{
// clamp stored value to 0-5
return max(0, min(5, (int) $this->value));
}
public function stars(): string
{
$filled = str_repeat('★', $this->decode());
$empty = str_repeat('☆', 5 - $this->decode());
return $filled . $empty;
}
}
site/fieldtypes/
rating/
rating.php ← class FieldTypeRating extends FieldTypeNumber
index.json ← optional, default search behaviour
edit.latte ← optional, admin field-editing UI
To control |render output, add site/views/fields/{type}.latte, which receives $field and $value (the decoded value). It is checked after site/views/fields/{view}/{name}.latte and site/views/fields/{name}.latte. edit.latte is a separate template for the admin editor.
Types in site/fieldtypes/ override matching types in phlat/fieldtypes/.