Events and Hooks
QUIQQER packages use events to react to framework actions and to extension points provided by other packages.
Use events.xml when a package should run PHP code after a setup step, during a request, when a business object changes, or when another package exposes an extension point.
events.xml
Create events.xml in the package root and add one <event> entry per listener.
<?xml version="1.0" encoding="UTF-8"?>
<events>
<event on="eventName" fire="\Vendor\Package\EventHandler::method"/>
</events>The on attribute contains the event name. The fire attribute contains the static PHP method that should be called.
Real package shape:
<?xml version="1.0" encoding="UTF-8"?>
<events>
<event on="onSiteSave" fire="\QUI\Bricks\Events::onSiteSave"/>
<event on="onSmartyInit" fire="\QUI\Bricks\Events::onSmartyInit"/>
<event on="onPackageSetup" fire="\QUI\Bricks\Events::onPackageSetup"/>
</events>Listener Classes
Event listener methods are usually grouped in an EventHandler or EventHandling class inside the package namespace.
<?php
namespace Vendor\Package;
use QUI;
class EventHandler
{
public static function onPackageSetup(QUI\Package\Package $Package): void
{
if ($Package->getName() !== 'vendor/package') {
return;
}
// Run package setup logic here.
}
}The method signature must match the event that is fired. Check existing event usage before adding a listener because parameters differ between events.
Multiple Listeners
A package can register more than one listener for the same event. This is useful when different setup routines should stay separated.
<events>
<event on="onPackageSetup" fire="\Vendor\Package\EventHandler::onPackageSetup"/>
<event on="onPackageSetup" fire="\Vendor\Package\EventHandler::onOtherPackageSetup"/>
</events>In the listener, guard against unrelated packages or contexts:
if ($Package->getName() !== 'vendor/package') {
return;
}This pattern is common for setup events because setup can run for different packages.
Priority
Use priority only when the order between listeners matters.
<event on="eventName"
fire="\Vendor\Package\EventHandler::method"
priority="20"
/>If no priority is set, QUIQQER uses the default priority. Most package listeners should not need a custom priority.
Common Event Types
Current packages use events for different extension scenarios:
onPackageSetupfor setup-time initialization and data preparation.onRequestfor request-specific behavior.- site and rendering events such as
onSiteSave,onSmartyInit, andonOutputParseEndfor content and template integration. - package-specific events for domain workflows.
- template and frontend extension points such as
onQuiqqer::template::header::end. - migration events such as
onQuiqqerMigrationV2for version-specific migration behavior.
Naming
Use the event name that is already provided by the framework or by the package you integrate with. Do not invent a new event name unless your package also fires that event and documents its parameters.
Package-specific event names should be explicit and namespaced enough to avoid collisions. Current packages use both classic names such as onTransactionCreate and namespaced names such as onQuiqqer::template::header::end.
Error Handling
Listener code runs as part of the operation that fires the event. Keep listeners small and predictable:
- return early when the listener does not apply to the current context.
- catch expected exceptions when the event should not abort the whole workflow.
- log exceptions that need later inspection.
- avoid expensive work in request-level events unless it is strictly necessary.
Event Names
Event names in events.xml usually start with on, for example onPackageSetup.
When events are fired in PHP, QUIQQER also accepts names without the on prefix. The event dispatcher normalizes packageSetup to onPackageSetup. Use the on... form in events.xml.
Common Core Events
The following events are general platform events that packages can subscribe to. Parameter names describe the values passed to the listener method.
This reference covers global events fired through QUI::getEvents(). Some objects also expose local event dispatchers for object-internal hooks; those are not part of the global package event reference.
Parameters marked with & are passed by reference and can be changed by listeners.
The reference is checked against current global event calls. Older wiki entries are not listed as Core events unless the current runtime fires them. For example, onLogWrite is registered by the optional quiqqer/log package and is not a Core event in the checked source.
System Events
| Event | Triggered when | Parameters |
|---|---|---|
onQuiqqerInit | after the central QUIQQER runtime initialization finished | none |
onFireEvent | before another event is dispatched by the global event manager | string $eventName, array $params |
onHeaderLoaded | after the runtime header was loaded | none |
onIconsInit | when the icon handler is initialized | icon handler object |
onHtaccessGenerate | when .htaccess content is generated | string &$htaccessContent |
onPermissionsSet | when permissions are assigned to a supported permission object | permission object, permissions array |
onQuiqqerSessionStorageInit | before Symfony session storage is initialized | QUI\Session $Session, array &$storageOptions |
onFireEvent is useful for diagnostics and generic event coordination. Avoid heavy work in this listener because it runs before every global event dispatch.
Setup Events
| Event | Triggered when | Parameters |
|---|---|---|
onSetupAllBegin | when the full setup process starts | none |
onSetupAllEnd | when the full setup process ends | setup output object |
onSetupMakeDirectoriesBegin | before setup creates required runtime directories | none |
onSetupMakeDirectoriesEnd | after setup created required runtime directories | none |
onSetupMainSystemBegin | before setup prepares permissions, groups, users, workspaces and login defaults | none |
onSetupMainSystemEnd | after setup prepared the main system data | none |
onSetupCommunicationBegin | before setup prepares mail, messages, editor and events | none |
onSetupCommunicationEnd | after setup prepared communication-related systems | none |
onSetupMakeHeaderFilesBegin | before setup writes runtime header files | none |
onSetupMakeHeaderFilesEnd | after setup wrote runtime header files | none |
onSetupPackageSetupBegin | before setup executes package setup for installed packages | none |
onSetupPackageSetupEnd | after setup executed package setup for installed packages | none |
Package And Setup Events
| Event | Triggered when | Parameters |
|---|---|---|
onPackageInstallBefore | before a package import/install starts | QUI\Package\Package $Package |
onPackageInstall | after events.xml was imported during package install | QUI\Package\Package $Package |
onPackageInstallAfter | after package install and optional setup finished | QUI\Package\Package $Package |
onPackageConfigSave | after package configuration values were saved through the settings XML workflow | QUI\Package\Package $Package, array $params |
onPackageSetupBegin | before a package setup imports metadata, permissions, events, database XML, locale and settings | QUI\Package\Package $Package |
onPackageSetup | during package setup after XML imports and settings processing | QUI\Package\Package $Package |
onPackageSetupEnd | after package setup finished | QUI\Package\Package $Package |
onPackageUnInstall | when a package is uninstalled | string $packageName |
onPackageDestroy | when a package is destroyed/removed | string $packageName |
onPackageUpdate | when a package update is executed | QUI\Package\Package $Package |
onUpdateBegin | when a system/package update run starts | none |
onUpdateEnd | when a system/package update run ends | none |
onQuiqqerMigrationV2 | when the v2 migration console tool runs | QUI\System\Console\Tools\MigrationV2 $Tool |
Package-specific variants also exist for package lifecycle events. They append the package name to the event, for example onPackageSetup-quiqqer/bricks. The package-specific variants use the same parameters as the base lifecycle event.
Request And Output Events
| Event | Triggered when | Parameters |
|---|---|---|
onRequest | during URL/request rewrite handling | QUI\Rewrite $Rewrite, string $url |
onRequestImageNotFound | when a requested image/cache URL cannot be resolved | string $url |
onRequestOutput | when the administration preview output has been parsed and can be changed | string &$content |
onRewriteOutputBegin | before rewrite output is parsed | array $eventData with Rewrite and output |
onRewriteOutput | after rewrite output was parsed and assigned to the rewrite object | array $eventData with Rewrite and output |
onQUI::rewriteOutput | after parsed output was assigned to the rewrite object | array $eventData with Rewrite |
onOutputParseBegin | before QUI\Output parses content | string &$content |
onOutputParseEnd | after QUI\Output parsed content | string &$content |
onErrorHeaderShowBefore | before an error/redirect header is shown | int $code, string $url |
onErrorHeaderShowAfter | after an error/redirect header is shown | int $code, string $url |
Template Events
| Event | Triggered when | Parameters |
|---|---|---|
onTemplateSiteFetch | when a template fetches/renders a site | QUI\Template $Template, QUI\Interfaces\Projects\Site $Site |
onTemplateGetSiteTitle | when the template builds a site title | QUI\Template $Template, QUI\Interfaces\Projects\Site $Site |
onTemplateGetHeader | when the template builds the document header | QUI\Template $Template |
onSmartyInit | when Smarty is initialized by packages/templates that expose the event | Smarty $Smarty |
Project And Site Events
| Event | Triggered when | Parameters |
|---|---|---|
onCreateProject | after a project was created | QUI\Projects\Project $Project |
onDeleteProject | after a project was deleted | string $projectName |
onProjectConfigSave | after project configuration was saved | string $projectName, array $config, array $params |
onProjectRenamed | after a project was renamed | event data array |
onProjectSetupBegin | before project setup starts | QUI\Projects\Project $Project |
onProjectSetupEnd | after project setup ends | QUI\Projects\Project $Project |
onSiteInit | when a site object is initialized | QUI\Interfaces\Projects\Site $Site |
onSiteLoad | when a site is loaded | QUI\Interfaces\Projects\Site $Site |
onSiteCheckActivate | before a site activation is executed | QUI\Projects\Site\Edit $Site |
onSiteCheckDeactivate | before a site deactivation is executed | QUI\Projects\Site\Edit $Site |
onSiteSaveBefore | before an editable site is saved | QUI\Projects\Site\Edit $Site |
onSiteSave | after an editable site was saved | QUI\Projects\Site\Edit $Site |
onSiteSaveAjaxBegin | before the backend site-save AJAX handler applies submitted attributes | QUI\Projects\Site\Edit $Site |
onSiteSaveAjaxEnd | after the backend site-save AJAX handler saved and refreshed the site | QUI\Projects\Site\Edit $Site |
onSiteDeleteBefore | before a site delete operation starts | int $siteId, QUI\Projects\Project $Project |
onSiteDelete | when a site is deleted | `int |
onSiteDestroy | when an editable site is destroyed and package-owned site data can be removed | QUI\Projects\Site\Edit $Site |
onSiteActivate | when a site is activated | QUI\Projects\Site\Edit $Site |
onSiteDeactivate | when a site is deactivated | QUI\Projects\Site\Edit $Site |
onSiteMoveBefore | before a site is moved | QUI\Projects\Site\Edit $Site, int $oldParentId |
onSiteMove | after a site was moved | QUI\Projects\Site\Edit $Site, int $parentId |
onSiteCreateChild | after a child site was created | int $newId, QUI\Projects\Site\Edit $Parent |
onSiteCreateChildEnd | after the backend child-site creation AJAX handler saved the new child | QUI\Projects\Site\Edit $Child |
onSiteGetUrlRewritten | when the rewritten site URL is built | QUI\Interfaces\Projects\Site $Site, mixed &$eventResult |
Media Events
| Event | Triggered when | Parameters |
|---|---|---|
onMediaSaveBegin | before a media item is saved | QUI\Projects\Media\Item $Item |
onMediaSave | after a media item was saved | QUI\Projects\Media\Item $Item |
onMediaReplace | when a media file is replaced | QUI\Projects\Media $Media, QUI\Projects\Media\File $File |
onMediaActivate | when a media item/folder is activated | media item/folder object |
onMediaDeactivate | when a media item/folder is deactivated | media item/folder object |
onMediaDeleteBegin | before a media item/folder is deleted | media item/folder object |
onMediaDelete | after a media item/folder was deleted | media item/folder object |
onMediaDestroy | when a media item/folder is destroyed | media item/folder object |
onMediaRename | when a media item/folder is renamed | media item/folder object |
onMediaCreateSizeCache | when an image size/cache variant is created | QUI\Projects\Media\Image $ImageItem, image object |
onMediaCreateImageHtmlBegin | before media image HTML is created | event data array |
onMediaCreateImageHtml | after media image HTML data was prepared | array &$picture |
User And Group Events
| Event | Triggered when | Parameters |
|---|---|---|
onUserCreate | after a user was created | QUI\Users\User $User |
onUserGet | when a user cannot be loaded normally and packages may provide a user object | `int |
onUserGetBySession | when the current session user is resolved and packages may provide a user object | none |
onUserGetAvatar | when a user's avatar image is requested and packages may provide an image | QUI\Users\User $User |
onUserLoad | when a user object is loaded | QUI\Users\User $User |
onUserSaveBegin | before a user is saved | QUI\Users\User $User |
onUserSave | during user save before database write | QUI\Users\User $User |
onUserSaveEnd | after a user was saved | QUI\Users\User $User |
onUserLoginAjaxStart | when the backend login AJAX handler starts | none |
onUserLoginStart | when login starts and the user id is known or guessed | `string |
onUserAuthenticatorLoginStart | before an authenticator starts authentication | `string |
onUserLogin | after a user successfully logged in | QUI\Users\User $User |
onUserLoginError | when login fails | `string |
onUserCliLogin | after successful console login | QUI\Users\User $User |
onUserCliLoginError | when console login fails | username, optional exception |
onUserLogoutBegin | before a user logs out | QUI\Users\User $User |
onUserLogout | after a user logged out | QUI\Users\User $User |
onUserChangePasswordBefore | before a user changes their own password | QUI\Users\User $User, string $newPassword, string $oldPassword |
onUserChangePassword | after a user changed their own password | QUI\Users\User $User, string $newPassword, string $oldPassword |
onUserSetPassword | after a user's password was changed | QUI\Users\User $User |
onUserActivateBegin | before user activation | QUI\Users\User $User, string $code, permission user |
onUserActivate | after user activation | QUI\Users\User $User, permission user |
onUserDeactivate | when a user is deactivated | QUI\Users\User $User |
onUserDisable | when a user is disabled | QUI\Users\User $User |
onUserDelete | before a user is deleted | QUI\Users\User $User |
onUserExtraAttributes | when user extra attributes are collected | QUI\Users\User $User, array &$attributes |
onUserAddressInitData | when user address database data is loaded before it is assigned to the address object | address object, array &$data |
onUserAddressSaveBegin | before a user address is saved | address object, user object |
onUserAddressSaveBefore | before address database data is written | address object, user object, array &$dbData |
onUserAddressSave | after a user address was saved | address object, user object |
onGroupCreate | after a group was created | QUI\Groups\Group $Group |
onGroupLoad | when a group object is loaded | QUI\Groups\Group $Group |
onGroupSaveBegin | before a group is saved | QUI\Groups\Group $Group |
onGroupSave | during group save | QUI\Groups\Group $Group |
onGroupSaveEnd | after a group was saved | QUI\Groups\Group $Group |
onGroupActivate | when a group is activated | QUI\Groups\Group $Group |
onGroupDeactivate | when a group is deactivated | QUI\Groups\Group $Group |
onGroupDelete | when a group is deleted | QUI\Groups\Group $Group |
onSetParent | when a group parent is changed | QUI\Groups\Group $Group, new parent group |
Administration, AJAX, Cache, And Mail Events
| Event | Triggered when | Parameters |
|---|---|---|
onAdminRequest | when the administration entry point handles a request | none |
onAdminLoadBegin | before the administration UI is rendered | none |
onAdminLoad | while the administration UI is rendered | none |
onAdminLoadFooter | when the administration footer is rendered | none |
onAdminLogin | when the administration login page is built | none |
onAdminLoginFooter | when the administration login footer is rendered | none |
onAjaxCallBefore | before an AJAX call is executed | event data array |
onAjaxCall | after an AJAX call was executed | event data array |
onAjaxResult | before an AJAX result is returned | mixed &$result |
onCacheClear | when a cache key is cleared | string $key |
onCacheClearAll | when all cache areas are cleared | none |
onCachePurge | when cache purge is executed | none |
onClearCompleteQuiqqerCache | when the complete QUIQQER cache area is cleared | none |
onClearSettingsCache | when settings cache is cleared | none |
onClearTemplateCache | when template cache is cleared | none |
onClearProjectsCache | when project cache is cleared | none |
onClearProjectCache | when one project cache is cleared | string $projectName |
onClearGroupsCache | when group cache is cleared | none |
onClearUsersCache | when user cache is cleared | none |
onClearPermissionsCache | when permissions cache is cleared | none |
onClearPackagesCache | when package cache is cleared | none |
onClearPackageCache | when one package cache is cleared | string $packageName |
onLongTimeCacheClear | when a long-term cache key is cleared | string $key |
onLongTimeCacheClearCompleteQuiqqerCache | when the complete QUIQQER long-term cache area is cleared | none |
onGetPhpMailerInitStart | before the mail manager initializes a PHPMailer instance | none |
onMailer | when a mailer object is initialized | mailer object |
onMailerSendInit | before mail send preparation | event data array or mailer/phpmailer objects |
onMailerSendBegin | before a prepared mail is sent | mailer object, PHPMailer object |
onMailerSend | after a mail was sent | mailer object, PHPMailer object |
onMailSendError | when direct mail sending fails | mailer object, PHPMailer object, exception |
onMailQueueSendError | when queued mail sending fails | queue object, PHPMailer object, exception |
onMailQueueError | when queued mail delivery failed and the queue entry remains failed | queue entry array |
onQuiqqerConsoleLicence | when the license console tool needs package-specific license output | string $packageName |
onQuiqqerConsoleLicenceList | when the license console tool builds the installed package license list | array &$data |
onMcpSiteUpdateAttributes | when MCP site updates build the allow-list of writable site attributes | array &$attributes, QUI\Projects\Site\Edit $Site |
Database Events
| Event | Triggered when | Parameters |
|---|---|---|
onDataBaseQueryCreate | before a database query is built from query parameters | database connection object |
onDataBaseQuery | after query SQL and prepare data were built, before execution | database connection object, query data array |
onDataBaseQueryEnd | after query execution finished or before a query error is reported | database connection object, query data array, start time, end time |
onDataBaseQueryError | when query execution raises a PDO exception | database connection object, PDO exception, query data array, start time, error time |
Package Events
Packages can define their own events. These events must be documented separately from Core events because they only exist when the package that fires them is installed.
Use a namespaced event name when the event belongs to one package or domain, for example onQuiqqer::template::header::end.
Current free package examples:
| Event | Package | Triggered when | Parameters |
|---|---|---|---|
onQuiqqerBricksCreate | quiqqer/bricks | after a brick record was created | int $brickId |
onQuiqqerBricksSaveBefore | quiqqer/bricks | before a brick is saved | `int |
onQuiqqerBricksSave | quiqqer/bricks | after a brick was saved and related caches were cleared | `int |
onQuiqqerBricksBrickDeleteBefore | quiqqer/bricks | before a brick is deleted | brick object |
onQuiqqerBricksBrickDeleteAfter | quiqqer/bricks | after a brick was deleted | int $brickId |
onBricksGetAreaByProject | quiqqer/bricks | when available brick areas for a project are collected | bricks manager, QUI\Projects\Project $Project, array &$bricks |
onQuiqqerBricksGetBricksByAreaBegin | quiqqer/bricks | before bricks for a site area are resolved | brick area, site object, array &$result |
onQuiqqerBricksGetBricksByAreaEnd | quiqqer/bricks | after bricks for a site area were resolved | brick area, site object, array &$result |
onQuiqqerMenuIndependentClear | quiqqer/menu | when an independent menu cache is cleared | menu id |
onQuiqqerMenuIndependentSave | quiqqer/menu | after an independent menu was saved | menu object |
onQuiqqerMenuIndependentCreate | quiqqer/menu | after an independent menu was created | menu object |
onQuiqqerMenuIndependentDelete | quiqqer/menu | after an independent menu was deleted | menu id |
onQuiqqerTranslatorPublish | quiqqer/translator | after translations were published and locale cache was refreshed | none |
onQuiqqerTranslatorUpdate | quiqqer/translator | after a translation value was updated in development mode | string $group, string $var, string $packageName, array $data |
onQuiqqerTranslatorEdit | quiqqer/translator | after a translation value was edited | string $group, string $var, string $packageName, array $data |
onQuiqqerTranslatorEditById | quiqqer/translator | after a translation value was edited by id | int $id, array $data |
Packages can also listen to package-specific events from other packages. For example, quiqqer/cache listens to Bricks, Frontend Users, Translator, and Menu events to invalidate caches when those packages change output-relevant data.
Document custom events in the package that fires them. At minimum, document:
- when the event is fired
- whether listeners can modify parameters by reference
- all parameters in order
- whether listener return values are used
Import Rules
When events.xml is imported:
- entries without
onare ignored - entries without
fireare ignored priorityis optional- default priority is
10 - imported listeners are registered in the QUIQQER event manager
