Guías Guía

Optimización del rendimiento PrestaShop: Acelera tu tienda

Guía completa de optimización: OPcache, ajuste de MySQL, configuración de CCC, optimización de imágenes, estrategias de caché y Core Web Vitals.

La velocidad es un problema de conversión, no una métrica de vanidad

Desarrollamos Performance Revolution, nuestro módulo de caché, Critters y PurgeCSS, y lo ejecutamos en las tiendas de alto tráfico que nosotros mismos operamos. El patrón es desalentadoramente constante: la mayoría de las tiendas PrestaShop son lentas por los mismos cinco motivos, y cuatro de ellos se pueden resolver en una tarde.

La velocidad rinde frutos en tres lugares:

  • Conversiones. En las tiendas Hummingbird que operamos, reducir el LCP mediano de 4 s a 2 s suele aumentar la conversión móvil entre un 30 % y un 60 %.
  • SEO. Google utiliza los Core Web Vitals como señal de posicionamiento desde 2021. Las tiendas lentas obtienen menos tráfico orgánico y pagan más por tráfico de pago para compensarlo.
  • Móvil. El 70 % del tráfico de comercio electrónico es móvil. Una página que parece correcta en un MacBook puede ser una pantalla en blanco de 6 segundos en un Android de gama media.
La velocidad es una disciplina de mantenimiento, no un proyecto que se termina. Cada módulo, cada ajuste del tema, cada imagen la empuja hacia arriba o hacia abajo. Mantenemos una referencia de LCP para cada tienda cliente y la comprobamos después de cada despliegue. Consulte nuestras notas de ajuste de rendimiento para conocer el trabajo de base de datos, caché y medición que hay detrás de esas mejoras.

Mida antes de tocar nada

La forma más rápida de desperdiciar un día es empezar a «optimizar» sin cifras. Cada tienda que auditamos recibe primero la misma medición de tres páginas (página de inicio, categoría, producto), porque cada una pone a prueba una parte distinta del sistema.

Las herramientas que realmente usamos

  • Google PageSpeed Insights: Gratuita, utiliza datos reales de usuarios de Chrome (CrUX). Ejecútela contra los tres tipos de página. Las páginas de categoría y de producto son donde la mayoría de las tiendas flaquean.
  • GTmetrix: La cascada le indica qué solicitud bloquea el renderizado, qué módulo envía 600 KB de CSS sin usar y qué script de terceros añade 800 ms antes del TTFB.
  • WebPageTest: Vista de tira de fotogramas desde distintos continentes y perfiles de conexión. Úsela cuando GTmetrix y PSI no coincidan.

Core Web Vitals: qué le dice cada uno

  • LCP (Largest Contentful Paint): El momento en que termina de pintarse el elemento visible más grande. Objetivo: menos de 2,5 s. En la mayoría de las tiendas PrestaShop es la imagen principal o el banner de categoría, y el verdadero culpable es el CSS que bloquea el renderizado más una imagen sin optimizar y sin precarga.
  • INP (Interaction to Next Paint): Con qué rapidez reacciona la página a un toque o un clic. Sustituyó al FID en marzo de 2024. Objetivo: menos de 200 ms. Los sospechosos habituales: módulos con mucho jQuery, gestores de etiquetas y controladores de clic que hacen demasiado de forma síncrona.
  • CLS (Cumulative Layout Shift): Cuánto salta la página durante la carga. Objetivo: menos de 0,1. Lo causan imágenes sin width/height, banners que cargan tarde y cambios de fuente sin una alternativa equiparada.

Objetivos realistas

Una tienda PrestaShop real con lógica de carrito, búsqueda, módulos y seguimiento no obtendrá un 100. Nuestros objetivos: móvil de 60 a 80, escritorio de 85 a 95, LCP por debajo de 2,5 s en móvil / 1,8 s en escritorio, peso total inferior a 2 MB, menos de 80 solicitudes en el primer renderizado.

No persiga un 98 eliminando lo que le hace ganar dinero. Un 65 con una conversión sana supera a un 98 en una página en la que nadie compra.

Servidor: donde se esconde la mayor parte de la latencia

Ninguna astucia en el front-end le salvará de un backend lento. Si PrestaShop tarda 800 ms en renderizar el HTML antes de que salga una sola solicitud de recursos, ese es su punto de partida.

PHP OPcache: innegociable

OPcache mantiene en memoria el bytecode PHP compilado para que el intérprete no vuelva a analizar los mismos archivos en cada solicitud. PrestaShop carga cientos de archivos PHP por página. Sin OPcache, paga ese coste de análisis cada vez.

opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=1
opcache.revalidate_freq=60
opcache.save_comments=1

Los valores predeterminados son incorrectos para PrestaShop. max_accelerated_files debe ser de al menos 20 000: una instalación típica de PS tiene de 10 000 a 15 000 archivos PHP, y el valor predeterminado de 4000 hace que la mayor parte del código se descarte y se vuelva a analizar. memory_consumption debería estar entre 128 y 256 MB. Si la caché se llena, OPcache expulsa entradas y pierde el beneficio en silencio.

En hostings con cPanel con validate_timestamps=0, OPcache nunca volverá a leer los archivos PHP del disco por sí solo. Debe reiniciarlo mediante una solicitud web después de cada despliegue: un reinicio por CLI solo limpia el pool de CLI, no el pool web. Hemos depurado tickets de «mi corrección no se despliega» que resultaron ser exactamente esto.

MySQL / MariaDB: el único ajuste que importa

Una página de producto de PrestaShop suele ejecutar entre 80 y 200 consultas SQL. Una página de categoría con filtros puede superar las 400. La variable más importante con diferencia es innodb_buffer_pool_size:

[mysqld]
# Ajustar al 50-70 % de la RAM disponible en un servidor de BD dedicado
innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2

# Solo MySQL 5.7 / MariaDB (eliminado en MySQL 8.0)
query_cache_type = 1
query_cache_size = 64M

# Localizar las consultas problemáticas
slow_query_log = 1
long_query_time = 1

# Ajustes de conexión
max_connections = 150
tmp_table_size = 64M
max_heap_table_size = 64M

Si su base de datos ocupa 500 MB y su buffer pool es de 1 GB, la mayoría de las consultas se sirven desde la RAM. Active el registro de consultas lentas y léalo cada semana: una consulta que tarda 1,2 s en reposo tarda 12 s con tráfico, y así es como el Black Friday se descontrola. La mayoría de las consultas lentas que encontramos provienen del controlador de búsqueda, de los filtros de navegación por capas en las páginas de categoría y de módulos de estadísticas que deberían haberse desactivado hace años.

Niveles de hosting: sea honesto consigo mismo

  • Compartido (5-15 $/mes): Comparte CPU y RAM con cientos de vecinos. Adecuado para una tienda de prueba de 200 productos, no para un negocio real.
  • VPS (20-60 $/mes): Donde se alojan casi todas las tiendas que operamos. 4 GB de RAM como mínimo, 2 núcleos, SSD NVMe. El punto ideal hasta unos cientos de pedidos al día.
  • Dedicado (80-300 $/mes): Más de 1000 pedidos diarios o catálogos de más de 100 000 productos. También para quien ejecute su propio sistema de Varnish / Redis.
Si está en hosting compartido y es lento, pasar a un VPS decente le aporta más velocidad que todos los demás consejos de esta página juntos. Hemos visto caer el LCP de 6 s a 2,2 s solo con el cambio de hosting, sin tocar nada más.

PHP-FPM y Redis

Utilice PHP-FPM en lugar de mod_php: pool de procesos independiente, mejor comportamiento de memoria, más fácil de ajustar ante picos de tráfico. Utilice Redis para el almacenamiento de sesiones y caché en lugar del sistema de archivos. La configuración está en app/config/parameters.php:

'ps_cache_enable' => true,
'ps_caching' => 'CacheRedis',

Los interruptores integrados de PrestaShop

La página Rendimiento en el back office de PrestaShop 8.

Aquí residen la caché de Smarty, el modo de depuración, el CCC y el motor de caché. La mayor parte del ajuste de rendimiento empieza aquí.

Página Rendimiento del back office de PrestaShop 8 que muestra los ajustes de Smarty, modo de depuración, CCC y caché

CCC (Combinar, Comprimir, Cachear)

En Parámetros avanzados → Rendimiento. El CCC concatena y minifica su CSS y JS. Actívelo siempre en producción. Cosas que nos han pasado factura:

  • Los archivos marcados como defer o async permanecen separados, por diseño.
  • Los recursos externos (Google Fonts, Stripe.js, scripts de Cloudflare) nunca se combinan.
  • Los módulos que inyectan etiquetas <link> en bruto a través de displayHeader en lugar de actionFrontControllerSetMedia eluden el CCC por completo. Toda auditoría descubre al menos uno. Nuestra página sobre hooks explica cómo solucionarlo.
  • Si el CCC rompe el proceso de compra o un widget, el módulo está haciendo algo que depende del orden. Localícelo, corríjalo o sustitúyalo, pero no deje el CCC desactivado.

Ajustes de plantillas de Smarty

Configure la caché de plantillas en «Recompilar las plantillas si los archivos han sido modificados» en producción. Nunca en «Forzar la compilación»: eso recompila cada plantilla en cada solicitud, el peor modo posible de Smarty.

Modo de depuración: compruebe esto primero, siempre

El modo de depuración desactiva la mayor parte de la caché, fuerza la recompilación y registra de forma agresiva. En producción el único valor correcto es false:

// En app/config/defines.inc.php: DEBE ser false en producción
define('_PS_MODE_DEV_', false);

Hemos heredado tiendas funcionando en modo de depuración durante meses. La «lentitud misteriosa» desaparece en el momento en que cambiamos el indicador. Compruébelo siempre en la primera pasada de auditoría.

Desactive los módulos que no utiliza

Cada módulo activado le cuesta: entradas en el autocargador, retrollamadas de hooks, posiblemente CSS/JS en cada página, posiblemente consultas a la BD aunque no haya nada que mostrar. Una instalación nueva incluye una larga lista de módulos: la mayoría no le hacen falta.

Recorra Módulos → Gestor de módulos y desinstale (no solo desactive) todo lo que no use activamente. ¿Tres módulos de analítica haciendo el mismo trabajo? Conserve uno. Si necesita una pasada de limpieza estructurada antes de ajustar, Cleanup Revolution ayuda a eliminar restos operativos antes de empezar a medir.

Imágenes: normalmente el 60-80 % del peso de su página

Las mayores y más sencillas mejoras de LCP están aquí. Hemos visto bajar el LCP de la página de inicio de 4,2 s a 1,6 s en una sola tienda con solo regenerar las imágenes en los tamaños adecuados y servir WebP.

WebP y dimensiones sensatas

WebP es entre un 25 % y un 35 % más pequeño que JPEG sin pérdida visible de calidad. PrestaShop 8+ lo admite de forma nativa; en versiones anteriores use conversión en el servidor o un módulo.

El desperdicio más común: archivos de origen de 2000×2000 px servidos en un hueco de miniatura de 300 px. Configure los tipos de imagen en Diseño → Ajustes de imágenes para que coincidan con lo que su tema renderiza realmente. No suba archivos maestros de 4000 px «por si acaso»: 1200 px bastan para el zoom de producto retina.

Carga diferida

Difiera todo lo que esté por debajo del pliegue:

<img src="product.jpg" loading="lazy" width="300" height="300" alt="Product Name">

No aplique carga diferida al logotipo de la cabecera, al banner principal ni a la primera fila de productos. Esos son candidatos a LCP: aplicarles carga diferida le indica a Chrome que desprioritice el elemento por el que le está midiendo. Hemos visto que este único error le cuesta a una tienda 1,5 s de LCP. Para catálogos donde las plantillas del tema son inconsistentes, Automatic SEO Images Lazy Tags puede aplicar el patrón de debajo del pliegue a gran escala.

Regenerar tras un cambio

Después de cambiar las dimensiones de un tipo de imagen, regenérelas desde el back office o la CLI:

php bin/console prestashop:image:regenerate --type=products

Optimizaciones de front-end que de verdad marcan la diferencia

Reduzca las solicitudes HTTP

Abra su cascada. Más de 100 solicitudes es un problema. Los infractores habituales: cada módulo cargando su propio archivo CSS/JS diminuto, Google Fonts con cuatro pesos y cursivas, widgets de compartir en redes sociales que arrastran sus propios SDK, dos gestores de etiquetas peleándose entre sí.

CSS crítico

Los navegadores bloquean el renderizado hasta que se ha descargado cada archivo CSS del <head>. El CSS crítico inserta en el HTML los estilos necesarios para la ventana inicial y luego carga la hoja de estilos completa de forma asíncrona. En móvil esto nos suele recortar entre 1 y 2 s de LCP. Performance Revolution genera el CSS crítico automáticamente mediante Critters y lo mantiene sincronizado cuando cambia el CSS del tema: hacerlo a mano en cada ajuste del tema es una tarea que nunca se llega a hacer.

JavaScript: defer es su aliado

Utilice defer para casi todo: el script se descarga en paralelo, pero no se ejecuta hasta que se ha analizado el HTML. Use async solo para scripts genuinamente independientes, como la analítica. En PrestaShop 1.7+:

$this->context->controller->registerJavascript(
    'module-my-script',
    'modules/mymodule/views/js/front.js',
    ['position' => 'bottom', 'priority' => 200, 'attribute' => 'defer']
);

Fuentes

Las fuentes personalizadas añaden de forma discreta entre 200 y 400 KB. Lo que hacemos en cada tienda:

  • Autoalojarlas en lugar de tirar de Google Fonts: ahorra una búsqueda DNS y un protocolo de enlace TLS.
  • Crear un subconjunto con los caracteres que necesita. Solo latino es entre un 60 % y un 80 % más pequeño que el Unicode completo.
  • font-display: swap para que el texto visible nunca espere por una fuente.
  • Dos pesos como máximo. El 400 y el 700 cubren casi todos los temas.
  • Solo WOFF2: la mejor compresión, soporte universal en los navegadores modernos.
@font-face {
    font-family: 'YourFont';
    src: url('/themes/your-theme/assets/fonts/yourfont.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

Conceptos básicos de CDN

Una CDN sirve archivos estáticos desde servidores cercanos a sus visitantes. Cloudflare es el punto de partida gratuito más obvio. Apunte las imágenes, el CSS y el JS al dominio de la CDN en Parámetros avanzados → Rendimiento → Servidores multimedia.

Optimización de la base de datos

Las bases de datos de PrestaShop se hinchan en silencio. Tablas que estaban bien en el lanzamiento se convierten en lastres tras dos años de carritos abandonados, tráfico de bots y registros de módulos que nadie lee.

Limpie los carritos antiguos

ps_cart y ps_cart_product reciben una fila por visitante, incluido cada bot que rastreó el catálogo. Al cabo de un año estas tablas suelen alcanzar millones de filas, y cada unión contra ellas se ralentiza.

-- Eliminar los productos de carrito de carritos antiguos abandonados (no vinculados a pedidos)
DELETE cp FROM ps_cart_product cp
INNER JOIN ps_cart c ON cp.id_cart = c.id_cart
LEFT JOIN ps_orders o ON c.id_cart = o.id_cart
WHERE o.id_order IS NULL
AND c.date_add < DATE_SUB(NOW(), INTERVAL 3 MONTH);

-- Eliminar los carritos vacíos
DELETE c FROM ps_cart c
LEFT JOIN ps_orders o ON c.id_cart = o.id_cart
LEFT JOIN ps_cart_product cp ON c.id_cart = cp.id_cart
WHERE o.id_order IS NULL AND cp.id_cart IS NULL
AND c.date_add < DATE_SUB(NOW(), INTERVAL 3 MONTH);
Haga primero una copia de seguridad, primero en staging. El patrón LEFT JOIN + IS NULL es lo que protege los carritos que se convirtieron en pedidos: hágalo mal y dejará huérfano el historial de pedidos.

Registros y conexiones

-- Registros de la aplicación
DELETE FROM ps_log WHERE date_add < DATE_SUB(NOW(), INTERVAL 30 DAY);

-- Seguimiento de visitantes
DELETE FROM ps_connections_page WHERE id_connections IN (
    SELECT id_connections FROM ps_connections
    WHERE date_add < DATE_SUB(NOW(), INTERVAL 3 MONTH)
);
DELETE FROM ps_connections WHERE date_add < DATE_SUB(NOW(), INTERVAL 3 MONTH);

-- Registros de invitados huérfanos
DELETE g FROM ps_guest g
LEFT JOIN ps_connections c ON g.id_guest = c.id_guest
WHERE c.id_guest IS NULL;

-- Estadísticas de búsqueda, registros 404, registros de correo
DELETE FROM ps_statssearch WHERE date_add < DATE_SUB(NOW(), INTERVAL 6 MONTH);
DELETE FROM ps_pagenotfound WHERE date_add < DATE_SUB(NOW(), INTERVAL 30 DAY);
DELETE FROM ps_mail WHERE date_add < DATE_SUB(NOW(), INTERVAL 3 MONTH);

Índice de búsqueda

Si usa Elasticsearch, Algolia o cualquier backend de búsqueda externo, las tablas de búsqueda integradas son peso muerto que PrestaShop sigue reconstruyendo:

TRUNCATE TABLE ps_search_index;
TRUNCATE TABLE ps_search_word;

Optimice las tablas y añada índices

Tras grandes eliminaciones, recupere espacio:

OPTIMIZE TABLE ps_cart, ps_cart_product, ps_connections,
    ps_connections_page, ps_guest, ps_log;

Índices que hemos añadido en casi todas las tiendas que auditamos:

-- Compruebe primero los índices existentes: SHOW INDEX FROM ps_cart;
ALTER TABLE ps_cart ADD INDEX idx_cart_date (date_add);
ALTER TABLE ps_connections ADD INDEX idx_conn_date (date_add);
ALTER TABLE ps_orders ADD INDEX idx_orders_ref (reference);
ALTER TABLE ps_product ADD INDEX idx_product_ref (reference);

Ejecute EXPLAIN sobre las consultas de su registro de consultas lentas. Si type dice ALL, la base de datos está haciendo un escaneo completo. El índice adecuado suele convertir una consulta de 4 segundos en 12 ms.

Estrategias de caché

Caché de página completa

La mayor palanca individual de la que dispone. Sin ella, cada solicitud anónima ejecuta toda la pila: cientos de archivos PHP, más de 100 consultas, de 200 a 500 ms de renderizado. Con ella, la misma página sale en 5-20 ms. En las tiendas Hummingbird que operamos, activar la FPC suele recortar el LCP móvil entre 1,2 y 1,8 s, además de todo lo demás.

Varnish es el estándar del sector. La caché FastCGI de nginx es más sencilla si ya ejecuta nginx:

fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=PS:100m inactive=60m;

set $skip_cache 0;
if ($http_cookie ~* "PrestaShop-") { set $skip_cache 1; }
if ($request_uri ~* "/cart|/order|/my-account|/admin") { set $skip_cache 1; }

location ~ \\.php$ {
    fastcgi_cache PS;
    fastcgi_cache_valid 200 10m;
    fastcgi_cache_bypass $skip_cache;
    fastcgi_no_cache $skip_cache;
}

La parte difícil no es activarla, sino la invalidación. Cuando cambia un precio, baja el stock o un administrador edita una categoría, las páginas cacheadas correctas tienen que caducar. Esa complejidad es la razón por la que tantas tiendas nunca activan la FPC. También es lo que Performance Revolution gestiona por usted en PrestaShop.

Caché de objetos y caché del navegador

La caché de objetos (Redis) mantiene los resultados de las consultas en memoria entre solicitudes. Una ganancia menor que la FPC (normalmente reduce entre un 30 % y un 50 % el tiempo de consulta), pero la invalidación es automática, así que es el primer paso seguro.

Las cabeceras de caché del navegador les indican a los navegadores de los visitantes que conserven los archivos estáticos localmente:

# Apache (.htaccess)
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType image/webp "access plus 1 year"
    ExpiresByType text/css "access plus 1 month"
    ExpiresByType application/javascript "access plus 1 month"
    ExpiresByType font/woff2 "access plus 1 year"
</IfModule>

Las cosas que destruyen el rendimiento en silencio

  • Demasiados módulos activados. Cada uno le cuesta: entradas en el autocargador, retrollamadas de hooks, a menudo CSS/JS, a menudo consultas. Una tienda ligera casi siempre supera a una sobrecargada en hardware idéntico. Ningún módulo es gratis.
  • Módulos que cargan recursos en cada página. Un módulo de ventana emergente que solo se dispara en la página de inicio pero envía 150 KB de JS en cada página de producto es puro desperdicio. Examine su cascada en busca de rutas de recursos de módulos donde no deberían estar.
  • Carruseles de imágenes principales. De 3 a 5 imágenes en alta resolución más una biblioteca JS de carrusel, a menudo entre 1 y 5 MB en total, para un componente con el que interactúa menos del 1 % de los usuarios más allá de la primera diapositiva. En casi todos los rediseños los sustituimos por una sola imagen principal estática.
  • Temas distribuidos sin revisión de rendimiento. Bootstrap completo para tres componentes, paquetes sin minificar, sin dimensiones de imagen, scripts síncronos. Pídales a los desarrolladores del tema una puntuación de Lighthouse de la demo antes de comprarlo.
  • Índices ausentes. Una consulta con el índice adecuado se ejecuta en 10 ms; sin él, la misma consulta en hora punta corre durante 5 s y deja en cola todas las solicitudes detrás de ella. No lo notará hasta el Black Friday.

Lista de comprobación de monitorización del rendimiento

Comprobaciones rápidas (5 minutos)

  • PageSpeed Insights en página de inicio, categoría y producto
  • _PS_MODE_DEV_ está en false
  • Smarty no está en «Forzar la compilación»
  • CCC activado
  • OPcache activo según phpinfo()

Mantenimiento mensual (30 minutos)

  • Limpie los carritos abandonados de más de 3 meses
  • Limpie ps_log, ps_connections, ps_connections_page, ps_guest
  • Ejecute OPTIMIZE TABLE en las tablas limpiadas
  • Revise el registro de consultas lentas
  • Desinstale los módulos que no use

Revisión trimestral (2 horas)

  • Prueba completa de GTmetrix desde varias ubicaciones, comparada con el trimestre anterior
  • Revise los Core Web Vitals en Google Search Console
  • Audite los recursos de los módulos en busca de CSS/JS innecesarios
  • Compruebe los tamaños de las imágenes para detectar subidas sobredimensionadas
  • Revise el uso de recursos del servidor (CPU, RAM, E/S de disco)
  • Pruebe en un dispositivo móvil real de gama media, no en el emulador de Chrome
  • Verifique que las cabeceras de caché del navegador siguen en su sitio
  • Compruebe los registros de errores de PHP (las excepciones consumen recursos aunque nadie las vea)

Después de cada despliegue

  • Borre la caché de PrestaShop
  • Reinicie el pool web de OPcache si validate_timestamps=0
  • Prueba rápida de PageSpeed para detectar regresiones
  • Compruebe la consola del navegador en busca de errores de JS
  • Recorra el proceso de compra de principio a fin

Por dónde empezar

Cuatro cosas, en orden: corregir la configuración del servidor (OPcache + buffer pool de InnoDB + PHP-FPM), regenerar y servir las imágenes en los tamaños adecuados en WebP, desinstalar los módulos que no use y limpiar la base de datos. Eso cubre la mayor parte de los problemas de rendimiento que encontramos en las auditorías.

Mida antes y después de cada cambio. Mantenga un breve registro de cambios con lo que hizo y lo que hicieron las cifras. La optimización que importa es la que sus clientes sienten: páginas de producto más rápidas, un proceso de compra ágil. Eso se traduce en confianza, menor tasa de rebote y mayor conversión.

Lecturas relacionadas

Preguntas relacionadas

Cargando...
Volver arriba