Pages::saved hook alerts without noise from autosaves and bulk edits
0 reputation · 17 Jul 2026, 16:08 UTC
0 reputation · 17 Jul 2026, 16:08 UTC
I want to add event-driven admin alerts to a ProcessWire 3.x site using the documented hook system: an addHookAfter on Pages::saved in /site/ready.php, surfacing routine events through session notices ($this->message() / $this->warning()) and reserving email for genuinely important edits. The filtering would use $page->getChanges(true) plus a template check so only meaningful field changes notify.
ProcessWire ships no throttling or digest mechanism, so dedup has to be built manually, e.g. storing a last-alert timestamp via WireCache or a hidden page field. What is unclear is the right event boundary: Pages::saved reportedly fires on autosaves, repeater sub-saves, and API-driven imports, so a naive hook would flood recipients during bulk operations. There is also a context question — hooks in ready.php run on every request, so gating by $this->process or role seems necessary, and session notices only reach the current admin user, not other editors.
Pages::saved vs Pages::published vs trash) and change-field filters gives a reliable signal without firing on autosaves and repeater writes?WireCache timestamp per page sufficient for dedup, or is a per-user/per-role throttle needed when several editors work concurrently?35275 reputation · 17 Jul 2026, 17:13 UTC
Hook Pages::saved with addHookAfter in /site/ready.php, but treat it as a raw signal, not a clean event: gate it by request context ($this->process), template, and $page->getChanges(true), throttle with a WireCache timestamp, and keep email out of the synchronous save path. What I cannot confirm from the information available is a reliable core API that flags autosaves or repeater sub-saves on the page object — so the honest recommendation is to verify that empirically before trusting any filter.
Pages::saved, the saved page arrives as $event->arguments(0); $event->object is the Pages instance, not the page.$page->getChanges(true) returns the fields changed in this save (with values), which is your primary noise filter — a save that changed nothing you care about should not alert.ready.php run on every request, so check $this->process (e.g. only ProcessPageEdit) and/or the current user's role before doing any work. This also naturally excludes most API-driven imports, which run outside ProcessPageEdit.$this->message(), $this->warning()) only reach the user in the current session — they cannot alert other editors.WireCache ($this->cache->get/save) is the standard place for a last-alert timestamp.wireMail() / the WireMail class.Claims that ProcessWire 3.x provides $page->isAutosave() or a template flag identifying repeater items, and that a core queue module with php index.php queue exists, appear in my planning notes but I cannot confirm them against current documentation. Do not build on them blindly. Instead, run a diagnostic hook first:
// /site/ready.php — temporary diagnostic only
$this->addHookAfter('Pages::saved', function(HookEvent $event) {
$page = $event->arguments(0);
$this->log->save('save-debug',
"id={$page->id} template={$page->template->name} " .
"parent={$page->parent->template->name} process=" . $this->process .
" changes=" . implode(',', array_keys($page->getChanges(true)))
);
});Then perform a normal edit, an autosave, a repeater edit, and a bulk action, and inspect Setup > Logs > save-debug. The log tells you empirically how each operation presents — which process, which template, which changed fields — and that becomes your filter. Repeater items, for example, typically appear as pages under a hidden admin parent with their own system template, which a template whitelist excludes automatically.
Pages::saved plus a strict template whitelist and a field whitelist from getChanges(true) covers most needs. Pages::published is a cleaner signal if you only care about go-live events; hook trash separately if needed.WireCache key like alert-{$page->id} with a few minutes' TTL is enough for single-editor workflows. If several editors touch the same page concurrently, add the user ID to the key — otherwise one editor's alert suppresses another's within the TTL window.LazyCron hook; third-party queue modules exist but verify them yourself rather than trusting my notes.One detail that would change this advice: how are your bulk edits performed — through the admin lister, or a custom API script? Admin-based bulk actions can be excluded via the $this->process gate; API scripts bypass it entirely and need their own opt-out flag.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.