# Panel Screen Data Hooks

https://dev.wisecp.com/es/admin-screen-data-hooks

The thirteen hooks over what the customer, service and tool screens show.

## Overview

The hooks that change what panel screens show live here: the customer detail and list, the service management cards, add-on buttons, critical notifications and the theme version lookup.

Two differ from the rest: the profile tabs and the security accordion hand you a **component object** rather than an array, and you add through a method call.

## Reference

### Changing the customer extra details

filteradmin.client_detail.info

`admin/users` passed by link

Runs once the extra detail fields on a customer page are read.

Parameters 2

$client_infoarrayby linkThe extra detail pairs. You may overwrite an existing key or add a new one.

$user_idintThe customer id.

Return 1

voidThe return is ignored; you write over the data.

Listener PHP

```php
Hook::add('filter:admin.client_detail.info', 10, function (&$client_info, $user_id) {
    $client_info['acme_tier'] = Acme::tierOf($user_id);
});
```

### Adding a sub-tab to a customer profile

filteradmin.client_detail.profile_subtabs

`admin/users` a component object

Runs while the vertical tabs of a customer profile are built. Add a tab of your own here.

Parameters 3

$profileTabobjectby linkThe tab component. It is an **object**, not an array: you add a tab by calling its add method, not by appending to a list.

$userarrayThe active customer record.

$user_idintThe customer id.

Return 1

voidThe return is ignored; the change happens through the object’s method.

Listener PHP

```php
Hook::add('filter:admin.client_detail.profile_subtabs', 10,
    function (&$profileTab, $user, $user_id) {
        // An object, not an array: call its method.
        $profileTab->add('acme', 'Acme', Acme::renderPanel($user_id));
    });
```

### Adding a section to the security area

filteradmin.client_detail.security_accordion

`admin/users` a component object

Runs while the security settings accordion of a customer is built.

Parameters 3

$secAccordionobjectby linkThe accordion component; add a section through its add method.

$client_infoarrayThe extra details of the customer.

$user_idintThe customer id.

Return 1

voidThe return is ignored; the change happens through the object.

Listener PHP

```php
Hook::add('filter:admin.client_detail.security_accordion', 10,
    function (&$secAccordion, $client_info, $user_id) {
        $secAccordion->add('acme-sessions', 'Acme sessions', Acme::sessions($user_id));
    });
```

### Changing the customer statistics

filteradmin.client_detail.statistics

`admin/users` passed by link

Runs once the counters on a customer page are worked out.

Parameters 2

$user_statsarrayby linkThe statistics: active and inactive services, invoices and tickets.

$user_idintThe customer id.

Return 1

voidThe return is ignored; you write over the data.

Listener PHP

```php
Hook::add('filter:admin.client_detail.statistics', 10, function (&$user_stats, $user_id) {
    $user_stats['acme_open_cases'] = Acme::openCases($user_id);
});
```

### Changing the customer list filters

filteradmin.client_list.filters

`admin/users` the model must support it

Runs once the filter criteria of the customer list are built.

Parameters 1

$dynamic_filterarrayby linkThe filter criteria: group, status, language, country, address and date. ? A key you add **must also be handled in the listing query**; otherwise the filter appears but narrows nothing.

Return 1

voidThe return is ignored; you write over the data.

Listener PHP

```php
Hook::add('filter:admin.client_list.filters', 10, function (&$dynamic_filter) {
    // A new key must be handled in the listing query too.
    $dynamic_filter['acme_tier'] = Acme::tierFilterValue();
});
```

### Changing the service management cards

filteradmin.service_detail.management_cards

`admin/services` two lists together

Runs once the management cards on a service detail are prepared. Add a card of your own, hide one, or change the order.

Parameters 1

$contextarrayby linkTwo lists together: `cards` holds the card content and `layout` says which card sits in which column and in what order. ? **Update both**: a card missing from the layout never appears, and a layout key with no card is quietly skipped.

Return 1

voidThe return is ignored; you write over the context.

Listener PHP

```php
Hook::add('filter:admin.service_detail.management_cards', 10, function (&$context) {
    // Update BOTH: the card and the layout.
    $context['cards']['acme'] = Acme::renderCard($context['service'] ?? []);
    $context['layout']['right'][] = 'acme';
});
```

### Changing the add-on settings buttons

filteradmin.addon_configure.buttons

`admin/tools` emptying removes them all

Runs once the buttons on an add-on settings page are prepared.

Parameters 1

$buttonsarrayby linkThe button map; each carries its text, class, icon and click action. Empty the array entirely and **no button appears**.

Return 1

voidThe return is ignored; you write over the data.

Listener PHP

```php
Hook::add('filter:admin.addon_configure.buttons', 10, function (&$buttons) {
    // Emptying it entirely leaves no buttons at all.
    $buttons['acme-sync'] = [
        'text'    => 'Sync Acme',
        'class'   => 'btn btn-outline-primary',
        'icon'    => 'bi bi-arrow-repeat',
        'onclick' => 'acmeSync()',
    ];
});
```

### Changing the address of an uploaded image

filteradmin.editor_upload_url

`admin/tools` passed by link

Runs after the address of an image uploaded into the editor is produced. This is how you move images onto a delivery network.

Parameters 2

$urlstringby linkThe address produced. Leave it alone and the local one stays.

$file_pathstringThe full path of the file on the server.

Return 1

voidThe return is ignored; you write over the data.

Listener PHP

```php
Hook::add('filter:admin.editor_upload_url', 10, function (&$url, $file_path) {
    $url = Acme::pushToCdn($file_path) ?: $url;
});
```

### Following an image upload

actionadmin.editor_image_uploaded

`admin/tools` address after the filter

Runs after an image is uploaded into the editor.

Parameters 2

$file_pathstringThe full path of the file on the server.

$urlstringThe final address, **as it stands after the address filter** ran.

Return 1

voidThe return is ignored.

Listener PHP

```php
Hook::add('action:admin.editor_image_uploaded', 10, function ($file_path, $url) {
    // The address is the one AFTER the filter ran.
    Acme::noteAsset($file_path, $url);
});
```

### Adding to the critical notification list

filteradmin.notifications.critical

`admin/inc` fixed item shape

Runs once the critical notification list in the panel header is prepared.

Parameters 1

$critical_transaction_notificationsarrayby linkThe notification items. Each must carry the fields the template expects: id, icon, type, message, date, read state and buttons. An item missing one breaks the display.

Return 1

voidThe return is ignored; you write over the data.

Listener PHP

```php
Hook::add('filter:admin.notifications.critical', 10, function (&$critical_transaction_notifications) {
    // Fill every field the template expects.
    foreach (Acme::criticalAlerts() as $a) $critical_transaction_notifications[] = $a;
});
```

### Following a panel notification

actionadmin.notified

`Notification` zero means not written

Runs when a system notification lands in the panel.

Parameters 4

$namestringThe event name.

$dataarrayThe event data: message placeholders and what is used to spot repeats.

$levelstringThe level: error, warning, information or success.

$event_idintThe id of the record created. **A zero means nothing was written**: either the same notice already existed or the write failed. Test before using the id.

Return 1

voidThe return is ignored.

Listener PHP

```php
Hook::add('action:admin.notified', 10, function ($name, $data, $level, $event_id) {
    // Zero means nothing was written.
    if ($level === 'error' && $event_id) Acme::page($name, $data);
});
```

### Taking over the theme version lookup

filteradmin.theme_version_check

`admin/settings` first filled wins

Runs before a theme is asked about a new version. Return an answer and **no remote call is made**.

Parameters 2

$keystringThe theme folder key.

$manifestarrayThe theme manifest: its update address and installed version.

Return 1

string|null**A filled text is taken as the raw response** and the call is skipped. The **first** filled return by priority wins and the rest never run. With an empty return the core makes its usual request.

Listener PHP

```php
Hook::add('filter:admin.theme_version_check', 10, function ($key, $manifest) {
    // A filled return means NO remote call is made.
    if (!str_starts_with($key, 'Acme')) return null;

    return Acme::versionJson($key);
});
```

### Adjusting the theme version response

filteradmin.theme_version_response

`admin/settings` the raw response

Runs after the version response arrives and before it is decoded. Its sibling picks the source; this hook **adjusts what came back**.

Parameters 2

$keystringby linkThe theme key. It is passed by link but already **consumed**: changing it has no effect.

$manifestarrayby linkThe theme manifest, also consumed.

Return 1

voidThe return is ignored; you write over the raw response. The core then decodes it; with no version field the result counts as empty.

Listener PHP

```php
Hook::add('filter:admin.theme_version_response', 10, function (&$key, &$manifest) {
    // Both parameters are consumed: changing them has no effect.
    Acme::noteVersionCheck($key);
});
```

## Pitfalls

> **Adding a card takes two lists**
> 
> In the service management cards the content sits in one list and the **layout in another**. Add only the content and the card never appears; write only a name into the layout and that name is quietly skipped. Update both.

> **The tabs and the accordion are objects, not arrays**
> 
> The profile sub-tabs and the security accordion hand you a **component object**. A listener treating it like an array fails; you add through the object’s own method.

## Related Articles

- [Management Panel Hooks](https://dev.wisecp.com/en/hooks-in-the-management-panel)
- [Customer Account Hooks](https://dev.wisecp.com/en/customer-account-hooks)
- [How Hooks Work](https://dev.wisecp.com/en/how-hooks-work)
