v0.23.0

Latest release

29 October 2026

The registry holds one row per record with a column per declared field, and every date is stored as a Unix timestamp in the files and the registry.

Changed

  • A registry query can filter and sort only on a declared field: one a view, a role or a collection field defines. A query naming any other field throws InvalidArgumentException. A declared field no record has written yet matches nothing.
  • Each declared field is a column of the registry table (items in a collection) with its own index. A list's or object's sub-values go to field_items. A page, user or item is one row, where field_index held a row per value.
  • created and updated in _index.json, the registry and collection items, and the value of a @phlat/datetime field, are Unix timestamps. Record::$created and Record::$updated are ?int, Collection::create() takes ?int stamps and Registry::updatedAt() returns ?int. phlat page:dates --apply rewrites existing pages and users; collection items convert on first read.
  • A date field and created and updated take dates in a condition: starts=2026-10-18 matches anywhere in that day in the site timezone, starts!=2026-10-18 is the rest, and a date with a time matches that instant. A date with no time is the whole day for <= and > as well: starts<=2026-10-18 includes that day and starts>2026-10-18 starts the day after.
  • < > <= >= match numbers only, so a field compared that way must be a @phlat/number or @phlat/datetime.
  • search_index stores no text of its own, so the registry file is a tenth of its size. Registry files need SQLite 3.43 or later.
  • Registry::SCHEMA is 21 and rebuilds on the first request. Collection databases drop their old index tables and reindex on first read.

Added

  • "query": false on a field option or in a fieldtype _index.json keeps the field out of the columns: it stays searchable with search= but cannot be filtered or sorted on. Markdown, richtext, code and password fields set it.
  • phlat page:dates [--apply] [folder...] lists, and with --apply writes, the date rewrite for pages and users.
  • FieldIndex::column($name) returns the column holding a field, and FieldIndex::forget() drops its cached column list.
  • @phlat/datetime rejects a value that is not a date with "Enter a valid date and time."

Fixed

  • cover_aspect>0,sort=-updated,limit=24 on 127,000 pages takes under 1 ms for the first page and 52 ms at offset 50,000, from 480 ms and 680 ms. Its count takes 86 ms, from 470 ms.