Verificado con PrestaShop 9.0 y el tema predeterminado Hummingbird 2.0 (Bootstrap 5.3, SCSS, nombres de clase de estilo BEM), además del tema Classic en PrestaShop 1.7/8.

Lee la guía de temas hijo: Usa la guía completa para planificar un tema hijo mantenible para Classic, Hummingbird o Warehouse, con cobertura de custom.css, sobrescrituras de plantillas y configuración de SCSS. Abrir la guía de temas hijo.

Esta es la parte 2 de la serie Arquitectura de PrestaShop. La parte 1 cubre la vista general completa de la estructura de carpetas.

Qué controla el directorio /themes/

Cada píxel del front office de tu tienda pasa por el directorio /themes/. Cuando un cliente visita una página de producto, PrestaShop no renderiza HTML directamente desde PHP: carga una plantilla Smarty desde tu tema activo, la rellena con datos de controladores y hooks, la compila y envía el resultado. El tema controla la estructura HTML, los estilos CSS, el comportamiento JavaScript e incluso qué hooks se muestran y dónde.

Entender cómo funciona este directorio significa entender cómo PrestaShop construye cada página que ven tus clientes.

Estructura de directorios de un tema

themes/
  classic/                          <-- PS 1.7/8 default
  hummingbird/                      <-- PS 9 default
  my-child-theme/                   <-- your customizations

  [active-theme]/
    config/
      theme.yml                     <-- theme identity, assets, layouts
    templates/
      catalog/
        product.tpl                 <-- product page
        listing/
          category.tpl              <-- category listing
          product-list.tpl          <-- product grid/list
      checkout/
        cart.tpl                    <-- shopping cart
        checkout.tpl                <-- checkout flow
        order-confirmation.tpl      <-- thank-you page
      cms/
        page.tpl                    <-- CMS content pages
      customer/
        my-account.tpl              <-- customer dashboard
        addresses.tpl               <-- address management
        history.tpl                 <-- order history
      errors/
        404.tpl                     <-- page not found
        maintenance.tpl             <-- maintenance mode
      _partials/
        head.tpl                    <-- <head> section, meta, CSS
        header.tpl                  <-- site header, navigation
        footer.tpl                  <-- site footer
        notifications.tpl           <-- success/error messages
        breadcrumb.tpl              <-- breadcrumb navigation
        pagination.tpl              <-- list pagination
      layouts/
        layout-full-width.tpl       <-- full-width page layout
        layout-left-column.tpl      <-- with left sidebar
        layout-right-column.tpl     <-- with right sidebar
        layout-both-columns.tpl     <-- both sidebars
    assets/
      css/
        theme.css                   <-- main compiled stylesheet
        custom.css                  <-- user overrides (if theme supports it)
      js/
        theme.js                    <-- main compiled JavaScript
        custom.js                   <-- user scripts
      img/
        logo.png                    <-- store logo
        favicon.ico                 <-- browser tab icon
    modules/
      ps_featuredproducts/
        views/templates/hook/
          ps_featuredproducts.tpl    <-- theme override of module template
    translations/
      en-US/
        Shop/Theme/Global.xlf       <-- theme-specific translations
    preview.png                     <-- 200x200 theme preview

Cómo resuelve PrestaShop las plantillas

Pantalla de tema y logotipo de PrestaShop que muestra el tema activo

El tema activo decide qué árbol de plantillas resuelve PrestaShop primero.

Cuando un controlador necesita renderizar una página, PrestaShop busca la plantilla en un orden concreto. Entender ese orden es crítico: determina qué archivo renderiza realmente tu página.

Orden de resolución de plantillas (de mayor a menor prioridad):

  • Tema hijo -- themes/my-child/templates/catalog/product.tpl
  • Tema padre -- themes/classic/templates/catalog/product.tpl

Resolución de plantillas de módulos (para hooks):

  • Sobrescritura del módulo en el tema hijo -- themes/my-child/modules/ps_featuredproducts/views/templates/hook/ps_featuredproducts.tpl
  • Sobrescritura del módulo en el tema padre -- themes/classic/modules/ps_featuredproducts/views/templates/hook/ps_featuredproducts.tpl
  • Plantilla propia del módulo -- modules/ps_featuredproducts/views/templates/hook/ps_featuredproducts.tpl

Este sistema de reserva de tres niveles es lo que hace posibles los temas hijo: solo incluyes los archivos que quieres cambiar, y todo lo demás cae en el tema padre. También es lo que permite las sobrescrituras de módulos basadas en el tema: un tema puede rediseñar por completo cómo se renderiza un módulo sin tocar los archivos propios del módulo.

Implicación práctica que debes entender: cuando un tema sobrescribe una plantilla de módulo, la sobrescritura tiene prioridad absoluta. Si el módulo publica una actualización que corrige un problema de seguridad en su plantilla, la sobrescritura de tu tema seguirá sirviendo la versión antigua. Debes comparar y actualizar manualmente las sobrescrituras del tema cuando se actualicen los módulos. Este es el coste de mantenimiento oculto de las sobrescrituras de tema que la mayoría de la documentación pasa por alto.

Cómo se renderiza una página: de la petición al HTML

Esta es la secuencia exacta cuando un cliente visita /en/product/linear-drain-800mm:

  • Apache/Nginx recibe la petición y la reescribe mediante .htaccess hacia index.php
  • El bootstrap de PrestaShop carga config/config.inc.php e inicializa el Dispatcher
  • Dispatcher analiza la URL e identifica el controlador: ProductController
  • ProductController::init() carga los datos del producto desde la base de datos
  • ProductController::initContent() asigna variables de Smarty ($product, $combinations, etc.)
  • Ejecución de hooks -- el controlador llama a Hook::exec('displayProductAdditionalInfo') y a otros hooks. Cada módulo registrado ejecuta su método de hook, que normalmente asigna sus propias variables de Smarty y devuelve HTML renderizado.
  • Selección de plantilla -- el controlador llama a $this->setTemplate('catalog/product'). PrestaShop resuelve esto hasta la ruta real del archivo usando el orden de resolución anterior.
  • Envoltura de layout -- la plantilla de producto se renderiza dentro de una plantilla de layout (layouts/layout-full-width.tpl). El layout incluye _partials/head.tpl, _partials/header.tpl, el contenido de la página y _partials/footer.tpl.
  • Compilación de Smarty -- Smarty compila los archivos .tpl en PHP y guarda el resultado en caché en var/cache/prod/smarty/compile/. Las peticiones posteriores omiten la compilación y usan directamente el PHP en caché.
  • Salida HTML -- la plantilla compilada se ejecuta, produce HTML y PrestaShop lo envía al navegador con las referencias CSS/JS.

Toda la cadena suele tardar 200-500 ms en un servidor bien configurado. De ese tiempo, la compilación de plantillas supone 0 ms en peticiones cacheadas (se reutiliza el PHP compilado) y 50-100 ms en la primera petición después de limpiar la caché.

theme.yml: el archivo de configuración del tema

Una configuración mínima de tema hijo es lo bastante pequeña como para leerla de un vistazo:

parent: hummingbird
name: my-child
display_name: My Child Theme
version: 1.0.0
assets:
  use_parent_assets: true

El archivo config/theme.yml define todo lo relativo a tu tema: su identidad, relación con el tema padre, registro de recursos, asignaciones de layout y configuración de hooks.

parent: classic                     <-- child theme inherits from this
name: my-child-theme                <-- directory name (must match)
display_name: My Custom Theme       <-- human-readable name
version: 1.0.0
author:
  name: "Your Name"
  email: "you@example.com"

meta:
  compatibility:
    from: 1.7.0.0
    to: ~                           <-- no upper limit

assets:
  use_parent_assets: true           <-- inherit CSS/JS from parent
  css:
    all:
      - id: custom-styles
        path: assets/css/custom.css
        media: all
        priority: 200               <-- higher = loaded later
  js:
    all:
      - id: custom-scripts
        path: assets/js/custom.js
        priority: 200

theme_settings:
  default_layout: layout-full-width
  layouts:
    category: layout-left-column
    product: layout-full-width
    checkout: layout-full-width

Campos críticos:

  • parent -- establece la cadena de herencia. Sin esto, PrestaShop trata el tema como independiente y no recurre a ninguna plantilla padre.
  • use_parent_assets: true -- carga el CSS y el JS del tema padre antes que los tuyos. Ponlo en false solo si quieres sustituir por completo los estilos del tema padre (es poco habitual, y tendrás que proporcionarlo todo tú mismo).
  • priority en los recursos -- controla el orden de carga. Los recursos del tema padre suelen tener prioridad 100. Asigna 200 o más a los recursos de tu tema hijo para asegurarte de que se cargan al final y pueden sobrescribir los estilos del padre.
  • layouts -- asigna tipos de página a plantillas de layout. Así puedes tener una barra lateral en las páginas de categoría y ancho completo en las páginas de producto.

El flujo de recursos: cómo llegan CSS y JS al navegador

El sistema de recursos de PrestaShop tiene varias capas, y entenderlas evita los problemas más comunes de "mis cambios de CSS no aparecen".

Fuentes de registro de recursos (en orden de carga):

  • Recursos de theme.yml -- registrados en el archivo de configuración del tema
  • Recursos de módulos -- registrados mediante $this->context->controller->registerStylesheet() o registerJavascript() en los métodos de hook del módulo
  • Recursos específicos del controlador -- registrados en el método setMedia() del controlador

La capa CCC (Combinar, Comprimir, Cachear):

Cuando CCC está activado (panel de administración > Parámetros avanzados > Rendimiento), PrestaShop:

  • Combina todos los archivos CSS en uno (o unos pocos) archivos combinados
  • Minifica el CSS combinado
  • Nombra la salida con un hash de contenido: themes/classic/assets/cache/combined-abc123.css
  • Hace lo mismo con JavaScript

Esto significa que, después de editar un archivo CSS, debes incrementar la versión de caché (PS_CCCCSS_VERSION en ps_configuration) o eliminar los archivos combinados en themes/*/assets/cache/. De lo contrario, el navegador seguirá cargando el archivo combinado antiguo porque el nombre del archivo no ha cambiado.

Esta es la causa número 1 de "he cambiado el CSS pero no ha pasado nada" en PrestaShop. No es un bug: es el sistema de caché funcionando como fue diseñado. Para cambios en SCSS, vuelva a compilar primero el CSS; después limpie la caché CCC si está activada y fuerce una recarga del navegador sin caché.

Motor de plantillas Smarty: lo que deben saber los desarrolladores de módulos

PrestaShop usa Smarty 3/4 para las plantillas del front office. Conceptos clave:

Asignación de variables: los controladores y módulos asignan datos a Smarty, y después las plantillas los renderizan.

// In PHP (controller or module hook):
$this->context->smarty->assign('my_data', $someArray);

// In .tpl template:
{$my_data.name}
{$my_data.price|number_format:2}

Sistema de bloques: las plantillas definen bloques con nombre que las plantillas hijas pueden sobrescribir.

// Parent template (classic/templates/catalog/product.tpl):
{block name='product_description'}
  <div class="product-description">{$product.description nofilter}</div>
{/block}

// Child template (my-child/templates/catalog/product.tpl):
{extends file='parent:catalog/product.tpl'}
{block name='product_description'}
  <div class="custom-description">
    {$product.description_short nofilter}
    <hr>
    {$product.description nofilter}
  </div>
{/block}

El prefijo parent: es obligatorio en {extends}. Sin él, Smarty encuentra el propio archivo del tema hijo y entra en un bucle infinito que termina por agotar el tiempo de espera. Este es el error más común en temas hijo.

El modificador nofilter: por defecto, Smarty escapa automáticamente las variables para prevenir XSS. Para variables que contienen HTML (como las descripciones de producto), debes usar {$var nofilter}. Sin él, las etiquetas HTML aparecen como texto literal en la página.

Renderizado de hooks en plantillas:

{hook h='displayProductAdditionalInfo' product=$product}
{hook h='displayFooter'}
{widget name='ps_emailsubscription' hook='displayFooter'}

La etiqueta {hook} llama a Hook::exec(), que ejecuta todos los módulos registrados en ese hook y concatena su salida. La etiqueta {widget} llama al método widget de un módulo concreto, independientemente de su registro en hooks.

Classic frente a Hummingbird: diferencias arquitectónicas

AspectoClassic (PS 1.7/8)Hummingbird (PS 9)
Framework CSSBootstrap 4.6Bootstrap 5.3
Arquitectura CSSEspecificidad planaCSS Layers (@layer)
JavaScriptjQuery + JavaScript nativoTypeScript + jQuery (compat)
Sistema de compilaciónWebpack 4Webpack 5
Propiedades personalizadas CSSMínimasAmplias (--bs-*)
Nomenclatura de clasesBEM/Bootstrap mixtoSimilar a BEM (.product__name)
Modo oscuroNo compatibleCompatibilidad basada en variables CSS
Formato de imagenJPG/PNGWebP por defecto

Las CSS Layers en Hummingbird cambian de forma fundamental cómo funciona la especificidad:

@layer vendors, bs-base, bs-components, bs-custom-components,
       ps-base, ps-components, ps-pages, ps-modules, utilities;

Los estilos de capas posteriores sobrescriben a los de capas anteriores independientemente de la especificidad del selector. Un simple .product__name { color: red; } en la capa ps-components gana a un selector muy específico #content .product-container .product__name { color: blue; } en la capa bs-components. Esto elimina las guerras de !important, pero exige entender a qué capa pertenece tu CSS.

Para desarrolladores de módulos que apuntan a ambos temas: usa el patrón var(--css-property, fallback-value). En Classic, las propiedades personalizadas CSS no están definidas, así que gana el valor de reserva. En Hummingbird, la propiedad personalizada sí está definida y gana ella. Un único archivo CSS sirve correctamente a ambos temas.

El subdirectorio modules/: sobrescrituras de módulos a nivel de tema

El directorio themes/[theme]/modules/ es una de las funciones más potentes y más peligrosas de PrestaShop. Permite que un tema sustituya por completo cómo renderiza sus plantillas cualquier módulo.

themes/my-child/modules/
  ps_featuredproducts/
    views/templates/hook/
      ps_featuredproducts.tpl        <-- replaces the module's own template
  ps_searchbar/
    views/templates/hook/
      ps_searchbar.tpl               <-- custom search bar rendering

Cuándo usar sobrescrituras de módulos en el tema:

  • La estructura HTML del módulo no encaja con tu diseño
  • Necesitas añadir o eliminar elementos de la salida del módulo
  • Quieres cambiar la lógica Smarty (mostrar/ocultar según condiciones)

Cuándo NO usar sobrescrituras de módulos en el tema:

  • Solo quieres cambiar CSS: usa en su lugar el CSS de tu tema hijo
  • El módulo ofrece opciones de configuración para lo que quieres cambiar: usa primero esas opciones
  • Estás sobrescribiendo un módulo que actualizas con frecuencia: cada actualización exige revisar de nuevo la sobrescritura

La trampa de mantenimiento: mantenemos 159 módulos. Cuando un módulo actualiza su plantilla para corregir un bug o añadir una función, las tiendas con sobrescrituras de tema de esa plantilla nunca ven la corrección. La sobrescritura sirve en silencio la versión antigua. Lo vemos con regularidad en soporte: "la función no funciona después de actualizar" acaba siendo una sobrescritura de tema obsoleta de hace 3 versiones. La solución siempre es: hacer un diff de la sobrescritura contra la plantilla actual del módulo, fusionar los cambios o eliminar la sobrescritura por completo.

Implicaciones de rendimiento de la arquitectura de temas

Las decisiones de tema impactan directamente en el tiempo de carga de la página:

  • Compilación de plantillas: la primera petición después de limpiar la caché compila todos los archivos .tpl a PHP. Un tema con 50 archivos de plantilla tarda 50-100 ms más en la primera carga. Peticiones posteriores: 0 ms (el PHP compilado está en caché).
  • Número de recursos: cada archivo CSS/JS es una petición HTTP (sin CCC). 15 archivos CSS separados = 15 peticiones. Con CCC activado: 1-2 peticiones. Activa siempre CCC en producción.
  • Tamaños de imagen: el theme.yml del tema define tipos de imagen (home_default: 250x250, large_default: 800x800). Usar tipos de imagen sobredimensionados en páginas de listado (por ejemplo, large_default para miniaturas de categoría) desperdicia ancho de banda. Usa el tipo más pequeño que se vea bien.
  • Densidad de hooks: cada llamada {hook} en una plantilla ejecuta todos los módulos registrados. Una cabecera con 5 hooks, cada uno con 3 módulos, ejecuta 15 métodos de hook de módulos por carga de página. Desinstala los módulos que no uses; incluso si están desactivados, algunos siguen registrando hooks.
  • Smarty nocache: el contenido dentro de bloques {nocache}...{/nocache} nunca se cachea por Smarty y se evalúa de nuevo en cada petición. Úsalo con moderación: normalmente solo para datos específicos del usuario, como el número de artículos del carrito o el estado de inicio de sesión.

Problemas habituales de /themes/ y soluciones

ProblemaCausaSolución
Los cambios de CSS no aparecenCCC está sirviendo un archivo combinado cacheadoElimina themes/*/assets/cache/*, incrementa PS_CCCCSS_VERSION
Los cambios de plantilla no aparecenCaché de compilación de Smartyrm -rf var/cache/prod/smarty/compile/*
Bucle infinito / tiempo de espera agotado{extends} sin el prefijo parent:Usa {extends file='parent:catalog/product.tpl'}
Las etiquetas HTML se muestran como textoEscape automático de SmartyUsa {$var nofilter} para variables HTML
Falta una función del módulo después de actualizarSobrescritura de módulo de tema obsoletaHaz un diff entre la sobrescritura y la plantilla del módulo, actualiza o elimina la sobrescritura
Página en blanco después de cambiar de temaFalta theme.yml o el parent es incorrectoRevisa la configuración, verifica que existe el tema padre
Las fuentes no carganRuta relativa incorrecta en @font-faceLa ruta debe ser relativa a la ubicación del archivo CSS
El diseño móvil está rotoFalta la meta viewport o la rejilla de Bootstrap es incorrectaRevisa _partials/head.tpl para la viewport, verifica las clases responsive

Archivos de este directorio que deberías entender

Si desarrollas módulos o personalizas temas, estos son los archivos que merece la pena leer (en el tema padre):

  • templates/_partials/head.tpl -- donde se generan el CSS y las metaetiquetas. Entenderlo te ayuda a depurar hojas de estilo que no aparecen.
  • templates/layouts/layout-full-width.tpl -- el envoltorio de la página. Te muestra el esqueleto HTML: cabecera, área de contenido, pie de página y posiciones de hooks.
  • templates/catalog/product.tpl -- la plantilla más compleja. Muestra todos los bloques de la página de producto, posiciones de hooks y variables de datos disponibles.
  • config/theme.yml -- la fuente de verdad para recursos, layouts y configuración del tema.
  • assets/css/theme.css -- léelo (no lo edites) para entender los nombres de clase del tema padre y sus patrones de especificidad.

Preguntas frecuentes

¿Puedo editar directamente el tema Classic o Hummingbird en vez de crear un tema hijo?

Puedes, pero no deberías. Los temas predeterminados se sobrescriben en las actualizaciones del núcleo de PrestaShop, así que cualquier cambio que hagas en themes/classic/ o themes/hummingbird/ se pierde la próxima vez que actualices. Un tema hijo (su propia carpeta con parent: definido en theme.yml) mantiene tus cambios en un directorio separado que el actualizador nunca toca, y solo llevas contigo los pocos archivos que realmente has cambiado. Para ajustes puntuales de CSS, basta con un custom.css en tu tema hijo; recurre a una sobrescritura completa de plantilla solo cuando necesites cambiar la estructura HTML.

¿Por qué mis cambios de SCSS o CSS no aparecen incluso después de guardar el archivo?

Hay dos cachés entre tu edición y el navegador. Primero, el CSS del tema suele compilarse desde SCSS durante la compilación, así que editar a mano el theme.css compilado se sobrescribe en la siguiente compilación: edita el código fuente SCSS y recompila, o usa custom.css. Segundo, si CCC está activado (Parámetros avanzados > Rendimiento), PrestaShop sirve un archivo combinado con hash desde themes/*/assets/cache/ y no recogerá tu cambio hasta que se regenere esa caché. Limpia la caché combinada (o incrementa PS_CCCCSS_VERSION) y después fuerza la recarga del navegador.

¿Hummingbird es un sustituto directo de Classic cuando migro a PrestaShop 9?

No. Hummingbird está construido sobre Bootstrap 5.3 con ordenación CSS mediante @layer y nombres de clase de estilo BEM, mientras que Classic usa Bootstrap 4.6 con especificidad plana. Los nombres de clase, las utilidades de rejilla y el modelo de especificidad son diferentes, así que un tema hijo o una sobrescritura de plantilla escrita para Classic no se renderizará correctamente en Hummingbird sin rehacerla. Planifica reconstruir tus personalizaciones sobre Hummingbird en lugar de copiarlas tal cual. El patrón var(--property, fallback) es la única pieza de CSS que puede servir a ambos temas desde un solo archivo.

¿Dónde guarda exactamente PrestaShop las plantillas compiladas, y es seguro eliminarlas?

Las plantillas Smarty compiladas viven en var/cache/prod/smarty/compile/ (y el equivalente de desarrollo en var/cache/dev/). Es seguro eliminar su contenido: PrestaShop recompila en la siguiente petición, con un coste único de 50-100 ms. En PrestaShop 9, no elimines en bruto todo el directorio var/cache/prod/ en una tienda en producción, porque el contenedor Symfony de administración vive bajo var/cache/prod/admin/ y eliminarlo puede romper el back office hasta que se reconstruya. Limpia específicamente la carpeta de compilación de Smarty o usa el botón de limpieza de caché del back office.

Una plantilla de módulo que sobrescribí en mi tema dejó de reflejar la última corrección del módulo. ¿Qué ha pasado?

Es la prioridad de las sobrescrituras de tema funcionando como fue diseñada. Una copia de la plantilla bajo themes/your-child/modules/<module>/views/templates/hook/ tiene prioridad absoluta sobre el archivo propio del módulo, así que cuando el módulo publica una corrección en su plantilla, tu sobrescritura sigue sirviendo la versión antigua. Haz un diff de tu sobrescritura contra la plantilla actual del módulo después de cada actualización, fusiona los cambios relevantes o elimina la sobrescritura si ya no la necesitas.

¿Necesitas que te prepare la estructura padre/hijo? Nuestro Child Theme Generator crea un tema hijo correctamente conectado (con parent:, registro de recursos y estructura de carpetas alineados) para que evites los errores de configuración más comunes. Para mantener CCC y los recursos combinados bajo control en producción, consulta Performance Revolution; y para el mapa de directorios de toda la plataforma, empieza por la guía de estructura de carpetas de PrestaShop.

Para una guía práctica sobre la creación de temas hijo y la personalización de plantillas, consulta nuestra guía de temas hijo en la base de conocimiento.

Siguiente entrega de la serie Arquitectura: análisis a fondo de /modules/ -- el ciclo de vida completo de un módulo, desde install() hasta hookDisplay*(), incluidos scripts de actualización, autoloading y los patrones en los que se apoyan 159 módulos en producción.

David Miller

David Miller

Fundador, mypresta.rocks
Sobre el autor

David Miller es un especialista en PrestaShop con más de una década de experiencia práctica y fundador de mypresta.rocks, un estudio de desarrollo con sede en Tychy, Polonia. Crea y mantiene un catálogo de 159 módulos PrestaShop, incluidas 21 suites «Revolution» que abarcan SEO, checkout, seguridad, rendimiento, marketing, búsqueda, soporte y gestión de almacén, que mejoran tiendas reales cada día, probados en PrestaShop 1.7.8, 8.x y 9.x. También se encarga del mantenimiento de tiendas en producción, por lo que su trabajo se mide por ventas reales, no por demos. Su experiencia abarca todo el comercio electrónico, rendimiento, seguridad, SEO y marketing, y va más allá de PrestaShop, hasta WooCommerce, Shopify y sistemas a medida. En el blog escribe sobre la parte técnica de PrestaShop: qué hace realmente la plataforma, qué se rompe en producción y qué soluciones aguantan.

Compartir esta publicación:

Comentarios

Aún no hay comentarios. ¡Sé el primero!

¿Le gustó este artículo?

Reciba nuestros últimos consejos, guías y actualizaciones de módulos en su bandeja de entrada.

Puedes darte de baja en cualquier momento. Encontrarás nuestros datos de contacto en el aviso legal.

Cargando...
Volver arriba