Understanding PrestaShop Hook Priorities and Execution Order
What Are Hooks in PrestaShop?
Hooks are PrestaShop's extension mechanism — the points in the code where modules can attach themselves to add functionality, modify behavior, or inject content into pages. Think of hooks as named connection points scattered throughout PrestaShop's codebase. When the system reaches a hook point during page rendering or processing, it calls every module registered on that hook, in a specific order.
Understanding hooks is fundamental to customizing PrestaShop without modifying core files. Every module you install uses hooks to do its work, and the order in which modules execute on shared hooks can significantly affect your store's behavior and appearance.
Two Types of Hooks
Display Hooks
Display hooks (prefixed with display) inject HTML content into the page. Their output is visible to the user. Examples -
displayHeader— inside the HTML<head>section (for CSS, meta tags)displayTop— top of the page (header area)displayHome— homepage content areadisplayLeftColumn/displayRightColumn— sidebar columnsdisplayFooter— footer areadisplayProductAdditionalInfo— product page additional info sectiondisplayShoppingCartFooter— below the shopping cart
Action Hooks
Action hooks (prefixed with action) execute logic without returning HTML. They are triggered during business operations and are used for data processing, validation, or synchronization. Examples -
actionCartSave— when a cart is savedactionOrderStatusUpdate— when an order status changesactionProductAdd— when a product is createdactionCustomerAccountAdd— when a new customer registersactionPaymentConfirmation— when payment is confirmedactionValidateOrder— when an order is validated
How Execution Order Works
When PrestaShop encounters a hook, it looks up all modules registered on that hook in the ps_hook_module table. The modules are executed in the order determined by the position column — position 1 runs first, position 2 runs second, and so on.
-- View execution order for the displayHeader hook
SELECT hm.position, m.name AS module_name, h.name AS hook_name
FROM ps_hook_module hm
JOIN ps_module m ON hm.id_module = m.id_module
JOIN ps_hook h ON hm.id_hook = h.id_hook
WHERE h.name = 'displayHeader'
ORDER BY hm.position ASC;What Determines Position?
When a module is installed and registers itself on a hook, it is assigned the next available position (appended to the end). The position can be changed in two ways -
- Through the Back Office - Go to Design > Positions. Here you can drag and drop modules to reorder them on each hook, or use the position editing interface.
- Through the database - Directly update the position value in
ps_hook_module.
Why Position Matters
For display hooks, position determines the visual order. A module at position 1 renders its HTML before a module at position 2. If you want a banner module to appear above a menu module in the header, the banner module needs a lower position number.
For action hooks, position determines processing order. This is critical when -
- Multiple modules modify the same data (e.g., price calculation hooks)
- One module depends on another module's processing being complete first
- A module needs to validate data before another module acts on it
Registering Hooks in Your Module
Modules register hooks during installation through the registerHook() method -
public function install()
{
return parent::install()
&& $this->registerHook('displayHeader')
&& $this->registerHook('displayProductAdditionalInfo')
&& $this->registerHook('actionCartSave')
&& $this->registerHook('actionOrderStatusUpdate');
}
// Handler methods must follow the naming convention
public function hookDisplayHeader($params)
{
// Return HTML for the section
$this->context->controller->addCSS($this->_path . 'views/css/style.css');
$this->context->controller->addJS($this->_path . 'views/js/front.js');
}
public function hookDisplayProductAdditionalInfo($params)
{
$product = $params['product'];
$this->context->smarty->assign([
'my_product_data' => $this->getProductData($product['id_product']),
]);
return $this->display(__FILE__, 'views/templates/hook/product-info.tpl');
}
public function hookActionCartSave($params)
{
// Process cart data - no HTML return
$cart = $params['cart'];
$this->logCartActivity($cart);
}Managing Hook Positions in the Back Office
The Positions Page
Navigate to Design > Positions to see all hooks and their attached modules. This page shows -
- Every hook that has at least one module attached
- The modules on each hook, in their current execution order
- Controls to reorder, unhook, or transplant modules
Transplanting Modules
Transplanting means moving a module from one hook to another. Click "Transplant a module" at the top of the Positions page, select the module and the target hook. This is useful when -
- A module is displaying in the wrong location
- You want to move content from the left column to the right column
- A theme uses different hook names than the module expects
Exceptions
You can configure a module to appear on specific pages only. Click the module's edit icon on the Positions page to set exceptions (pages where the module should NOT appear).
Common Hook Execution Issues
Module Conflict Through Shared Hooks
When two modules both hook into displayProductAdditionalInfo and both try to add an "Add to Cart" button, you get duplicate buttons. Solutions -
- Reorder the modules so the correct one appears first
- Unhook the conflicting module from that hook
- Use CSS to hide the duplicate element (quick fix)
CSS/JS Loading Order
Modules that add CSS through displayHeader load their styles in hook position order. If Module A adds a CSS reset and Module B adds component styles, Module A must have a lower position so its CSS loads first. Use addCSS() with the media parameter and priority controls when available.
Performance Impact
Every module on displayHeader or actionDispatcher runs on every page load. If you have 30 modules on displayHeader, that is 30 function calls per page. Check which modules you actually need on performance-critical hooks and unhook unnecessary ones.
-- Count modules per hook to find potential performance issues
SELECT h.name, COUNT(*) AS module_count
FROM ps_hook_module hm
JOIN ps_hook h ON hm.id_hook = h.id_hook
GROUP BY h.name
ORDER BY module_count DESC
LIMIT 20;Important Hooks for Store Owners
Hooks That Affect Checkout
displayPayment/paymentOptions— where payment methods appeardisplayOrderConfirmation— the thank-you page after purchaseactionValidateOrder— fires when order is created (used by stock, email, analytics modules)
Hooks That Affect SEO
displayHeader— where meta tags, canonical URLs, and schema markup are injectedfilterHtmlContent— can modify page HTML before outputactionDispatcher— fires on every request, used by URL rewrite and redirect modules
Hooks That Affect Product Display
displayProductAdditionalInfo— additional info on product pagedisplayProductListReviews— review snippets in category listingsdisplayAfterProductThumbs— below product image gallery
Debugging Hook Issues
If you suspect a hook-related problem, enable PrestaShop's debug mode and check -
- Which modules are attached to the relevant hook (Design > Positions or the SQL query above)
- The execution order of those modules
- Whether any module is returning errors or unexpected HTML
- Whether transplanting or reordering resolves the issue
For advanced debugging, you can temporarily add logging to specific hook methods to trace execution flow and identify which module is causing the problem.
For more details, read our guides: PrestaShop Hooks Explained: How Modules Talk to Your Store and Mastering PrestaShop Hooks: A Developer Reference for 1.7, 8.x and 9.x.
Was this answer helpful?
Still have questions?
Can't find what you're looking for? Send us your question and we'll get back to you quickly.