The Back Office Dashboard page is being migrated from a legacy controller to a Symfony controller rendering a Twig layout. The migrated page is gated behind the dashboard feature flag (beta, disabled by default), available in Advanced Parameters > New & Experimental Features.
The migrated page deliberately exposes a new, dedicated hook family (displayAdminDashboard*), distinct from the legacy dashboard hooks. This is the key integration principle:
get_class($this->context->controller) check, and no dependency on Smarty or the legacy Helper* classes.A complete, minimal example is provided by the dashexample module.
| New hook (Symfony dashboard) | Type | Parameters | Legacy counterpart |
|---|---|---|---|
displayAdminDashboardZoneOne |
display | date_from, date_to |
dashboardZoneOne |
displayAdminDashboardZoneTwo |
display | date_from, date_to |
dashboardZoneTwo |
displayAdminDashboardZoneThree |
display | date_from, date_to |
dashboardZoneThree |
displayAdminDashboardTop |
display | date_from, date_to |
displayDashboardTop |
displayAdminDashboardBottom |
display | date_from, date_to |
— (new full-width zone) |
displayAdminDashboardToolbar |
display | — | displayDashboardToolbarTopMenu |
The date_from / date_to parameters carry the employee’s selected stats date range (format Y-m-d).
The zone hooks are expected to return an HTML string; the core injects it into the corresponding zone. The page makes no assumption about how the module produces that HTML.
On the migrated page you render your content with a Twig template and the module’s Symfony service container — no Smarty, no HelperForm, no Db::getInstance():
public function install(): bool
{
return parent::install()
&& $this->registerHook([
'displayAdminDashboardZoneOne',
'displayAdminDashboardZoneTwo',
'displayAdminDashboardToolbar',
]);
}
public function hookDisplayAdminDashboardZoneOne(array $params): string
{
return $this->get('twig')->render('@Modules/mymodule/views/templates/admin/zone_one.html.twig', [
'dateFrom' => $params['date_from'] ?? null,
'dateTo' => $params['date_to'] ?? null,
]);
}
Because there is no actionAdminControllerSetMedia + controller class-name detection, load your CSS/JS from your hook output. The toolbar hook is rendered once at the top of the page, which makes it a good place for this:
{# views/templates/admin/toolbar.html.twig #}
<link rel="stylesheet" href="{{ moduleUri }}views/css/mymodule.css">
<script src="{{ moduleUri }}views/js/mymodule.js" defer></script>
where moduleUri is $this->getPathUri() passed from the hook.
To keep a single module compatible across PrestaShop versions, register on both hook families. The core calls only the hook that belongs to the currently displayed page, so the two never collide:
public function install(): bool
{
return parent::install()
&& $this->registerHook([
// Migrated (Symfony) dashboard — Twig, no legacy helpers
'displayAdminDashboardZoneOne',
'displayAdminDashboardZoneTwo',
'displayAdminDashboardToolbar',
// Legacy dashboard — Smarty / HelperForm as before
'dashboardZoneOne',
'dashboardZoneTwo',
'displayDashboardToolbarTopMenu',
]);
}
// Called only on the migrated page
public function hookDisplayAdminDashboardZoneOne(array $params): string
{
return $this->get('twig')->render('@Modules/mymodule/views/templates/admin/zone_one.html.twig', $params);
}
// Called only on the legacy page
public function hookDashboardZoneOne(array $params): string
{
$this->smarty->assign($params);
return $this->display(__FILE__, 'views/templates/hook/zone_one.tpl');
}
dashactivity, dashtrends, dashgoals, dashproducts) are not yet compatible with the migrated page and will not display anything on it until they are migrated. This is why the page is gated behind a beta feature flag.