Panel Service Screen Hooks
The eighteen placement points of the service screens: the detail tabs, the title area and the toolbars of the side lists.
Overview
The placement points of the service screens live here. They cover every tab of the detail page, the title area and the toolbars of the side lists.
Most detail points hand you the service record. Some add something that can arrive empty: the product record when the product was gone, or the module instance when the service has no server. Test before reaching into those.
Reference
A badge or button in the service title
Appears in the title row of the service detail. Put the state on the remote panel or a shortcut of your own 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.service_detail.header_actions', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});A new tab on the service detail
Runs once the core tabs are built. You do not return HTML: you add the tab through the object’s method. Two flags tell you which tab makes sense.
Hook::add('ui:admin.service_detail.tabs', 10,
function ($tab, $service, $is_domain, $has_module) {
// Sunucusu olmayan hizmette uzak panel sekmesi bos cikar.
if (!$has_module) return;
$tab->add('acme', 'Acme', Acme::renderTab((int) ($service['id'] ?? 0)));
});The bottom of the details tab
Appears below the service details.
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.service_detail.details.bottom', 10, function ($service, $product) {
// Urun BOS gelebilir.
if (!$product) return null;
return '<div class="mt-3">' . htmlspecialchars(Acme::planNote($product)) . '</div>';
});The bottom of the management tab
Appears below the server management tools.
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.service_detail.management.bottom', 10, function ($service, $module) {
// Modul BOS gelebilir: metot cagirmadan once sinayin.
if (!$module) return null;
return Acme::renderRemotePanel($module, $service);
});The top of the add-ons tab
Appears above the list of service add-ons.
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.service_detail.addons.top', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});The bottom of the requirements tab
Appears below the details asked of the customer during the order.
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.service_detail.requirements.bottom', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});The bottom of the history tab
Appears below the service history. The place to put your own record beside the core one.
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.service_detail.history.bottom', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});The top of the package change tab
Appears above the package upgrade screen. The remaining days and amount are in your hands, so you can show your own pricing note 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.service_detail.upgrade.top', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});The bottom of the transfer tab
Appears below the domain transfer screen.
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.service_detail.transfer.bottom', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});The bottom of the verification tab
Appears below the domain contact verification screen.
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.service_detail.verification.bottom', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});The very bottom of the service page
Appears at the very end of the page. 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.service_detail.bottom', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});The service list toolbar
Appears in the button group above the service list.
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.service_list.toolbar', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});Above the table on the service list
Appears immediately above the service 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.service_list.before_table', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});The add-on list toolbar
Appears in the toolbar of the service add-on list.
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.service_addon_list.toolbar', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});Above the table on the add-on list
Appears immediately above the add-on 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.service_addon_list.before_table', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});The cancellation request toolbar
Appears in the toolbar of the cancellation request list.
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.service_cancellation_list.toolbar', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});The transfer list toolbar
Appears in the toolbar of the service transfer list.
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.service_transfer_list.toolbar', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});The package change list toolbar
Appears in the toolbar of the package upgrade and downgrade list.
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.service_updowngrade_list.toolbar', 10, function () {
return '<div class="alert alert-info">Acme</div>';
});Pitfalls
The module parameter on the management tab is empty when the service has no server or the module failed to load. A listener calling a method straight away raises a fatal error there and takes the whole page down: it is not your panel that breaks but the administrator’s service screen.
The options array on the transfer tab holds the authorisation code of the domain. Whoever sees that code can move the domain to another registrar: keep it off the screen, out of your logs and away from outside services.
Related Articles
Thanks for your feedback!
Our support team is here around the clock for anything you can't find above.