🛍️ Todos los hooks de la pagina de producto — mapa completo

Actualizado: 2025-01-15

#Mapa visual de hooks en producto

Layout de la pagina de producto con posiciones de hooks
text
┌─────────────────────────────────────────────────────────┐
│  displayHeader                                          │
│  displayBanner                                          │
├─────────────────────────────────────────────────────────┤
│  Breadcrumb                                             │
├──────────────────────┬──────────────────────────────────┤
│                      │  Nombre producto                 │
│  Imagenes            │  ───────────────                 │
│                      │  displayProductAdditionalInfo     │
│  displayAfterProduct │  Precio · Descuento              │
│  Thumbs              │  ───────────────                 │
│                      │  displayProductPriceBlock         │
│                      │  ───────────────                 │
│                      │  Cantidad  [+][-]                │
│                      │  displayProductButtons            │
│                      │  [Anadir al carrito]             │
│                      │  displayProductActions            │
│                      │  ───────────────                 │
│                      │  Envio, devolucion, etc.         │
│                      │  displayReassurance               │
├──────────────────────┴──────────────────────────────────┤
│  Tabs:                                                  │
│  [Descripcion] [Detalles] [Tab custom...]               │
│  displayProductExtraContent ← aqui se anaden tabs       │
│                                                         │
│  Contenido del tab activo                               │
├─────────────────────────────────────────────────────────┤
│  displayProductFooter                                   │
│  Productos relacionados / accesorios                    │
├─────────────────────────────────────────────────────────┤
│  displayFooterProduct                                   │
│  displayFooter                                          │
└─────────────────────────────────────────────────────────┘

#displayProductAdditionalInfo

Se muestra justo debajo del nombre del producto y encima del precio. Ideal para: referencias, stock badges, seller info, valoraciones.

Mostrar referencia y stock badge
php
<?php
public function hookDisplayProductAdditionalInfo($params)
{
    $product = $params['product'];

    // Acceder a datos del producto
    $reference = $product['reference'] ?? $product->reference ?? '';
    $quantity  = StockAvailable::getQuantityAvailableByProduct(
        (int) ($product['id_product'] ?? $product->id)
    );

    $this->context->smarty->assign([
        'reference' => $reference,
        'stock_qty' => $quantity,
        'stock_class' => $quantity > 10 ? 'in-stock' : ($quantity > 0 ? 'low-stock' : 'out-of-stock'),
    ]);

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

#displayProductButtons

Se ejecuta junto al selector de cantidad y boton de carrito. Perfecto para: wishlist, comparar, compartir, preguntar sobre producto.

Boton 'Anadir a favoritos'
php
<?php
public function hookDisplayProductButtons($params)
{
    $idProduct = (int) ($params['product']['id_product'] ?? $params['product']->id);
    $isLogged = $this->context->customer->isLogged();
    $inWishlist = false;

    if ($isLogged) {
        $inWishlist = Db::getInstance()->getValue(
            'SELECT COUNT(*) FROM `' . _DB_PREFIX_ . 'ecom_wishlist`
             WHERE id_customer = ' . (int) $this->context->customer->id . '
             AND id_product = ' . $idProduct
        ) > 0;
    }

    $this->context->smarty->assign([
        'id_product'  => $idProduct,
        'in_wishlist' => $inWishlist,
        'is_logged'   => $isLogged,
        'ajax_url'    => $this->context->link->getModuleLink($this->name, 'ajax'),
    ]);

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

#displayProductExtraContent

Este hook es especial: NO devuelve HTML directo. Devuelve un array de objetos PrestaShop\PrestaShop\Core\Product\ProductExtraContent. Cada objeto genera un tab automaticamente.

Anadir tabs personalizados a la ficha de producto
php
<?php
use PrestaShop\PrestaShop\Core\Product\ProductExtraContent;

public function hookDisplayProductExtraContent($params)
{
    $idProduct = (int) $params['product']->id;
    $tabs = [];

    // Tab 1: Guia de tallas
    $sizeGuide = new ProductExtraContent();
    $sizeGuide->setTitle('Guia de tallas');

    $this->context->smarty->assign(['id_product' => $idProduct]);
    $sizeGuide->setContent(
        $this->display(__FILE__, 'views/templates/hook/size-guide.tpl')
    );
    $tabs[] = $sizeGuide;

    // Tab 2: Reviews (si hay)
    $reviews = $this->getProductReviews($idProduct);
    if (!empty($reviews)) {
        $reviewTab = new ProductExtraContent();
        $reviewTab->setTitle('Opiniones (' . count($reviews) . ')');
        $this->context->smarty->assign(['reviews' => $reviews]);
        $reviewTab->setContent(
            $this->display(__FILE__, 'views/templates/hook/reviews.tpl')
        );
        $tabs[] = $reviewTab;
    }

    // Tab 3: Documentacion tecnica (si el producto tiene archivos adjuntos)
    $attachments = Product::getAttachmentsStatic(
        $this->context->language->id, $idProduct
    );
    if (!empty($attachments)) {
        $docsTab = new ProductExtraContent();
        $docsTab->setTitle('Documentacion');
        $this->context->smarty->assign(['attachments' => $attachments]);
        $docsTab->setContent(
            $this->display(__FILE__, 'views/templates/hook/docs.tpl')
        );
        $tabs[] = $docsTab;
    }

    return $tabs;
}

#displayAfterProductThumbs

Se muestra debajo de las miniaturas de imagen del producto. Ideal para: video del producto, vista 360, imagen de garantia.

Incrustar video de YouTube del producto
php
<?php
public function hookDisplayAfterProductThumbs($params)
{
    $idProduct = (int) $params['product']->id;

    // Obtener URL de video guardada como feature del producto
    $videoUrl = Db::getInstance()->getValue(
        'SELECT fvl.value
         FROM `' . _DB_PREFIX_ . 'feature_product` fp
         JOIN `' . _DB_PREFIX_ . 'feature_value_lang` fvl
           ON fp.id_feature_value = fvl.id_feature_value
           AND fvl.id_lang = ' . (int) $this->context->language->id . '
         JOIN `' . _DB_PREFIX_ . 'feature_lang` fl
           ON fp.id_feature = fl.id_feature AND fl.id_lang = fvl.id_lang
         WHERE fp.id_product = ' . $idProduct . '
           AND fl.name = "Video"'
    );

    if (empty($videoUrl)) {
        return '';
    }

    // Extraer ID de YouTube
    preg_match('/(?:youtu\.be\/|youtube\.com\/(?:watch\?v=|embed\/))([\w-]+)/', $videoUrl, $m);
    $youtubeId = $m[1] ?? '';

    if (empty($youtubeId)) {
        return '';
    }

    $this->context->smarty->assign(['youtube_id' => $youtubeId]);
    return $this->display(__FILE__, 'views/templates/hook/product-video.tpl');
}

#displayProductActions

Se muestra justo despues del boton 'Anadir al carrito'. Usos comunes: compartir en redes, anadir a lista, notificar cuando haya stock.

#Ejemplo completo: tabs personalizados

views/templates/hook/size-guide.tpl
smarty
<div class="ecom-size-guide">
  <h4>{l s='Guia de tallas' mod='ecom_productplus'}</h4>
  <table class="table table-striped">
    <thead>
      <tr>
        <th>{l s='Talla' mod='ecom_productplus'}</th>
        <th>{l s='Pecho (cm)' mod='ecom_productplus'}</th>
        <th>{l s='Cintura (cm)' mod='ecom_productplus'}</th>
        <th>{l s='Cadera (cm)' mod='ecom_productplus'}</th>
      </tr>
    </thead>
    <tbody>
      <tr><td>S</td><td>86-91</td><td>71-76</td><td>91-97</td></tr>
      <tr><td>M</td><td>97-102</td><td>81-86</td><td>102-107</td></tr>
      <tr><td>L</td><td>107-112</td><td>91-97</td><td>107-112</td></tr>
      <tr><td>XL</td><td>117-122</td><td>102-107</td><td>117-122</td></tr>
    </tbody>
  </table>
</div>

#Ejemplo: badge de producto

Mostrar badges: nuevo, mas vendido, descuento
php
<?php
public function hookDisplayProductAdditionalInfo($params)
{
    $product = $params['product'];
    $badges = [];

    // Badge "Nuevo" — productos de los ultimos 20 dias
    $nbDaysNew = (int) Configuration::get('PS_NB_DAYS_NEW_PRODUCT') ?: 20;
    $dateNew = date('Y-m-d', strtotime("-{$nbDaysNew} days"));
    if (isset($product['date_add']) && $product['date_add'] > $dateNew) {
        $badges[] = ['label' => 'Nuevo', 'class' => 'badge-new'];
    }

    // Badge "Descuento"
    $hasDiscount = isset($product['has_discount']) && $product['has_discount'];
    if ($hasDiscount) {
        $pct = $product['discount_percentage'] ?? '';
        $badges[] = ['label' => $pct ? "-{$pct}" : 'Oferta', 'class' => 'badge-sale'];
    }

    // Badge "Mas vendido" — top 10 de su categoria
    $idProduct = (int) ($product['id_product'] ?? $product->id);
    $isBestseller = Db::getInstance()->getValue(
        'SELECT COUNT(*) FROM (
            SELECT ps.id_product
            FROM `' . _DB_PREFIX_ . 'product_sale` ps
            ORDER BY ps.quantity DESC LIMIT 10
        ) top WHERE top.id_product = ' . $idProduct
    );
    if ($isBestseller) {
        $badges[] = ['label' => 'Top ventas', 'class' => 'badge-best'];
    }

    if (empty($badges)) {
        return '';
    }

    $this->context->smarty->assign(['badges' => $badges]);
    return $this->display(__FILE__, 'views/templates/hook/product-badges.tpl');
}
Descargar en Markdown Pensado para pegar en ChatGPT, Claude u otra IA. Incluye solo el contenido de esta pagina.