Page::save() Hook Execution and Atomic Persistence Limits
0 reputation · 03 Jun 2023, 21:56 UTC
0 reputation · 03 Jun 2023, 21:56 UTC
In ProcessWire 3.x, the Page::save() method is used to persist page fields and metadata to the database. This process is designed to be atomic, returning the saved object or false upon failure, and triggers the saved hook after the database transaction is complete.
When designing integration tests using a local test database to avoid production credentials, it is necessary to understand the relationship between the persistence layer and hook invocation. Specifically, there is a need to determine if the saved hook execution is tied to the success of the atomic transaction or if it can be triggered independently during specific failure states.
saved hook fire if the database transaction fails during the Page::save() process?$options parameters that can suppress hook execution while still persisting data to the database?32275 reputation · 04 Jun 2023, 06:15 UTC
saved hook fire on a failed transaction?In ProcessWire 3.x the Page::save() method wraps its database writes in a single transaction. The saved hook is only invoked after that transaction has been committed successfully. If the transaction rolls back—whether due to a database error, a validation failure, or any exception—the hook is never called. This guarantees that hooks that rely on a persisted state do not run when the state is incomplete.
The Page::save() method accepts an $options array. Setting ['nohooks' => true] disables *all* hooks for that call, including saved, savedFields, and any custom hooks that might be attached to the page. The database write still occurs; only the hook callbacks are skipped.
If you need to suppress only the saved hook but leave other hooks active, ProcessWire does not provide a built‑in flag. The usual workaround is to temporarily detach the hook before the save and reattach it afterward:
// Temporarily detach the 'saved' hook
$hooks = $wire->hooks;
$hooks->detach('saved', $myCallback);
// Perform the save with hooks still enabled
$page->save();
// Reattach the hook for future saves
$hooks->attach('saved', $myCallback);
saved hook fires:
$wire->hooks->add('saved', function($page) {
file_put_contents('/tmp/pw_saved.log', "Saved: {$page->id}\n", FILE_APPEND);
});
$page->save(['nohooks' => true]);
Confirm the page exists in the database but the log file remains empty.nohooks and confirm that the log entry appears.nohooks flag suppresses every hook; use it only when you are certain that no other hooks should run.saved hook after a rollback is possible, but that is outside the default ProcessWire flow.Do you have any custom hooks that might be manually invoked after a rollback? If so, they could still fire even when the transaction fails.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.