🎨 Hooks de front + assets — patron completo
Actualizado: 2024-12-01
Codigo real de produccion
Patron extraido de multiples modulos reales (ecom_stickycart, ecom_magnificus, ecom_showcombilist). Muestra como combinar hooks de front para añadir funcionalidad visual.
#Registrar CSS y JS
actionFrontControllerSetMedia — el hook correcto para assets
php
<?php
// ══ REGLA: Usar actionFrontControllerSetMedia para CSS/JS ══
// NO usar displayHeader para esto (funciona pero no es correcto)
public function hookActionFrontControllerSetMedia()
{
// Solo cargar en pagina de producto
if ($this->context->controller->php_self !== 'product') {
return;
}
// CSS principal del modulo
$this->context->controller->registerStylesheet(
'ecom-stickycart-style',
'modules/' . $this->name . '/views/css/front.css',
['media' => 'all', 'priority' => 150]
);
// JS principal (defer para no bloquear)
$this->context->controller->registerJavascript(
'ecom-stickycart-js',
'modules/' . $this->name . '/views/js/front.js',
['position' => 'bottom', 'priority' => 150, 'attribute' => 'defer']
);
// CSS custom del admin (textarea en la config)
$customCss = Configuration::get('ECOM_STICKY_CUSTOM_CSS');
if (!empty(trim($customCss))) {
// Inyectar CSS inline (no como archivo)
Media::addJsDef([
'ecomStickyCustomCss' => $customCss,
]);
}
// Variables PHP → JavaScript
Media::addJsDef([
'ecomStickyConfig' => [
'layout' => Configuration::get('ECOM_STICKY_LAYOUT'),
'position' => Configuration::get('ECOM_STICKY_POSITION'),
'gap' => (int) Configuration::get('ECOM_STICKY_GAP'),
'scrollTrigger' => (int) Configuration::get('ECOM_STICKY_SCROLL_TRIGGER'),
'animation' => Configuration::get('ECOM_STICKY_ANIMATION'),
'showQty' => (bool) Configuration::get('ECOM_STICKY_SHOW_QTY'),
'showStock' => (bool) Configuration::get('ECOM_STICKY_SHOW_STOCK'),
'mobileOptimized'=> (bool) Configuration::get('ECOM_STICKY_MOBILE_OPTIMIZED'),
'enableCartUpdate'=> (bool) Configuration::get('ECOM_STICKY_ENABLE_CART_UPDATE'),
],
]);
}
// En el JS del modulo estas variables estan disponibles globalmente:
// ecomStickyConfig.layout → 'classic'
// ecomStickyConfig.position → 'bottom'
// ecomStickyConfig.showQty → true
#hookDisplayHeader — logica condicional
Logica condicionada por pagina y configuracion
php
<?php
public function hookDisplayHeader()
{
// Solo en pagina de producto
if (!($this->context->controller instanceof ProductController)) {
return '';
}
// Comprobar si la categoria actual esta excluida
$product = $this->context->controller->getProduct();
if ($product && $this->isCategoryExcluded($product->id_category_default)) {
return '';
}
// Inyectar CSS dinamico via style tag
$bgColor = Configuration::get('ECOM_STICKY_BG_COLOR');
$txtColor = Configuration::get('ECOM_STICKY_TXT_COLOR');
$btnColor = Configuration::get('ECOM_STICKY_BTN_COLOR');
return '<style>
:root {
--sticky-bg: ' . htmlspecialchars($bgColor) . ';
--sticky-text: ' . htmlspecialchars($txtColor) . ';
--sticky-btn: ' . htmlspecialchars($btnColor) . ';
}
</style>';
}
private function isCategoryExcluded(int $idCategory): bool
{
$excluded = Configuration::get('ECOM_STICKY_EXCLUDE_CATEGORIES');
if (empty($excluded)) {
return false;
}
$excludedIds = array_map('intval', explode(',', $excluded));
return in_array($idCategory, $excludedIds);
}
#hookDisplayFooter — renderizar template
Inyectar HTML via template Smarty
php
<?php
public function hookDisplayFooter()
{
// Solo en pagina de producto
if ($this->context->controller->php_self !== 'product') {
return '';
}
// Obtener datos del producto actual
$product = $this->context->controller->getProduct();
if (!$product) {
return '';
}
// Preparar datos para el template
$this->context->smarty->assign([
'sticky_product_name' => $product->name,
'sticky_product_price' => Tools::displayPrice(
$product->getPrice(true)
),
'sticky_product_image' => $this->context->link->getImageLink(
$product->link_rewrite,
$product->getCover($product->id)['id_image'] ?? 0,
'small_default'
),
'sticky_in_stock' => StockAvailable::getQuantityAvailableByProduct(
$product->id
) > 0,
'sticky_layout' => Configuration::get('ECOM_STICKY_LAYOUT'),
'sticky_position' => Configuration::get('ECOM_STICKY_POSITION'),
]);
return $this->display(__FILE__, 'views/templates/hook/sticky-bar.tpl');
}
// ── Template: views/templates/hook/sticky-bar.tpl ──
// <div id="ecom-sticky-cart"
// class="sticky-cart sticky-cart--{$sticky_layout}"
// data-position="{$sticky_position}">
// <img src="{$sticky_product_image}" alt="{$sticky_product_name}">
// <span class="sticky-cart__name">{$sticky_product_name}</span>
// <span class="sticky-cart__price">{$sticky_product_price}</span>
// {if $sticky_in_stock}
// <button class="sticky-cart__btn">{l s='Add to cart' mod='ecom_stickycart'}</button>
// {/if}
// </div>
#Patron completo integrado
| Hook | Funcion | Cuando usarlo |
|---|---|---|
| actionFrontControllerSetMedia | registerStylesheet/JS + Media::addJsDef | SIEMPRE para CSS y JS de front |
| displayHeader | CSS variables, meta tags, logica condicional | CSS dinamico, inline styles |
| displayFooter | HTML via template Smarty | Elementos visuales que van al final del body |
| displayProductAdditionalInfo | Info extra en ficha producto | Badges, avisos, datos extra |
| displayProductButtons | Botones junto a 'Añadir al carrito' | Wishlist, comparar, compartir |
| hookDisplayBackOfficeHeader | Assets solo en el admin | CSS/JS para controllers admin |
Orden de ejecucion de hooks
actionFrontControllerSetMedia → displayHeader (en
) → [body content] → displayFooter (antes de ). Los assets registrados con registerStylesheet/JS se incluyen automaticamente en las posiciones correctas.
Descargar en Markdown
Pensado para pegar en ChatGPT, Claude u otra IA. Incluye solo el contenido de esta pagina.