Purpose
The editor-side hook for persisting fields a plugin added to the
page form. When PagesModule is about to save a page (create or
update), it dispatches this event with the about-to-be-saved item.
A listener pulls its inputs off the request and calls mergeData()
to fold extra keys into the item's data bag before the write.
It is the persistence half of PageFormRendering:
that event renders the input, this one saves the posted value.
Added in Scriptor 2.1.0.
FQCN + file path
- FQCN:
Scriptor\Boot\Events\Editor\PageSaving - Source:
boot/Events/Editor/PageSaving.php
When to use
Subscribe inside Plugin::register(), alongside a
PageFormRendering listener, to store whatever that listener
rendered. Read the value with $event->input->postString('…')
and hand it to mergeData().
This event has no error or veto channel: a listener can add data
but cannot block the save or attach a validation error. Sanitise
and normalise the value in the listener (trim, collapse
whitespace, route through the Sanitizer); if a value is invalid,
store a cleaned version rather than trying to reject the save here.
Surface
Public properties
| Property | Type | Purpose |
|---|---|---|
item |
readonly Item |
The iManager item about to be saved, core fields already populated from the form |
input |
readonly Request |
Per-request input bag; listeners pull their own POST fields from it |
Public methods
public function mergeData(array $extra): void
Merge keys into the data the page will be saved with. Called any
number of times; later keys override earlier ones on collision.
PagesModule applies the accumulated set after dispatch.
public function extraData(): array
Returns everything merged so far. Called by PagesModule to read
the result; listeners rarely need it.
Constructor
public function __construct(public readonly Item $item, public readonly Request $input)
PagesModule constructs it. You do not construct it yourself.
Lifecycle
Fires inside PagesModule's save action, after the core Item is
assembled from the posted core fields and before the item is
written to storage. After dispatch, PagesModule checks
extraData(): if non-empty, it rebuilds the item with
data: [...$coreData, ...$saving->extraData()] and saves that.
When no listener merged anything, the save runs unchanged, so the
event is zero-cost when no plugin subscribes.
Because the core data is spread first and extraData() second,
a merged key whose name collides with a core key wins. In normal
use the keys are plugin-private (meta_title, price) and do not
collide.
Common patterns
Persist the fields a PageFormRendering listener rendered
$context->subscribe(
\Scriptor\Boot\Events\Editor\PageSaving::class,
function (\Scriptor\Boot\Events\Editor\PageSaving $event): void {
$event->mergeData([
'meta_title' => trim($event->input->postString('meta_title')),
]);
},
);
Gate persistence on a page-type
$context->subscribe(
PageSaving::class,
function (PageSaving $event): void {
if (($event->item->data->get('template') ?? '') !== 'produkt') {
return;
}
$event->mergeData([
'price' => trim($event->input->postString('price')),
'deposit' => trim($event->input->postString('deposit')),
]);
},
);
Read the template from $event->item->data rather than a
Page object: at save time the event carries the raw iManager
item, and its data bag already holds the posted template value.
See also
PageFormRendering: the render-side companion; subscribe to both togetherPlugin: where you subscribe, inregister()LifecyclePlugin: when the keys you merge should be real iManager fields instead ofdata-bag JSON- Cookbook: Add fields to the page edit form: the worked recipe for the render plus save round trip
- Concept: Editor extensions: the narrative model behind the editor events