Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Most of these modules have been optimized and made compatible for PrestaShop v9.
| Module name | Description | Minimum version |
|----------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------|
| [api_module](https://github.com/PrestaShop/example-modules/tree/master/api_module) | This example module demonstrates how to modify PrestaShop's new API. | v9.0.0 |
| [dashexample](https://github.com/PrestaShop/example-modules/tree/master/dashexample) | This module demonstrates how to integrate with the migrated Symfony dashboard page through its new dedicated hooks. | v9.2.0 |
| [demo_grid](https://github.com/PrestaShop/example-modules/tree/master/demo_grid) | This module demonstrates how to use Grid in PrestaShop | v9.0.0 |
| [democonsolecommand](https://github.com/PrestaShop/example-modules/tree/master/democonsolecommand) | Example module showing how to implement a Symfony console command | v9.0.0 |
| [democontrollertabs](https://github.com/PrestaShop/example-modules/tree/master/democontrollertabs) | Demo Creating modern Controllers and associate Tabs to them | v9.0.0 |
Expand Down
3 changes: 3 additions & 0 deletions dashexample/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
vendor/
composer.lock
.idea
88 changes: 88 additions & 0 deletions dashexample/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Dashboard example (`dashexample`)

Demonstration module for the **migrated (Symfony) Back Office Dashboard** and its new dedicated hook family.

It is both living documentation of the integration contract and a validation vehicle: once installed with the `dashboard` feature flag enabled, it renders content in Zone One, Zone Two and the toolbar area of the new dashboard page.

## What it demonstrates

- Registering on the **new** dashboard hooks: `displayAdminDashboardZoneOne`, `displayAdminDashboardZoneTwo`, `displayAdminDashboardToolbar`.
- Rendering hook content through **module Twig templates** (`views/templates/admin/*.html.twig`) — no Smarty, no `HelperForm`, no `Db::getInstance()`.
- Passing and using hook **parameters** (`date_from` / `date_to`, the employee stats date range).
- Loading the module's **own CSS/JS assets from its hook output** (see `toolbar.html.twig`) — no `actionAdminControllerSetMedia`, no `get_class($this->context->controller)` detection.

## Requirements

- PrestaShop **9.2.0** or later (the version that introduces the migrated dashboard and its hooks).
- The **`dashboard` feature flag** enabled: *Advanced Parameters > New & Experimental Features > Dashboard page*.

## Install

```bash
# from the PrestaShop root
php bin/console prestashop:module install dashexample
```

Then enable the `dashboard` feature flag and open the Dashboard. You should see the module's blocks in the two zones and a marker in the toolbar area.

## New vs legacy hook families

The migrated dashboard deliberately uses a **new hook family**, distinct from the legacy one. A module knows which architecture it is integrating with purely from **which hook is called** — there is no version detection to do on the module side.

| New (Symfony dashboard) | Legacy (legacy dashboard) | Area |
|---|---|---|
| `displayAdminDashboardZoneOne` | `dashboardZoneOne` | Left column |
| `displayAdminDashboardZoneTwo` | `dashboardZoneTwo` | Center column |
| `displayAdminDashboardZoneThree` | `dashboardZoneThree` | Right column |
| `displayAdminDashboardTop` | `displayDashboardTop` | Top area |
| `displayAdminDashboardToolbar` | `displayDashboardToolbarTopMenu` | Toolbar |

The legacy hooks are untouched and keep working on the legacy page (flag off).

## Supporting both PrestaShop versions in one module

To render on **both** the legacy and the migrated dashboard from a single module, register on **both** hook families and let each callback render with the matching architecture. The core calls only the hook that belongs to the currently displayed page, so the two never collide.

```php
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
{
// legacy Smarty rendering
$this->smarty->assign($params);

return $this->display(__FILE__, 'views/templates/hook/zone_one.tpl');
}
```

This module registers **only the new hooks** on purpose, so it also serves as a focused test of the new contract.

## Files

| File | Role |
|---|---|
| `dashexample.php` | Module class: hook registration + hook callbacks rendering Twig |
| `views/templates/admin/zone_one.html.twig` | Zone One block |
| `views/templates/admin/zone_two.html.twig` | Zone Two block |
| `views/templates/admin/toolbar.html.twig` | Toolbar block + asset loading |
| `views/css/dashexample.css`, `views/js/dashexample.js` | Module-owned assets |
17 changes: 17 additions & 0 deletions dashexample/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "prestashop/dashexample",
"description": "Demonstration of the new dedicated hooks of the migrated Symfony dashboard page.",
"license": "AFL-3.0",
"authors": [
{
"name": "PrestaShop Core Team"
}
],
"require": {
"php": ">=8.1"
},
"config": {
"prepend-autoloader": false
},
"type": "prestashop-module"
}
11 changes: 11 additions & 0 deletions dashexample/config.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<module>
<name>dashexample</name>
<displayName><![CDATA[Dashboard example]]></displayName>
<version><![CDATA[1.0.0]]></version>
<description><![CDATA[Demonstration of the new dedicated hooks of the migrated Symfony dashboard page.]]></description>
<author><![CDATA[PrestaShop]]></author>
<tab><![CDATA[administration]]></tab>
<is_configurable>0</is_configurable>
<need_instance>0</need_instance>
</module>
111 changes: 111 additions & 0 deletions dashexample/dashexample.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/

declare(strict_types=1);

use Twig\Environment;

if (!defined('_PS_VERSION_')) {
exit;
}

/**
* Demonstrates how a module integrates with the migrated (Symfony) Back Office Dashboard.
*
* The Symfony dashboard dispatches a dedicated hook family (`displayAdminDashboard*`), distinct
* from the legacy `dashboardZone*` / `displayDashboard*` hooks. A module therefore knows which
* architecture it is integrating with purely from which hook is called — no version detection,
* no `get_class($controller)` check, no Smarty, no `HelperForm`, no `Db::getInstance()`.
*
* See README.md for how to stay compatible with the legacy dashboard at the same time.
*/
class DashExample extends Module
{
public function __construct()
{
$this->name = 'dashexample';
$this->author = 'PrestaShop';
$this->version = '1.0.0';
$this->ps_versions_compliancy = ['min' => '9.2.0', 'max' => '9.99.99'];
$this->need_instance = 0;

parent::__construct();

$this->displayName = $this->l('Dashboard example');
$this->description = $this->l('Demonstration of the new dedicated hooks of the migrated Symfony dashboard page.');
}

public function install(): bool
{
return parent::install()
&& $this->registerHook([
'displayAdminDashboardZoneOne',
'displayAdminDashboardZoneTwo',
'displayAdminDashboardToolbar',
]);
}

/**
* Renders a block in the first (left) column of the Symfony dashboard.
* Receives the employee date range selected on the page.
*/
public function hookDisplayAdminDashboardZoneOne(array $params): string
{
return $this->render('zone_one.html.twig', [
'dateFrom' => $params['date_from'] ?? null,
'dateTo' => $params['date_to'] ?? null,
]);
}

/**
* Renders a block in the second (center) column of the Symfony dashboard.
*/
public function hookDisplayAdminDashboardZoneTwo(array $params): string
{
return $this->render('zone_two.html.twig', [
'dateFrom' => $params['date_from'] ?? null,
'dateTo' => $params['date_to'] ?? null,
]);
}

/**
* Renders content in the toolbar area of the Symfony dashboard.
*
* This hook is rendered once at the top of the page, so the module loads its own
* assets from here (via its hook output) instead of `actionAdminControllerSetMedia`.
*/
public function hookDisplayAdminDashboardToolbar(array $params): string
{
return $this->render('toolbar.html.twig', [
'moduleUri' => $this->getPathUri(),
]);
}

/**
* Render one of this module's admin Twig templates.
*/
private function render(string $template, array $params = []): string
{
/** @var Environment $twig */
$twig = $this->get('twig');

return $twig->render(sprintf('@Modules/%s/views/templates/admin/%s', $this->name, $template), $params);
}
}
25 changes: 25 additions & 0 deletions dashexample/views/css/dashexample.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0).
* It is also available through the world-wide-web at this URL: https://opensource.org/licenses/AFL-3.0
*/

.dashexample-toolbar {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 14px;
margin-bottom: 15px;
border-radius: 4px;
background-color: #e6f0ff;
color: #25b9d7;
font-weight: 600;
}

.dashexample-card .panel-heading {
display: flex;
align-items: center;
gap: 6px;
}
13 changes: 13 additions & 0 deletions dashexample/views/js/dashexample.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0).
* It is also available through the world-wide-web at this URL: https://opensource.org/licenses/AFL-3.0
*/

document.addEventListener('DOMContentLoaded', () => {
// The module manages its own assets: this file is loaded from the module's hook output
// (see views/templates/admin/toolbar.html.twig), not via actionAdminControllerSetMedia.
console.log('[dashexample] Loaded on the migrated Symfony dashboard page.');
});
19 changes: 19 additions & 0 deletions dashexample/views/templates/admin/toolbar.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{#**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0).
* It is also available through the world-wide-web at this URL: https://opensource.org/licenses/AFL-3.0
*#}

{% trans_default_domain 'Module.Dashexample.Admin' %}

{# The module loads its own assets from its hook output — no actionAdminControllerSetMedia,
no get_class($controller) detection. #}
<link rel="stylesheet" href="{{ moduleUri }}views/css/dashexample.css">
<script src="{{ moduleUri }}views/js/dashexample.js" defer></script>

<div class="dashexample-toolbar">
<span class="material-icons">extension</span>
<span>{{ 'Dashboard example module is active.'|trans }}</span>
</div>
22 changes: 22 additions & 0 deletions dashexample/views/templates/admin/zone_one.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{#**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0).
* It is also available through the world-wide-web at this URL: https://opensource.org/licenses/AFL-3.0
*#}

{% trans_default_domain 'Module.Dashexample.Admin' %}

<div class="panel dashexample-card">
<h3 class="panel-heading">
<span class="material-icons">widgets</span>
{{ 'Zone one'|trans }}
</h3>
<div class="panel-body">
<p>{{ 'This block is rendered by the dashexample module through the displayAdminDashboardZoneOne hook.'|trans }}</p>
<p class="text-muted mb-0">
{{ 'Selected range: %from% → %to%'|trans({'%from%': dateFrom, '%to%': dateTo}) }}
</p>
</div>
</div>
24 changes: 24 additions & 0 deletions dashexample/views/templates/admin/zone_two.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{#**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0).
* It is also available through the world-wide-web at this URL: https://opensource.org/licenses/AFL-3.0
*#}

{% trans_default_domain 'Module.Dashexample.Admin' %}

<div class="panel dashexample-card">
<h3 class="panel-heading">
<span class="material-icons">insights</span>
{{ 'Zone two'|trans }}
</h3>
<div class="panel-body">
<p>{{ 'This block is rendered by the dashexample module through the displayAdminDashboardZoneTwo hook.'|trans }}</p>
<ul class="mb-0">
<li>{{ 'Rendered with a module Twig template (no Smarty).'|trans }}</li>
<li>{{ 'No HelperForm, no Db::getInstance().'|trans }}</li>
<li>{{ 'Range received as hook parameters: %from% → %to%.'|trans({'%from%': dateFrom, '%to%': dateTo}) }}</li>
</ul>
</div>
</div>