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/.