# System Event Hooks

https://dev.wisecp.com/es/system-event-hooks

The ten hooks over the installation itself: add-ons, announcements, imports, tasks, versions, the site map and certificates.

## Overview

These hooks watch **the installation itself** rather than a customer: which add-on was installed, which announcement went out, which transfer finished, whether a new version appeared.

Three of them face outward: the site map towards search engines, the certificate sweep towards your alerting, and the transfer page towards the parties looking at it.

## Reference

### Following an add-on being installed

actionaddon.installed

`AdminModules` after install

Runs after an add-on package is installed. Being installed does not mean it is switched on.

Parameters 2

$modulestringThe key of the installed add-on.

$activatedboolWhether it was **switched on** during the install. A false means it sits on disk but does not run.

Return 1

voidThe return is ignored.

Listener PHP

```php
Hook::add('action:addon.installed', 10, function ($module, $activated) {
    // Installed does not mean switched on.
    if ($activated) Acme::onEnabled($module);
});
```

### Following an add-on status change

actionaddon.status_changed

`AdminModules` one of two values

Runs when an add-on is switched on or off.

Parameters 2

$keystringThe key of the add-on.

$statusstringThe new state: `enable` or `disable`.

Return 1

voidThe return is ignored.

Listener PHP

```php
Hook::add('action:addon.status_changed', 10, function ($key, $status) {
    if ($status === 'disable') Acme::pauseIntegration($key);
});
```

### Following an add-on being deleted

actionaddon.deleted

`AdminModules` after deletion

Runs after an add-on is removed.

Parameters 1

$modulestringThe key of the removed add-on.

Return 1

voidThe return is ignored.

Listener PHP

```php
Hook::add('action:addon.deleted', 10, function ($module) {
    Acme::cleanupIntegration($module);
});
```

### Following an announcement being saved

actionannouncement.saved

`AdminAnnouncements` create and edit

Runs after an announcement is saved.

Parameters 3

$savedIdintThe id of the announcement.

$dataarrayThe saved data: title, message, type, target country and language, product group, server, date range and status.

$isNewboolTrue when newly added, false when updated.

Return 1

voidThe return is ignored.

Listener PHP

```php
Hook::add('action:announcement.saved', 10, function ($savedId, $data, $isNew) {
    // Carry only a new announcement to the outside channel.
    if ($isNew) Acme::broadcast($data['title'] ?? '', $data['message'] ?? '');
});
```

### Following an import finishing

actionimport.completed

`Imports` per data type

Runs when a transfer from another system finishes. It fires **per data type**: customers, products and invoices each finish separately.

Parameters 3

$platformstringThe platform data came from.

$typestringThe type of data transferred.

$resultarrayWhat the transfer produced: progress, counters and status.

Return 1

voidThe return is ignored.

Listener PHP

```php
Hook::add('action:import.completed', 10, function ($platform, $type, $result) {
    // It fires per type: this does not mean "everything is done".
    Acme::noteImport($platform, $type, $result);
});
```

### Following a task being saved

actiontask.saved

`AdminTasks` create and edit

Runs when a task inside the panel is saved.

Parameters 2

$idintThe id of the task.

$is_newboolTrue when it was newly created.

Return 1

voidThe return is ignored.

Listener PHP

```php
Hook::add('action:task.saved', 10, function ($id, $is_new) {
    if ($is_new) Acme::mirrorTask($id);
});
```

### Following a new version being spotted

actionupdates.new_version_detected

`Updates` notice only

Runs when a new core version is spotted. **Nothing is upgraded**: this is only news.

Parameters 2

$responsearrayWhat the new version carries: its number, type and change list.

$current_versionstringThe version currently installed.

Return 1

voidThe return is ignored.

Listener PHP

```php
Hook::add('action:updates.new_version_detected', 10, function ($response, $current_version) {
    // Nothing is upgraded here, it is only reported.
    Acme::notifyOps('new version: ' . ($response['version'] ?? '?'));
});
```

### Adding addresses to the site map

filtersitemap.links

`Sitemap` per language

Runs while the site map is produced. Announce your own pages to search engines here.

Parameters 2

$linksarrayby linkThe list of full addresses. Add or remove freely. Empty entries and repeats are cleaned as the output is made; the order holds.

$ctxarrayby linkContext: the language of this map and the address keys the **active theme does not serve**. The hook runs once per language: build your address for that language.

Return 1

voidThe return is ignored; you add to the list.

Listener PHP

```php
Hook::add('filter:sitemap.links', 10, function (&$links, &$ctx) {
    // The hook runs once per language.
    foreach (Acme::publicPages($ctx['lang'] ?? '') as $url) $links[] = $url;
});
```

### Reporting certificates about to expire

filterssl.expiring_services

`cronjobs` returns a contribution

Runs while certificates nearing their end are collected. Add certificates the core does not know about here.

Parameters 1

$maxDaysintThe warning window: how many days ahead to report.

Return 1

array|nullYou return your own **contribution**: the services nearing their end, each with the days left. The core merges every return, so give your share rather than the whole list.

Listener PHP

```php
Hook::add('filter:ssl.expiring_services', 10, function ($maxDays) {
    // Return only YOUR share: the core merges them all.
    return Acme::expiringCerts($maxDays);
});
```

### Enriching the transfer verification page

filterlicense.transfer.verify_context

`LicenseTransfer` passed by link

Runs while the licence transfer verification page is shown. Add information of your own here.

Parameters 1

$ctxarrayby linkThe page context: the transfer state and record, the service, and the parties handing over and receiving.

Return 1

voidThe return is ignored; you write over the context.

Listener PHP

```php
Hook::add('filter:license.transfer.verify_context', 10, function (&$ctx) {
    $ctx['acme_note'] = Acme::transferNote((int) ($ctx['transfer']['id'] ?? 0));
});
```

## Pitfalls

> **An import finishes per data type**
> 
> The import event fires **separately for each type**: customers finish, then products, then invoices. Reading one call as "the whole import is done" starts work on half the data.

> **The certificate hook wants a contribution, not a list**
> 
> In the expiry sweep you return your own **share**. The core merges every return, so handing back the whole list duplicates records.

## Related Articles

- [How Hooks Work](https://dev.wisecp.com/en/how-hooks-work)
- [Hook Domains](https://dev.wisecp.com/en/hook-domains)
- [Writing a Hook Listener](https://dev.wisecp.com/en/writing-a-hook-listener)
