Análisis a fondo del directorio /themes/ de PrestaShop: cómo funcionan realmente las plantillas, los recursos y los temas hijo
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

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
.htaccesshaciaindex.php - El bootstrap de PrestaShop carga
config/config.inc.phpe 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
.tplen PHP y guarda el resultado en caché envar/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 enfalsesolo si quieres sustituir por completo los estilos del tema padre (es poco habitual, y tendrás que proporcionarlo todo tú mismo).priorityen 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()oregisterJavascript()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
| Aspecto | Classic (PS 1.7/8) | Hummingbird (PS 9) |
|---|---|---|
| Framework CSS | Bootstrap 4.6 | Bootstrap 5.3 |
| Arquitectura CSS | Especificidad plana | CSS Layers (@layer) |
| JavaScript | jQuery + JavaScript nativo | TypeScript + jQuery (compat) |
| Sistema de compilación | Webpack 4 | Webpack 5 |
| Propiedades personalizadas CSS | Mínimas | Amplias (--bs-*) |
| Nomenclatura de clases | BEM/Bootstrap mixto | Similar a BEM (.product__name) |
| Modo oscuro | No compatible | Compatibilidad basada en variables CSS |
| Formato de imagen | JPG/PNG | WebP 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
.tpla 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.ymldel tema define tipos de imagen (home_default: 250x250,large_default: 800x800). Usar tipos de imagen sobredimensionados en páginas de listado (por ejemplo,large_defaultpara 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
| Problema | Causa | Solución |
|---|---|---|
| Los cambios de CSS no aparecen | CCC está sirviendo un archivo combinado cacheado | Elimina themes/*/assets/cache/*, incrementa PS_CCCCSS_VERSION |
| Los cambios de plantilla no aparecen | Caché de compilación de Smarty | rm -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 texto | Escape automático de Smarty | Usa {$var nofilter} para variables HTML |
| Falta una función del módulo después de actualizar | Sobrescritura de módulo de tema obsoleta | Haz 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 tema | Falta theme.yml o el parent es incorrecto | Revisa la configuración, verifica que existe el tema padre |
| Las fuentes no cargan | Ruta relativa incorrecta en @font-face | La ruta debe ser relativa a la ubicación del archivo CSS |
| El diseño móvil está roto | Falta la meta viewport o la rejilla de Bootstrap es incorrecta | Revisa _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.