Events: changing data, output and arguments
A handler does not only observe: it receives the values of the original call by reference and can change them. This is how an extension adds a block to someone else's page or corrects data before it is saved — without touching the core file.
What the handler receives
| Trigger kind | before | after |
|---|---|---|
controller, model | &$route, &$args | &$route, &$args, &$output |
view | &$route, &$data | &$route, &$data, &$output |
$args is the array of arguments of the original method, $data is the data array of the template, $output is the result: the return value of a model method or ready HTML. The ampersand means the value is passed by reference — a change made in the handler is seen by the engine.
All handlers of this lesson are methods of extension/acme_hello/catalog/controller/module/acme_hello.php. Each is registered in install() with its own code and trigger, as in the previous lesson.
Changing template data
// trigger: catalog/view/product/product/before
public function productData(string &$route, array &$data): void
{
$data['heading_title'] .= ' — ' . $this->config->get('module_acme_hello_text');
}Open a product page — the heading of the product is followed by the greeting text from the module settings. The handler changed a variable before the template was rendered.
Changing the output
A new variable is useless if the core template does not print it. Then the ready HTML is changed:
// trigger: catalog/view/product/product/after
public function productOutput(string &$route, array &$data, string &$output): void
{
$note = '<p class="acme-note">' . $this->config->get('module_acme_hello_text') . '</p>';
$output = str_replace('</h1>', '</h1>' . $note, $output);
}On the product page a paragraph with the text appears right under the heading.
Changing arguments
// trigger: admin/model/catalog/product.addProduct/before
public function normalizeSku(string &$route, array &$args): void
{
$args[0]['sku'] = strtoupper(trim($args[0]['sku'] ?? ''));
}$args[0] is the first argument of addProduct() — the array with the product form. Add a product in the admin panel with the SKU mug-001 — it is saved as MUG-001. This trigger belongs to the admin application, so the handler must be in an admin controller of the extension.
Changing the result
In an after handler of a model $output is what the method returned:
// trigger: catalog/model/catalog/product.getProduct/after
public function productResult(string &$route, array &$args, mixed &$output): void
{
if ($output) {
$output['name'] = trim($output['name']);
}
}Cancelling the original call
If a before handler returns a value, the original method is not executed and the returned value becomes the result. This replaces a core method completely — and breaks other extensions subscribed to the same call, so it is a last resort.
Common mistake
Insertion through str_replace() depends on the markup of the theme. The shop switches to another theme where the heading is written differently — and the block silently disappears. Search for stable fragments, and after the replacement compare the string with the original: if nothing changed, write a line to the log.