# Module Installation Hooks

https://dev.wisecp.com/es/module-installation-hooks

The nine hooks over installing, switching on, deleting and queueing modules.

## Overview

A module travels four steps: it is uploaded, switched on, switched off and deleted. Each step has a gate you can stop at in front of it and an event that reports it behind.

Two shapes differ. The switching hooks take a **list**, because the panel allows a multiple selection; the deletion hooks work with one module.

## Reference

### Stopping a module being switched on

gatemodule.activate

`AdminModules` a list arrives

Runs before one or more modules are switched on. The panel allows a multiple selection, so what arrives is a **list**.

Parameters 2

$groupstringThe module type: mail, text message, payment or product.

$modulesarrayThe keys being switched on in this request. It is an array even for one module; walk all of them.

Return 1

mixed**A filled return blocks it**: either a text or an array carrying a message, both accepted, and the message is shown to the user. An empty return lets it carry on.

Listener PHP

```php
Hook::add('gate:module.activate', 10, function ($group, $modules) {
    // It is an array even when one module was picked.
    foreach ($modules as $key)
        if (!Acme::licensed($group, $key)) return 'You hold no licence for this module: ' . $key;

    return null;
});
```

### Following modules being switched on

actionmodule.activated

`AdminModules` a list arrives

Runs after the modules are switched on.

Parameters 2

$groupstringThe module type.

$modulesarrayThe keys that were switched on.

Return 1

voidThe return is ignored.

Listener PHP

```php
Hook::add('action:module.activated', 10, function ($group, $modules) {
    foreach ($modules as $key) Acme::onModuleOn($group, $key);
});
```

### Following modules being switched off

actionmodule.deactivated

`AdminModules` a list arrives

Runs after modules are switched off. A payment or server module taken out of service can leave **live services** behind it.

Parameters 2

$groupstringThe module type.

$modulesarrayThe keys that were switched off.

Return 1

voidThe return is ignored.

Listener PHP

```php
Hook::add('action:module.deactivated', 10, function ($group, $modules) {
    // Live services may still sit behind a module now switched off.
    foreach ($modules as $key) Acme::warnOrphans($group, $key);
});
```

### Stopping a module being deleted

gatemodule.delete

`AdminModules` one module

Runs before a module is deleted along with its files. Unlike switching on, here there is **one** module.

Parameters 2

$typestringThe module type.

$keystringThe module key.

Return 1

string|null**A non-empty text blocks the operation** and is shown as the error. An empty return lets it carry on.

Listener PHP

```php
Hook::add('gate:module.delete', 10, function ($type, $key) {
    // Do not let a module go while services still sit on it.
    if (Acme::hasLiveServices($type, $key)) return 'Live services still run on this module.';

    return null;
});
```

### Following a module being deleted

actionmodule.deleted

`AdminModules` after deletion

Runs after a module is deleted. Its files are no longer on disk.

Parameters 2

$typestringThe type of the deleted module.

$keystringThe key of the deleted module.

Return 1

voidThe return is ignored.

Listener PHP

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

### Stopping an add-on upload

gatemodule.addon_install

`AdminModules` the uploaded file

Runs before an uploaded add-on package is opened. What you hold is the **raw file**, still in the temporary folder.

Parameters 2

$filearrayThe uploaded file: its name, temporary path and size. The file name **comes from the user**: do not trust it as it stands.

$activatedboolWhether it will be switched on right after the install.

Return 1

string|null**A non-empty text blocks the operation** and is shown as the error. An empty return lets it carry on.

Listener PHP

```php
Hook::add('gate:module.addon_install', 10, function ($file, $activated) {
    // The name comes from the user: look at the content, not the name.
    if (!Acme::signatureValid($file['tmp_name'] ?? '')) return 'The package signature did not verify.';

    return null;
});
```

### Stopping an add-on deletion

gatemodule.addon_delete

`AdminModules` before the write

Runs before an add-on is removed.

Parameters 1

$keystringThe key of the add-on to be removed.

Return 1

string|null**A non-empty text blocks the operation** and is shown as the error. An empty return lets it carry on.

Listener PHP

```php
Hook::add('gate:module.addon_delete', 10, function ($key) {
    if (Acme::isRequired($key)) return 'The installation needs this add-on to run.';

    return null;
});
```

### Changing the add-on list

filtermodule.addons_list

`AdminModules` passed by link

Runs once the list on the add-on page is prepared.

Parameters 1

$moduleListarrayby linkThe list in three groups: enabled, disabled and available to buy. Change it without breaking the shape: the template expects all three groups.

Return 1

voidThe return is ignored; you write over the list.

Listener PHP

```php
Hook::add('filter:module.addons_list', 10, function (&$moduleList) {
    // Keep the shape of the three groups.
    $moduleList['premium'] = Acme::filterOffers($moduleList['premium'] ?? []);
});
```

### Stopping an intervention in the queue

gatemodule.queue_intervene

`AdminModules` zero on a bulk action

Runs before an administrator steps into the module queue by hand: retrying, deleting, clearing and running now.

Parameters 2

$actionstringWhat kind of intervention it is.

$idintThe id of the target record. On a **bulk action it arrives as zero**: a rule written to inspect one record then inspects nothing.

Return 1

string|null**A non-empty text blocks the operation** and is shown as the error. An empty return lets it carry on.

Listener PHP

```php
Hook::add('gate:module.queue_intervene', 10, function ($action, $id) {
    // On a bulk action the id is ZERO: build no single-record assumption.
    if ($id === 0 && $action === 'delete') return 'Bulk deletion is closed.';

    return null;
});
```

## Pitfalls

> **The switching hooks receive a list**
> 
> Even for a single module the parameter is an **array**. A check that compares it directly catches nothing; walk the list.

> **A bulk queue action carries a zero**
> 
> When several records are handled at once the record id arrives as **zero**. A rule written to inspect one record then quietly inspects nothing.

## Related Articles

- Module Hooks
- [System Event Hooks](https://dev.wisecp.com/en/system-event-hooks)
- [How Hooks Work](https://dev.wisecp.com/en/how-hooks-work)
