Styles and scripts
A module block needs its own styles and sometimes a script. You do not write link and script tags in a hook template: files are registered with the page controller, and the engine prints them in the right place and combines and minifies them with the rest.
Where the files live
Create two folders and two files by hand:
modules/acmehello/
├── acmehello.php
├── logo.png
└── views/
├── css/
│ └── front.css
├── js/
│ └── front.js
└── templates/
└── hook/
├── home.tpl
└── product-reviews.tpl/* modules/acmehello/views/css/front.css */
.acme-hello h2 {
color: #2563eb;
text-align: center;
}Loading a stylesheet
Files are registered in the handler of the actionFrontControllerSetMedia hook — the engine calls it on every front office page while it collects the list of styles and scripts.
// modules/acmehello/acmehello.php
public function hookActionFrontControllerSetMedia(): void
{
$this->context->controller->registerStylesheet(
'acmehello-front',
'modules/' . $this->name . '/views/css/front.css',
['media' => 'all', 'priority' => 150],
);
}The first argument is a unique id of the file, the second is the path from the shop root. The lower the priority, the earlier the file is loaded.
The hook has to be registered: add the line && $this->registerHook('actionFrontControllerSetMedia') to install() and reset the module:
php bin/console prestashop:module reset acmehelloRefresh the home page: the greeting is now blue and centred.
Loading a script
// modules/acmehello/views/js/front.js
document.addEventListener('DOMContentLoaded', () => {
const block = document.querySelector('.acme-reviews');
if (block) {
block.classList.add('acme-reviews--ready');
}
});// modules/acmehello/acmehello.php
public function hookActionFrontControllerSetMedia(): void
{
$this->context->controller->registerStylesheet(
'acmehello-front',
'modules/' . $this->name . '/views/css/front.css',
['media' => 'all', 'priority' => 150],
);
$this->context->controller->registerJavascript(
'acmehello-front',
'modules/' . $this->name . '/views/js/front.js',
['position' => 'bottom', 'priority' => 150],
);
}'position' => 'bottom' puts the script at the end of the page, 'head' at the top. In the product page source the reviews block gets the class acme-reviews--ready.
Only on the page that needs it
To avoid loading files on the whole site, check which page is open:
// modules/acmehello/acmehello.php
public function hookActionFrontControllerSetMedia(): void
{
if ($this->context->controller->php_self !== 'product') {
return;
}
// registerStylesheet and registerJavascript as above
}The php_self property is the page name: index, product, category, cart, order.
Data for the script
Values from PHP are passed to JavaScript with a Media::addJsDef() call:
Media::addJsDef([
'acmeHelloProductId' => (int) Tools::getValue('id_product'),
]);A global variable acmeHelloProductId appears on the page and is available in front.js.
In the back office
Back office pages use another hook — actionAdminControllerSetMedia, and files are added with the addCSS() and addJS() methods:
// modules/acmehello/acmehello.php
public function hookActionAdminControllerSetMedia(): void
{
$this->context->controller->addCSS($this->_path . 'views/css/admin.css');
}The $this->_path property is the web path to the module folder.
Common mistake
You edited the CSS, but the site looks the same. If combining and minifying files is turned on at "Advanced Parameters → Performance", the engine serves a built copy. Press "Clear cache" there, and turn these settings off during development.