🎨 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

HookFuncionCuando usarlo
actionFrontControllerSetMediaregisterStylesheet/JS + Media::addJsDefSIEMPRE para CSS y JS de front
displayHeaderCSS variables, meta tags, logica condicionalCSS dinamico, inline styles
displayFooterHTML via template SmartyElementos visuales que van al final del body
displayProductAdditionalInfoInfo extra en ficha productoBadges, avisos, datos extra
displayProductButtonsBotones junto a 'Añadir al carrito'Wishlist, comparar, compartir
hookDisplayBackOfficeHeaderAssets solo en el adminCSS/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.