Page
A page on the site.
Routes its own URLs, renders its view, and exposes its fields, children, parents and files to templates.
Properties (14)
| $page->router | Router | readonly | |
| $page->view | ?string | readonly | |
| $page->published | bool | readonly | Whether this page is live - true unless _index.json says false. |
| $page->access | string | readonly | Who may open this page: '' for anyone, 'login' for any signed-in user, or role names joined by '|'. |
| $page->hidden | bool | readonly | Whether this page is left out of navigation and child lists. |
| $page->position | int | readonly | Where this page sits among its siblings when its parent's view sorts by `position` - set by dragging it in the admin tree. |
| $page->uri | string | readonly | |
| $page->path | string | readonly | |
| $page->objectRoot | string | readonly | |
| $page->uuid | string | readonly | |
| $page->locked | bool | readonly | |
| $page->created | ?int | readonly | |
| $page->updated | ?int | readonly | |
| $page->isRoot | bool | readonly |
Identity 8
- fragment Whether this page renders as a bare fragment - its own _index.json wins over the view's default.
- objectType Always `page`.
- boundClass The class App::loadType() looks for when views/{name}/{name}.php declares a bound subclass, e.g. "article" -> ArticlePage.
- registryKeyFor Builds a page registry key from a raw page uuid, for callers without a live Page instance.
- registryPath The path stored in the registry for this object.
- registryFields Extra registry columns this object type contributes (e.g. view for pages, role for users).
- isVirtual Whether this page's view says `"virtual": true`: its pages come from a source page, never from the registry.
- virtual A virtual child of this source page: $data from the source, with the overlay folder at its URL (if any) over it.
Saving 3
- save Persists page data, routing structural fields to _index.json and content fields to _data.json.
- delete Deletes this page and its persisted subtree - PageCollection::delete() for one page, which has the details.
- move Moves (or renames) this page and its whole subtree to $newPath, e.g. "blog/2026/post".
Fields 6
- fields Returns this page's template fields as resolved FieldValue instances.
- settingFields The structural settings an editor sets - published, access, hidden, locked - as FieldValues, so the admin edits them with the same field UI as everything else.
- childFields The fields a new child is made from: its name, unless this view names pages by uuid, and its view when there is a choice.
- viewFields The view a page without one is given: the ones its parent's view takes, or any when it names none.
- moveFields The fields a move is made from: the page's name and its parent, any page whose view takes this one's (or where it is now).
- viewConfig Returns app-level config under $key merged with this view's override of the same key.
Drafts 4
- hasAutosave Whether an unsaved draft exists for this page.
- autosave Persists a draft snapshot outside the normal save path - no _index.json, no registry, no git.
- discardAutosave Clears any pending draft.
- data The page's content file.
Rendering 6
- view The view that renders this page; throws when the page has none.
- session Session data scoped to this page's own view - auto-namespaced, no manual scope('name') needed.
- emit Fires `{view}/{event}`, this page's own view as the prefix, so a page can't spell a core event (core names have no slash).
- controller Includes a view's controller file and calls it if it returns a callable; returns the resulting data array.
- render Renders the page view, merging in global and view-specific controller data.
- cache This page's part of the fragment cache.
Access 3
- isPublic Whether anyone at all may open this page - it and every ancestor published and open to all - whoever is asking.
- isViewable Whether the current visitor may open this page.
- assertViewable Throws what the current visitor gets for a page they may not open: a 404 for an unpublished one (it doesn't admit to existing), a login redirect for a gated page when signed out, a 403 when signed in without the role.
Routing 5
- route Dispatches the request sub-path against this page's view router.
- remainder Returns the request path after stripping this page's own URL prefix, trimmed of slashes.
- target Resolves remainder() as a Page, the common case behind most remainder() call sites.
- segment Returns the nth segment (1-indexed) of the request sub-path, or null.
- url Returns the site-relative URL by stripping the pages/ root from the filesystem path.
Tree 18
- parent Returns the parent page, or null if this page has no parent (including root pages).
- parents Returns all ancestor pages from root to immediate parent, lazily computed and cached.
- closest Returns the nearest page matching $query (the find() DSL) walking up from this page, this page included, or null if none does.
- root Returns the root page.
- section Returns the top-level section page.
- depth Returns the depth in the page tree. 0 for root pages.
- childDepth The depth new children are placed at: one below this page, or deeper when its view's `children.path` puts them in folders.
- reorderable Whether this page's children are put in order by hand: its view's `children.sort` is `position`.
- childViews The views an editor may give a new child: the view's `children.views`.
- siblings Returns sibling pages - children of the parent, excluding this page.
- next Returns the next sibling in parent's child order, or null if this is the last.
- prev Returns the previous sibling in parent's child order, or null if this is the first.
- contains True if $other is this page or a descendant of it.
- hasChildren True if this page has any children.
- isActive True if this page is the current request page.
- isOpen True if this page is active or contains the active page.
- child Returns a named child page without checking whether it exists.
- has Whether a child page folder already exists on disk.
Children 6
- new Creates a new child page: mints its uuid and writes a complete, minimal _index.json in one shot, then applies $data via the normal save() path - structural keys (view/hidden/ published/locked) to _index.json, everything else to _data.json (only written if there's content).
- children Queries the registry for direct child pages, ordered by the view's own `children.sort` (_index.json), unless $query supplies its own sort= to override it.
- pageLimit The page size: $limit, else the view's `pagination.limit` over the app's. 0 means no limit.
- paginate The current `?page=N` slice of children($query); every child when the limit is 0.
- pageCount How many pages children($query) fill at the page limit; 1 when the limit is 0.
- find Queries the registry for pages within this page's subtree.
Files 5
- fileSourcePath Folder a file() call mirrors source files from.
- publicPath Returns this page's public-mirror directory, e.g. "" -> public/, "blog/post" -> public/blog/post.
- file Resolves a file from this page's own folder.
- image Resolves an image from this page's own folder.
- files This page's files, narrowed by the query DSL over filename, name, extension, type, mime, size, modified and their metadata fields: `files('type=image,sort=filename,limit=4')`.
From Record 12
- assertUnlocked A locked record is protected: it can't be changed or deleted until `locked` is turned off.
- create The one way a record comes into being: under the lock for $key (default: the path) $guard refuses a conflict, then $make builds the record at $path and save() applies $data.
- exists Whether the record is on disk.
- generateUuid The current system uuid format - the single source of truth for tooling that needs to mint or recognize one.
- index The `_index.json` file: uuid, timestamps and the type's structural keys.
- isSiteObject Whether it lives in the site rather than in `phlat/` or an addon.
- keyFor Builds a registry uuid key from a type and identity value, e.g. keyFor('page', $uuid) -> "page:{uuid}".
- name The folder name: the last segment of a page's URL, or a username.
- path The record's folder, with a trailing slash.
- publishedData The canonical _data.json contents, bypassing any draft/preview override (e.g.
- registryKey The registry's uuid key for this object, e.g. "page:{uuid}".
- upload Validates and stores an uploaded file (a raw $_FILES-shape array) into this record's own folder.
Identity
$page->fragment(): bool
Whether this page renders as a bare fragment - its own _index.json wins over the view's default.
Returns bool
phlat/src/Page.php:74
boundClass
staticPage::boundClass(string $name): string
The class App::loadType() looks for when views/{name}/{name}.php declares a bound subclass, e.g. "article" -> ArticlePage.
Nested/hyphenated names normalize to the same class: "catalogue/record" and "catalogue-record" both -> CatalogueRecordPage.
Parameters (1)
| $name | string |
Returns string
phlat/src/Page.php:87
registryKeyFor
staticPage::registryKeyFor(string $uuid): string
Builds a page registry key from a raw page uuid, for callers without a live Page instance.
Parameters (1)
| $uuid | string |
Returns string
phlat/src/Page.php:107
$page->registryPath(): string
The path stored in the registry for this object.
Returns string
phlat/src/Page.php:112
$page->registryFields(): array
Extra registry columns this object type contributes (e.g. view for pages, role for users).
Returns array
phlat/src/Page.php:117
$page->isVirtual(): bool
Whether this page's view says `"virtual": true`: its pages come from a source page, never from the registry.
Returns bool
phlat/src/Page.php:135
Saving
$page->delete(): void
Deletes this page and its persisted subtree - PageCollection::delete() for one page, which has the details.
phlat/src/Page.php:208
$page->move(string $newPath): Page
Moves (or renames) this page and its whole subtree to $newPath, e.g. "blog/2026/post".
Refuses a locked page or locked descendant, a destination that exists or has no parent page, and a move into itself. Drops the image variants recorded under the old URL, since both their rows and their public mirrors would otherwise outlive the page there, then re-indexes the old and new subtrees. Returns the page at its new path.
Parameters (1)
| $newPath | string |
Returns Page
phlat/src/Page.php:220
Fields
$page->fields(): FieldValueSet
Returns this page's template fields as resolved FieldValue instances.
Returns FieldValueSet
phlat/src/Page.php:270
$page->settingFields(): FieldValueSet
The structural settings an editor sets - published, access, hidden, locked - as FieldValues, so the admin edits them with the same field UI as everything else.
Built here because their values come from _index.json rather than _data.json and so never appear in fields(). A locked page only accepts the lock toggle, so the rest are read-only until it is turned off.
Returns FieldValueSet
phlat/src/Page.php:285
$page->childFields(): FieldValueSet
The fields a new child is made from: its name, unless this view names pages by uuid, and its view when there is a choice.
Returns FieldValueSet
phlat/src/Page.php:318
$page->viewFields(): FieldValueSet
The view a page without one is given: the ones its parent's view takes, or any when it names none.
Returns FieldValueSet
phlat/src/Page.php:333
$page->moveFields(): FieldValueSet
The fields a move is made from: the page's name and its parent, any page whose view takes this one's (or where it is now).
Returns FieldValueSet
phlat/src/Page.php:340
$page->viewConfig(string $key): array
Returns app-level config under $key merged with this view's override of the same key.
Parameters (1)
| $key | string |
Returns array
phlat/src/Page.php:359
Drafts
$page->hasAutosave(): bool
Whether an unsaved draft exists for this page.
Returns bool
phlat/src/Page.php:367
$page->autosave(array $data): void
Persists a draft snapshot outside the normal save path - no _index.json, no registry, no git.
Parameters (1)
| $data | array |
phlat/src/Page.php:373
$page->discardAutosave(): void
Clears any pending draft.
Called automatically on a real save.
phlat/src/Page.php:382
$page->data(): DataFile
The page's content file.
The admin preview reads the editor's draft in its place.
Returns DataFile
phlat/src/Page.php:392
Rendering
$page->view(): PageView
The view that renders this page; throws when the page has none.
Returns PageView
phlat/src/Page.php:407
$page->emit(string $event, mixed ...$args): void
Fires `{view}/{event}`, this page's own view as the prefix, so a page can't spell a core event (core names have no slash).
Parameters (2)
| $event | string | |
| ...$args | mixed |
phlat/src/Page.php:421
$page->controller(string $viewName, array $context = []): array
Includes a view's controller file and calls it if it returns a callable; returns the resulting data array.
Parameters (2)
| $viewName | string | |
| $context | array = [] |
Returns array
phlat/src/Page.php:438
$page->render(array $data = [], ?string $block = null): string
Renders the page view, merging in global and view-specific controller data.
A :block
declared {fragment 'name', cache: N} is served from the fragment cache before any
controller runs. Such a block must not set response headers - a hit replays only the body.
Parameters (2)
| $data | array = [] | |
| $block | ?string = null |
Returns string
phlat/src/Page.php:453
$page->cache(): Cache
This page's part of the fragment cache.
Whatever it holds is cleared when the page is saved, moved or deleted, or a page below it is - so a page's cache is only as stale as its subtree.
Returns Cache
phlat/src/Page.php:489
Access
$page->isPublic(): bool
Whether anyone at all may open this page - it and every ancestor published and open to all - whoever is asking.
Returns bool
phlat/src/Page.php:508
$page->isViewable(): bool
Whether the current visitor may open this page.
See assertViewable().
Returns bool
phlat/src/Page.php:518
$page->assertViewable(): void
Throws what the current visitor gets for a page they may not open: a 404 for an unpublished one (it doesn't admit to existing), a login redirect for a gated page when signed out, a 403 when signed in without the role.
The page and every ancestor must pass, and editors and the CLI see everything (App::isEditor()). Registry::scope() applies the same rule to listings.
phlat/src/Page.php:529
Routing
$page->remainder(): string
Returns the request path after stripping this page's own URL prefix, trimmed of slashes.
Returns string
phlat/src/Page.php:639
$page->segment(int $n): ?string
Returns the nth segment (1-indexed) of the request sub-path, or null.
Parameters (1)
| $n | int |
Returns ?string
phlat/src/Page.php:655
$page->url(string $path = '', array $query = []): string
Returns the site-relative URL by stripping the pages/ root from the filesystem path.
Always starts with /, never ends with / except root which is just /.
Parameters (2)
| $path | string = '' | |
| $query | array = [] |
Returns string
phlat/src/Page.php:662
Tree
$page->parents(string $query = ''): PageCollection
Returns all ancestor pages from root to immediate parent, lazily computed and cached.
A $query (the find() DSL, e.g. 'view=section') keeps only the ancestors that match.
Parameters (1)
| $query | string = '' |
Returns PageCollection
phlat/src/Page.php:686
$page->depth(): int
Returns the depth in the page tree. 0 for root pages.
Returns int
phlat/src/Page.php:747
$page->childDepth(): int
The depth new children are placed at: one below this page, or deeper when its view's `children.path` puts them in folders.
Returns int
phlat/src/Page.php:753
$page->reorderable(): bool
Whether this page's children are put in order by hand: its view's `children.sort` is `position`.
Returns bool
phlat/src/Page.php:759
$page->childViews(): array
The views an editor may give a new child: the view's `children.views`.
None listed means it takes no children.
Returns array
phlat/src/Page.php:765
$page->siblings(string $query = '', bool $includeHidden = false): PageCollection
Returns sibling pages - children of the parent, excluding this page.
Excludes hidden pages unless $includeHidden is true.
Parameters (2)
| $query | string = '' | |
| $includeHidden | bool = false |
Returns PageCollection
phlat/src/Page.php:771
$page->next(string $query = '', bool $includeHidden = false): ?Page
Returns the next sibling in parent's child order, or null if this is the last.
With a $query (the find() DSL), the next one that matches.
Parameters (2)
| $query | string = '' | |
| $includeHidden | bool = false |
Returns ?Page
phlat/src/Page.php:781
$page->prev(string $query = '', bool $includeHidden = false): ?Page
Returns the previous sibling in parent's child order, or null if this is the first.
With a $query (the find() DSL), the previous one that matches.
Parameters (2)
| $query | string = '' | |
| $includeHidden | bool = false |
Returns ?Page
phlat/src/Page.php:787
$page->hasChildren(bool $includeHidden = false): bool
True if this page has any children.
Parameters (1)
| $includeHidden | bool = false |
Returns bool
phlat/src/Page.php:826
$page->isActive(): bool
True if this page is the current request page.
Returns bool
phlat/src/Page.php:832
$page->isOpen(): bool
True if this page is active or contains the active page.
Returns bool
phlat/src/Page.php:838
$page->has(string $slug): bool
Whether a child page folder already exists on disk.
Parameters (1)
| $slug | string |
Returns bool
phlat/src/Page.php:852
Children
$page->new(string $name, array $data = []): Page
Creates a new child page: mints its uuid and writes a complete, minimal _index.json in one shot, then applies $data via the normal save() path - structural keys (view/hidden/ published/locked) to _index.json, everything else to _data.json (only written if there's content).
The page is published unless $data says published => false. Where it goes is
this page's view's children.path - {year}/{month}/{day}/{slug}, {uuid:2}/{uuid} - and
any folder on the way is made as a hidden page of this view. Throws NotFoundException if
this page doesn't exist, ForbiddenException if it is locked or not in pages/, and
ConflictException if the slug is already taken.
Parameters (2)
| $name | string | |
| $data | array = [] |
Returns Page
phlat/src/Page.php:869
$page->children(string $query = '', bool $includeHidden = false): PageCollection
Queries the registry for direct child pages, ordered by the view's own `children.sort` (_index.json), unless $query supplies its own sort= to override it.
Excludes hidden pages unless $includeHidden is true or $query supplies its own hidden= condition. Pass a depth= condition in $query to override the direct-children depth - the two will conflict rather than combine.
Parameters (2)
| $query | string = '' | |
| $includeHidden | bool = false |
Returns PageCollection
phlat/src/Page.php:944
$page->pageLimit(?int $limit = null): int
The page size: $limit, else the view's `pagination.limit` over the app's. 0 means no limit.
Parameters (1)
| $limit | ?int = null |
Returns int
phlat/src/Page.php:969
$page->paginate(string $query = '', ?int $limit = null): PageCollection
The current `?page=N` slice of children($query); every child when the limit is 0.
Parameters (2)
| $query | string = '' | |
| $limit | ?int = null |
Returns PageCollection
phlat/src/Page.php:975
$page->pageCount(string $query = '', ?int $limit = null): int
How many pages children($query) fill at the page limit; 1 when the limit is 0.
Parameters (2)
| $query | string = '' | |
| $limit | ?int = null |
Returns int
phlat/src/Page.php:987
$page->find(string $query = ''): PageCollection
Queries the registry for pages within this page's subtree.
Recursive by default - pass a depth= condition in $query (e.g. 'depth=' . ($page->depth() + 1)) to limit to a single level.
Parameters (1)
| $query | string = '' |
Returns PageCollection
phlat/src/Page.php:1006
Files
$page->fileSourcePath(): string
Folder a file() call mirrors source files from.
Overridden by AddonPage, whose files ship in the addon's pages folder even when a real site page backs it.
Returns string
phlat/src/Page.php:1021
$page->publicPath(): string
Returns this page's public-mirror directory, e.g. "" -> public/, "blog/post" -> public/blog/post.
Returns string
phlat/src/Page.php:1027
$page->files(string $query = ''): array
This page's files, narrowed by the query DSL over filename, name, extension, type, mime, size, modified and their metadata fields: `files('type=image,sort=filename,limit=4')`.
Parameters (1)
| $query | string = '' |
Returns array
phlat/src/Page.php:1050
From Record
$page->assertUnlocked(): void
A locked record is protected: it can't be changed or deleted until `locked` is turned off.
phlat/src/Data/Record.php:288
create
staticPage::create(App $app, string $path, array $data, callable $make, callable $guard, string $uuid = '', ?string $key = null): T
The one way a record comes into being: under the lock for $key (default: the path) $guard refuses a conflict, then $make builds the record at $path and save() applies $data.
Emits {page|user|item}.create:after.
Parameters (7)
| $app | App | |
| $path | string | |
| $data | array | |
| $make | callable | |
| $guard | callable | |
| $uuid | string = '' | |
| $key | ?string = null |
Returns T
phlat/src/Data/Record.php:90
$page->exists(): bool
Whether the record is on disk.
Returns bool
phlat/src/Data/Record.php:204
generateUuid
staticPage::generateUuid(App $app): string
The current system uuid format - the single source of truth for tooling that needs to mint or recognize one.
Parameters (1)
| $app | App |
Returns string
phlat/src/Data/Record.php:76
$page->index(): DataFile
The `_index.json` file: uuid, timestamps and the type's structural keys.
Returns DataFile
phlat/src/Data/Record.php:174
$page->isSiteObject(): bool
Whether it lives in the site rather than in `phlat/` or an addon.
Returns bool
phlat/src/Data/Record.php:168
keyFor
staticPage::keyFor(string $type, string $value): string
Builds a registry uuid key from a type and identity value, e.g. keyFor('page', $uuid) -> "page:{uuid}".
Parameters (2)
| $type | string | |
| $value | string |
Returns string
phlat/src/Data/Record.php:156
$page->name(): string
The folder name: the last segment of a page's URL, or a username.
Returns string
phlat/src/Data/Record.php:232
$page->path(): string
The record's folder, with a trailing slash.
Returns string
phlat/src/Data/Record.php:210
$page->publishedData(): DataFile
The canonical _data.json contents, bypassing any draft/preview override (e.g.
Page's autosave-aware data()). Writes and search indexing must always go through this, never the overridable data() accessor, so a draft in progress can never clobber or leak into the persisted record.
Returns DataFile
phlat/src/Data/Record.php:191
$page->registryKey(): string
The registry's uuid key for this object, e.g. "page:{uuid}".
Returns string
phlat/src/Data/Record.php:162