# Customer Site Data and Gates

https://dev.wisecp.com/es/customer-site-data-and-gates

The customer site away from the screen. 41 filters change data, 10 gates stop an action, and 30 hooks report an event.

## Overview

Screen hooks add HTML. The hooks here touch the data deciding **what a page shows**, stop an action, or report what happened.

Telling the three apart decides where your work goes. Adding a row to a list is a filter. Stopping a spam comment is a gate. Telling an outside system is an event hook.

## Reference

### The ones that change data

The most used of the forty-one filters. Most hand the value over **by reference**, and the *Ref* column of an entry says which one you can change.

- **filter:client.page.output**: The finished output of a page — the widest place to step in. Changed in place by reference; the return is not used.
- **filter:client.menu**: The site menu tree. Changed by reference; the return is not used.
- **filter:client.breadcrumb**: The breadcrumb trail. Changed by reference; the return is not used.
- **filter:client.dashboard.panels**: The panels on the account dashboard. Changed by reference; the return is not used.
- **filter:client.dashboard.alerts**: The alert strips on the dashboard. Changed by reference; the return is not used.
- **filter:client.list.rows**: List rows — services, invoices, domains. Changed by reference; the return is not used.
- **filter:client.service_detail.data**: The data behind a service detail. Changed by reference; the return is not used.
- **filter:client.domain_detail.data**: The data behind a domain detail. Changed by reference; the return is not used.
- **filter:client.invoice_view_data**: The data behind an invoice view. Changed by reference; the return is not used.
- **filter:client.payment_methods**: The payment methods offered to the customer. Changed by reference; the return is not used.
- **filter:client.theme**: The theme in use. Changed by reference; the return is not used.
- **filter:client.routes**: The site routes. Changed by reference; the return is not used.

### The ones that stop

Ten gates. They share one contract: returning a non-empty string stops the action, and that text reaches the customer as the error.

- **gate:client.page_access**: Access to a page. A filled return cuts the request off; a listener that redirects must end the request itself.
- **gate:client.contact_submit**: Saving a contact form message. The first filled return vetoes the save.
- **gate:client.blog_comment**: Saving a blog comment. The first filled return vetoes the save.
- **gate:client.api_key_create**: The customer opening a new API key. A filled return stops it.

### The ones that report

Most of the thirty event hooks report what the customer did on their account. Opening a key, writing a comment, sending a form.

- **action:client.api_key_created**: The customer opened a new API key. The return is ignored.
- **action:client.api_key_revoked**: A key was revoked. The return is ignored.
- **action:client.blog_comment_added**: A blog comment was saved. The return is ignored.
- **action:client.data_prepared**: The page data is ready and drawing is about to start. The return is ignored; add data with `addData()`.

### The three contracts side by side

```php
// A FILTER: add your own panel to the dashboard (by reference)
Hook::add('filter:client.dashboard.panels', 10, function (&$panels) {
    $panels[] = ['title' => 'Acme', 'body' => AcmePanel::html()];
});

// A GATE: stop the comment where the spam score is high
Hook::add('gate:client.blog_comment', 10,
    function ($owner_id, $parent_id, $message) {
        if (Spam::score($message) > 80) return 'Your comment was not saved.';
        return null;
    });

// AN EVENT: write the opened key to the audit trail
Hook::add('action:client.api_key_created', 10, function ($owner_id, $new_id, $perms) {
    Audit::keyOpened($owner_id, $new_id, $perms);
});
```

## Pitfalls

> **The owner comes from the hook, not the session**
> 
> Most customer hooks hand you the **account id** in the first parameter. Use it. Reading from the session brings the wrong person on sub-account and account-switch flows. On a call arriving through the API there is **no session at all**.

> **A gate is not the only defence**
> 
> A gate runs on **that flow** alone. Where the same work can be done through the API, that path may not pass this gate. To hold a rule everywhere, check from the hook's entry which call paths the gate covers.

> **The page-output hook runs on every request**
> 
> The filter touching a page's finished output runs on **every page view**. A heavy query or an outside call inside it is paid for by the whole site. Cache the heavy work and use only the ready answer in the listener.

## Related Articles

- [Hooks on the Customer Site](https://dev.wisecp.com/en/hooks-on-the-customer-site)
- [Customer Account Hooks](https://dev.wisecp.com/en/customer-account-hooks)
- [Writing a Hook Listener](https://dev.wisecp.com/en/writing-a-hook-listener)
