v0.10.0

23 October 2026

Collections move to data/collections, every page write is a commit, and views, fields and includes are named per owner.

Added

  • children.path in a view's index.json decides where a new child page goes: {slug}, {uuid}, {uuid:N}, {year}, {month} and {day}, ending in {slug} or {uuid}. {year}/{month}/{slug} or {uuid:2}/{uuid} keeps a large section from becoming one flat folder. Page::new() places the page once and makes each missing folder as a hidden page of the section's view.
  • Registry indexes on (view, created) and (depth, created) keep a section's newest-first list fast at any size. Existing registries are updated in place, with no rebuild.
  • History::batch($message, fn() => ...) makes everything written inside it one commit. Nothing is recorded if it throws.
  • A field definition can extends another field and override its options, type or label.
  • $app->collection('tags')->create('', [...]) adds a collection item that belongs to no page.
  • Arr::combine(), Arr::search(), F::first(), Str::count(), Str::beforeLast(), Str::repeat() and Res::finish().

Changed

  • Every page write is committed by History, wherever it comes from: the admin, the CLI, an import or a site's own routes. Commits are built from objects for the changed paths only, about 30 ms for a page in a repository of 400k files, where git add and git commit took about a second.
  • Collection databases live at data/collections/{field}.db instead of data/pages/_{field}/items.db. Items have no files of their own: a file field on an item holds a filename of its page, or {page uuid}:{filename}.
  • A collection field name must be lowercase letters and digits with single hyphens or underscores. It names the database file.
  • Fields, fieldtypes, views and includes are resolved per owner. A bare name is the file owner's own and is never searched for past it. @alias/name names one root and @phlat the core. The site overrides by placing the file under @alias in its own folder of that kind, for example site/views/@phlat/errors/ or site/fields/@phlat/required/.
  • A page of an @alias view runs that owner's router, controller and shell, never the site's.
  • A field or fieldtype ref that names nothing is an error, and the message names the file it was written in.
  • site/ is its own repository, cloned into the framework checkout. deploy.php clones it into each release and the shared directories are under site/data/.
  • The 500 page uses the core errors view.
  • data/ is split: History's deploy key is data/git/, caches are data/cache/, and data/storage/ keeps only the registry, locks and rate limits.
  • registry:check reports collections still in the old layouts, and no longer treats an item with no page as a stray.
  • Registry::search queries start from the full-text match.
  • V::collectionSegment() is removed.

Comments

No comments yet. Be the first!

Loading form…