v0.39.0

2 November 2026

Pages can be kept level with an external source, and code and markdown fields return their source from decode().

Added

  • Page::sync($records, $prune = false) keeps a page's children level with an external source. $records maps each child's slug to its data. A missing child is created, and the rest of the data is written to the child's _source.json, which a save never touches, so what an editor saved in _data.json stays over it. $prune deletes the children that have a _source.json and are no longer in $records. The whole sync is one History entry.
  • A page's _source.json is read under its _data.json, committed with the page and restored with its revisions.
  • Page::withData($data) returns a copy of the page that reads $data as its content, for showing and never saved.
  • FieldValue::html() on a markdown field and FieldValue::highlight() on a code field return the rendered HTML.
  • A field inside a stack, blocks or repeater can use site/views/fields/{view}/{parent}/{name}.latte, which is tried before site/views/fields/{view}/{name}.latte.

Changed

  • decode() on a code or markdown field, and $value in its render.latte, hold the stored source instead of HTML. {$page->field} and |render print the same as before.
  • History::pageAt() is now History::revision(), and a revision is the page itself with its content swapped through Page::withData().

Removed

  • The Phlat\History\Revision class.

Bug fix releases