Panel Customer Screen Hooks
The nineteen placement points of the customer screens: summary cards, tabs, the list toolbar and the creation form.
Overview
The placement points of the customer screens live here. They all work the same way. The HTML you return appears at that point. Return null when you have nothing to add.
Two points fall outside that pattern. Adding a tab receives an object rather than HTML, and the addition happens through a method call. The document field form is collected once as the page opens and then fixed. It cannot vary with the field being edited.
Reference
The top of the summary tab
Appears at the very top of the customer summary, above the statistic cards. The right place for a risk banner, a last-contact note or a key-account warning.
null and false are skipped, so return null when you have nothing to add. The output enters the page unescaped — clean anything coming from outside yourself.Hook::add('ui:admin.client_detail.summary.top', 10,
function ($user, $user_id, $user_stats) {
$score = Acme::riskScore($user_id);
if ($score < 70) return null; // eklenecek bir sey yoksa null
return '<div class="alert alert-warning">Risk skoru: ' . (int) $score . '</div>';
});Adding a row to the information card
Appears after the last row of the information card. The place for a field such as an outside customer number, the referral source or an account manager.
null and false are skipped, so return null when you have nothing to add. The output enters the page unescaped — clean anything coming from outside yourself.Hook::add('ui:admin.client_detail.summary.info_card', 10,
function ($user, $client_info, $user_id) {
$crm = Acme::crmId($user_id);
if ($crm === '') return null;
// Cikti kacissiz basilir: dis degeri kendiniz temizleyin.
return '<div class="row"><div class="col-5">CRM</div><div class="col-7">'
. htmlspecialchars($crm) . '</div></div>';
});Adding an operation to the actions card
Appears after the last operation in the actions card. It puts an operation of your own beside the built-in ones.
null and false are skipped, so return null when you have nothing to add. The output enters the page unescaped — clean anything coming from outside yourself.Hook::add('ui:admin.client_detail.summary.action_cards', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});The bottom of the summary tab
Appears once the cards of the summary tab end. The place for a card or an information panel of your own.
null and false are skipped, so return null when you have nothing to add. The output enters the page unescaped — clean anything coming from outside yourself.Hook::add('ui:admin.client_detail.summary.bottom', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});A badge or button in the title area
Appears at the end of the status badges in the page title. Put a badge of your own or a shortcut button here.
null and false are skipped, so return null when you have nothing to add. The output enters the page unescaped — clean anything coming from outside yourself.Hook::add('ui:admin.client_detail.header_actions', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});A new tab on the customer detail
Runs once every core tab is built. Unlike the other placement points you do not return HTML here: you add the tab through the object’s method.
Hook::add('ui:admin.client_detail.tabs', 10, function ($tab, $user, $user_id) {
// HTML DONDURMEYIN: sekme nesneye eklenir.
$tab->add('acme', 'Acme', Acme::renderTab($user_id));
});The bottom of the profile tab
Appears once the vertical tabs of the profile are on screen. It suits a verification summary or an extra preference section.
null and false are skipped, so return null when you have nothing to add. The output enters the page unescaped — clean anything coming from outside yourself.Hook::add('ui:admin.client_detail.profile.bottom', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});The top of the contacts tab
Appears above the address and contact list. It suits an address verification state or a warning about a missing billing address.
null and false are skipped, so return null when you have nothing to add. The output enters the page unescaped — clean anything coming from outside yourself.Hook::add('ui:admin.client_detail.contacts.top', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});The top of the sub-users tab
Appears above the sub-user list. It suits a warning about unaccepted invitations or a note on permission policy.
null and false are skipped, so return null when you have nothing to add. The output enters the page unescaped — clean anything coming from outside yourself.Hook::add('ui:admin.client_detail.subusers.top', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});The top of the invoices tab
Appears above the invoice table. It suits an outstanding balance warning or the state of automatic payment.
null and false are skipped, so return null when you have nothing to add. The output enters the page unescaped — clean anything coming from outside yourself.Hook::add('ui:admin.client_detail.invoices.top', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});The top of the services tab
Appears above the service and order list. It suits a renewal warning or a provisioning failure banner.
null and false are skipped, so return null when you have nothing to add. The output enters the page unescaped — clean anything coming from outside yourself.Hook::add('ui:admin.client_detail.orders.top', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});The top of the support tab
Appears above the ticket table. It suits a count of open tickets or a satisfaction summary.
null and false are skipped, so return null when you have nothing to add. The output enters the page unescaped — clean anything coming from outside yourself.Hook::add('ui:admin.client_detail.tickets.top', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});The top of the notes tab
Appears above the note list. The place to show system notes coming from an outside source.
null and false are skipped, so return null when you have nothing to add. The output enters the page unescaped — clean anything coming from outside yourself.Hook::add('ui:admin.client_detail.notes.top', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});The very bottom of the customer page
Appears at the very end of the page, immediately before the footer. It suits a panel that belongs to no tab.
null and false are skipped, so return null when you have nothing to add. The output enters the page unescaped — clean anything coming from outside yourself.Hook::add('ui:admin.client_detail.bottom', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});The customer list toolbar
Appears in the button group above the list. Add a button for an export or a bulk action of your own.
null and false are skipped, so return null when you have nothing to add. The output enters the page unescaped — clean anything coming from outside yourself.Hook::add('ui:admin.client_list.toolbar', 10, function () {
return '<a href="/acme/export" class="btn btn-outline-secondary">'
. '<i class="bi bi-download"></i> Acme</a>';
});Above the table on the customer list
Appears after the statistic card and the filter panel, immediately above the table.
null and false are skipped, so return null when you have nothing to add. The output enters the page unescaped — clean anything coming from outside yourself.Hook::add('ui:admin.client_list.before_table', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});Above the customer creation form
Appears above the new customer form. It suits an information banner or an extra instruction.
null and false are skipped, so return null when you have nothing to add. The output enters the page unescaped — clean anything coming from outside yourself.Hook::add('ui:admin.client_create.before_content', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});Below the customer creation form
Appears once the new customer form ends, at the bottom of the page.
null and false are skipped, so return null when you have nothing to add. The output enters the page unescaped — clean anything coming from outside yourself.Hook::add('ui:admin.client_create.bottom', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});An extra section on the document field form
Puts an extra section into the add and edit window of the document verification fields. If you introduced a field type of your own, ask for its settings here.
Hook::add('ui:admin.document_field.form', 10, function () {
// The output is collected once: it cannot vary per field.
return '<div class="mb-3"><label>Acme check</label>'
. '<input class="form-control" name="acme_rule"></div>';
});Pitfalls
Whatever you return at these points enters the page as it stands. Embedding a value from outside (a customer name, a response from another system, form input) directly creates a code execution hole in the panel. Escape the value yourself.
The tab point looks like the others but shows no HTML: it hands you an object and the tab is added through its method. A listener returning HTML quietly does nothing here, and raises no error either, which makes it hard to spot.
Related Articles
Vielen Dank für Ihre Rückmeldung!
Unser Support-Team ist rund um die Uhr für Sie da, wenn Sie oben nicht fündig werden.