Purpose
The editor-side hook for adding fields to the page edit form
without forking PagesModule. When the Pages module renders the
create or edit form, it dispatches this event once at the top.
A listener appends its own input markup into a named slot, and may
mark core fields hidden when they do not apply to a page-type.
PageSaving is the companion that persists what these inputs post.
Added in Scriptor 2.1.0 (hide() / isHidden() shipped in the
same release, after the base slot API).
FQCN + file path
- FQCN:
Scriptor\Boot\Events\Editor\PageFormRendering - Source:
boot/Events/Editor/PageFormRendering.php
When to use
Subscribe inside Plugin::register() when you want to:
- Add inputs to the page form (SEO meta, a price, a flag) that
save into the page's
databag. - Remove core fields that a page-type does not need (a product
child has no use for
menu_title).
Pair it with PageSaving: this event renders the
input, that one stores the posted value. Reach for an
editor module instead when the admin surface is a
separate screen rather than fields on the existing page form.
Surface
Public properties
| Property | Type | Purpose |
|---|---|---|
page |
readonly ?Page |
The page being edited; null on the new-page flow |
categoryId |
readonly int |
The iManager category id the form edits |
Public methods
public function appendHtml(string $html, string $slot = self::SLOT_END): void
Append markup into a named slot. Buffers concatenate when several listeners target the same slot. The buffer is printed verbatim, so the listener owns its HTML escaping (the event does not re-encode).
public function hide(string $field): void
public function isHidden(string $field): bool
hide() marks a core field skipped; PagesModule consults
isHidden() before rendering each built-in field. Field names
match the POST input names: name, menu_title, slug,
content, images, parent, template, position, published.
A hidden field posts no value, so its stored data is carried
forward untouched on save.
public function htmlFor(string $slot): string
Returns a slot's accumulated buffer. Called by PagesModule, not
by listeners.
Slot constants
Ten constants, one slot after each core field plus an end slot:
SLOT_AFTER_NAME, SLOT_AFTER_MENU_TITLE, SLOT_AFTER_SLUG,
SLOT_AFTER_CONTENT, SLOT_AFTER_IMAGES, SLOT_AFTER_PARENT,
SLOT_AFTER_TEMPLATE, SLOT_AFTER_POSITION,
SLOT_AFTER_PUBLISHED, SLOT_END. appendHtml() defaults to
SLOT_END (just before the hidden action/csrf inputs) when no slot
is given.
Constructor
public function __construct(public readonly ?Page $page, public readonly int $categoryId)
PagesModule constructs it. You do not construct it yourself.
Lifecycle
Fires once per edit-form render, inside
PagesModule::renderForm(). After dispatch, PagesModule walks
the core fields in order: for each one it checks isHidden() and
skips the field if a listener hid it, then prints
htmlFor(SLOT_AFTER_<field>). SLOT_END prints last, before the
form's hidden inputs. Listeners run in registration order; slot
buffers from multiple plugins concatenate in that order.
The event carries no state beyond the request. The page it
references is the one currently being edited (or null when the
operator is creating a new page, so always read $event->page?->…
defensively).
Common patterns
Add a field under the Content textarea
$context->subscribe(
\Scriptor\Boot\Events\Editor\PageFormRendering::class,
function (\Scriptor\Boot\Events\Editor\PageFormRendering $event): void {
$current = (string) ($event->page?->meta_title ?? '');
$event->appendHtml(
'<div class="form-control"><label for="meta-title">Meta title</label>'
. '<input id="meta-title" name="meta_title" type="text" value="'
. htmlspecialchars($current, ENT_QUOTES) . '"></div>',
\Scriptor\Boot\Events\Editor\PageFormRendering::SLOT_AFTER_CONTENT,
);
},
);
Hide a core field for a page-type
$context->subscribe(
PageFormRendering::class,
function (PageFormRendering $event): void {
if ($event->page?->template !== 'produkt') {
return;
}
$event->hide('menu_title'); // products are not nav items
$event->appendHtml($priceInput, PageFormRendering::SLOT_AFTER_SLUG);
},
);
Core fields are read from $_POST after this event fires, so
PageSaving::mergeData() cannot override a built-in value. To
replace a core field with your own widget, hide() it and
re-inject an input under the same name.
See also
PageSaving: the persist-side companion; the two are almost always subscribed togetherPage: the DTO$event->pagecarries;__getresolves data-bag keys such as$page->meta_titlePlugin: where you subscribe, inregister()Module: the alternative when the admin surface is a separate screen rather than page-form fields- Cookbook: Add fields to the page edit form: the worked recipe, including the JSON-blob storage round trip
- Concept: Editor extensions: how editor events, modules, and the container fit together