Cuando una actualización automática de PrestaShop falla o una instalación empieza a dar errores inexplicables (como el bucle de redirecciones 302 o errores de Symfony), la solución más robusta no es reparar, sino trasplantar.
Esta técnica, conocida como migración quirúrgica, consiste en instalar un PrestaShop limpio y mover únicamente el "corazón" de tu negocio (productos, categorías y clientes). Es el método definitivo tanto para reparar instalaciones dañadas como para realizar una actualización mayor sin arrastrar errores del pasado.
1. Preparación del Entorno
Antes de tocar la base de datos, prepara el nuevo destino:
-
Instalación Limpia: Instala la versión de PrestaShop deseada en una carpeta o base de datos nueva.
-
Verificación: Asegúrate de que el panel de administración (Backoffice) funciona perfectamente.
-
Copia de archivos: Mueve las carpetas de imágenes y archivos de usuario desde la instalación antigua a la nueva:
En el caso de que sea una actualización NUEVA..
-
En el caso de que sea una ACTUALIZACIÓN ENTRE IGUALES VERSIONES.
-
/img/: Contiene todas las fotos de productos, categorías, fabricantes y logos. Es vital.
-
/download/: Si vendes productos virtuales.
-
/upload/: Archivos que los clientes hayan subido.
-
/themes/tu-tema-actual/: La carpeta de tu plantilla.
-
/modules/: Aquí hay un matiz. Copia solo los módulos que hayas comprado o personalizado. No copies los módulos nativos (ps_...), deja que la instalación limpia de la 8.2 instale sus versiones actualizadas.
-
/mails/: Si personalizaste los correos de envío, pedidos, etc.
2. El Script de Extracción (Exportación)
Para evitar el "ruido" de configuraciones corruptas, utilizaremos mysqldump desde la terminal (SSH). Este comando extraerá solo las tablas vitales del catálogo, atributos, clientes y pedidos.
Ejecuta este comando en el servidor de la instalación antigua:
(Servidor de Origen)
Nota: Sustituye usuario y base_de_datos por tus credenciales reales. El archivo resultante migracion_esencial.sql contendrá toda la inteligencia de tu negocio.
3. El Script de Restauración (Importación)
Antes de importar, debemos preparar la base de datos de destino. La nueva instalación ya tiene tablas con datos de ejemplo; si importamos encima, los IDs chocarán.
Paso A: Limpiar tablas de destino
Crea un archivo llamado limpiar_destino.sql con el siguiente contenido y ejecútalo en la base de datos nueva:
(Servidor de destino)
Paso B: Importar los datos
(Servidor de destino)
Ahora, inyecta el archivo que exportamos anteriormente en la base de datos nueva:
4. El "Ancla" de Seguridad: La Cookie Key
Para que las contraseñas de los clientes importados sigan funcionando, debes sincronizar la clave de cifrado.
-
Busca en tu instalación antigua el archivo app/config/parameters.php.
-
Localiza el valor de 'cookie_key'.
-
Pégalo en el archivo app/config/parameters.php de la nueva instalación.
5. Pasos Post-Migración
Una vez completado el trasplante, realiza estas tres acciones en el nuevo panel de administración:
-
Regenerar .htaccess: Ve a Parámetros de la Tienda > Tráfico & SEO y pulsa "Guardar".
-
Limpiar Caché: En Parámetros Avanzados > Rendimiento, limpia la caché de Symfony.
-
Indexar Productos: En Parámetros de la Tienda > Buscar, reconstruye el índice para que el buscador de la web encuentre los productos recién importados.
5. El Proceso de Integración (Post-Trasplante)
Una vez que hayas volcado tus carpetas antiguas (/img, /modules, /themes, /mails) sobre la instalación limpia, el sistema está en un estado "híbrido". Sigue este orden exacto para consolidar la migración:
-
Sincronizar Identidad: Copia el cookie_key del archivo app/config/parameters.php antiguo al nuevo. Sin esto, las contraseñas importadas no funcionarán.
-
Limpieza e Importación SQL: Ejecuta el script de TRUNCATE y luego importa tu migracion_esencial.sql.
-
Regenerar el motor de rutas: Ve a Parámetros de la tienda > Tráfico & SEO, desactiva las "URLs amigables", guarda, y vuelve a activarlas. Esto reconstruye el archivo .htaccess.
-
Reconstruir el índice de búsqueda: Ve a Parámetros de la tienda > Buscar y pulsa en "Añadir los productos que faltan al índice".
6. Script de Comprobación Final (Salud del Sistema)
Para asegurarte de que la migración ha sido exitosa y no quedan "cabos sueltos", hemos preparado este script de verificación. Puedes ejecutar estas consultas SQL para detectar posibles errores de integridad:
-- 1. Verificar si hay productos sin categorías (Productos huérfanos)
SELECT COUNT(*) FROM ps_product p
LEFT JOIN ps_category_product cp ON (p.id_product = cp.id_product)
WHERE cp.id_category IS NULL;
-- 2. Verificar si hay imágenes que no tienen asignado un producto físico
SELECT COUNT(*) FROM ps_image i
LEFT JOIN ps_product p ON (i.id_product = p.id_product)
WHERE p.id_product IS NULL;
-- 3. Comprobar que los clientes tienen su dirección asociada
SELECT c.email, a.alias FROM ps_customer c
LEFT JOIN ps_address a ON (c.id_customer = a.id_customer)
WHERE a.id_address IS NULL;
Verificación de Permisos (Terminal SSH)
Finalmente, ejecuta este comando para asegurar que PrestaShop tiene permisos de escritura en las carpetas que acabas de mover:
Consejo final de ExtreHost: Si tras la migración ves una pantalla en blanco, activa el Modo Depuración en config/defines.inc.php cambiando PS_MODE_DEV a true. Esto te dirá exactamente qué módulo está causando el conflicto en la nueva versión.
Resumen para el Administrador
-
Archivos movidos: OK.
-
Base de Datos inyectada: OK.
-
Cookie Key sincronizada: OK.
-
URLs e Índices regenerados: OK.
¡Tu tienda ahora es una instalación limpia, rápida y libre de errores heredados!
Este método es el más limpio y seguro para dejar atrás errores críticos de sistema. Al tratar los datos como piezas modulares, garantizas que la nueva instalación nazca sana y optimizada.
Situación inicial - Tras el primer paso.
La tienda original funcionaba correctamente. La tienda clonada también arrancaba, cargaba productos, tema, páginas y estructura general. Sin embargo, al abrir el menú “Productos”, la navegación no coincidía con la original.
A simple vista parecía un problema de categorías no clonadas, pero al revisar la base de datos se comprobó que las categorías sí existían. Es decir: el problema no era la ausencia de datos, sino la forma en la que PrestaShop los estaba utilizando en la tienda clonada.
Ese tipo de incidencia es muy habitual en migraciones reales. La información está en base de datos, pero faltan asociaciones internas o configuraciones complementarias que permiten que el front-end la represente correctamente.
Paso 1. Confirmar si las categorías existen realmente en destino
Lo primero fue comprobar si las categorías del menú estaban presentes en la base de datos de la tienda clonada.
Consulta usada:
SELECT c.id_category, cl.name, cs.id_shop
FROM ps_category c
JOIN ps_category_lang cl ON c.id_category = cl.id_category
LEFT JOIN ps_category_shop cs ON c.id_category = cs.id_category
WHERE cl.id_lang = 1
ORDER BY c.id_category;
Con esta verificación se confirmó que categorías como:
- Productos
- Productos Sanitarios
- Cuidado Capilar
- Complemento Alimenticio
- Bebés Y Mamás
- Accesorios del Bebé
- Alimentación del Bebé
y muchas otras, ya existían en la base de datos destino.
Conclusión de este paso: las categorías estaban clonadas. El problema no era su ausencia.
Paso 2. Comprobar si el menú estaba siendo gestionado por el módulo correcto
Cuando una categoría existe pero no aparece correctamente en el menú, el siguiente paso es revisar el sistema que genera esa navegación.
En este caso se revisó si el módulo responsable era ps_mainmenu o algún sistema de menú propio del tema.
Primero se buscó la configuración del menú en ps_configuration, pero la consulta inicial no devolvió resultados:
SELECT *
FROM ps_configuration
WHERE name LIKE '%MAINMENU%';
Esto no significaba necesariamente que el menú no existiera, sino que el módulo podía guardar la configuración con otro nombre.
Después se comprobó directamente qué módulos de menú estaban instalados y en qué hook estaban cargados.
Consulta útil:
SELECT id_module, name, active
FROM ps_module
WHERE name LIKE '%menu%'
OR name LIKE '%mega%'
OR name LIKE '%nav%'
OR name LIKE '%top%'
ORDER BY name;
En la tienda origen apareció ps_mainmenu, y además se confirmó que estaba asociado al hook correcto:
SELECT m.name AS modulo, h.name AS hook, hm.position
FROM ps_hook_module hm
JOIN ps_module m ON hm.id_module = m.id_module
JOIN ps_hook h ON hm.id_hook = h.id_hook
WHERE h.name IN ('displayTop', 'displayNav1', 'displayNav2', 'displayHeader', 'displayHome')
ORDER BY h.name, hm.position;
Resultado relevante:
ps_mainmenu en displayTop
En la tienda destino también existía ps_mainmenu, estaba activo y correctamente enganchado a displayTop.
Conclusión de este paso: el módulo del menú sí estaba presente y cargado correctamente.
Paso 3. Confirmar que el menú estaba apuntando a la categoría correcta
El siguiente paso fue revisar la configuración real del módulo. En PrestaShop, ps_mainmenu no siempre guarda sus valores con el nombre “MAINMENU”, sino frecuentemente con claves relacionadas con BLOCKTOPMENU.
Consulta usada:
SELECT id_configuration, id_shop_group, id_shop, name, value
FROM ps_configuration
WHERE name LIKE '%BLOCKTOPMENU%'
ORDER BY name, id_shop_group, id_shop;
Resultado clave:
MOD_BLOCKTOPMENU_ITEMS = CMS_CAT1,CAT2,LNK1,LNK2,LNK3
Esto significaba que el menú sí estaba configurado para incluir:
- una categoría CMS,
- la categoría
CAT2 (Productos),
- varios enlaces personalizados.
Por tanto, el problema no estaba en que ps_mainmenu apuntara a una categoría equivocada. El menú estaba bien configurado para cargar Productos.
Conclusión de este paso: el módulo sí sabía qué categoría debía mostrar.
Paso 4. Verificar la jerarquía real del árbol de categorías
Cuando el módulo, la categoría principal y la configuración son correctos, el siguiente punto a revisar es el árbol real de categorías: padres, hijos, niveles y profundidad.
Consulta usada:
SELECT c.id_category, c.id_parent, c.level_depth, c.nleft, c.nright, c.active, cl.name
FROM ps_category c
LEFT JOIN ps_category_lang cl
ON c.id_category = cl.id_category AND cl.id_lang = 1
ORDER BY c.id_category;
Después, para centrarse solo en las descendientes de Productos, se utilizó una consulta más precisa:
SELECT c.id_category, c.id_parent, c.level_depth, cl.name
FROM ps_category c
JOIN ps_category_lang cl
ON c.id_category = cl.id_category AND cl.id_lang = 1
WHERE c.nleft > (
SELECT nleft FROM ps_category WHERE id_category = 2
)
AND c.nright < (
SELECT nright FROM ps_category WHERE id_category = 2
)
ORDER BY c.nleft;
Esto permitió confirmar que la jerarquía existía y era coherente. Por ejemplo:
- Productos Sanitarios colgaba de Productos
- Bebés Y Mamás colgaba de Productos
- Accesorios del Bebé colgaba de Bebés Y Mamás
- Alimentación del Bebé colgaba de Bebés Y Mamás
- Biberones, Tetinas y Vajillas colgaban de Accesorios Alimentación
Conclusión de este paso: el árbol de categorías estaba bien definido.
Paso 5. Revisar la categoría raíz y la categoría de inicio
En una clonación de PrestaShop es fundamental comprobar que la tienda mantiene correctamente sus referencias internas a la categoría raíz y a la categoría de inicio.
Consulta usada:
SELECT name, value
FROM ps_configuration
WHERE name IN (
'PS_ROOT_CATEGORY',
'PS_HOME_CATEGORY',
'PS_SHOP_DEFAULT'
);
Resultado:
PS_HOME_CATEGORY = 2
PS_ROOT_CATEGORY = 1
PS_SHOP_DEFAULT = 1
Estos valores eran coherentes con la estructura existente. Por tanto, el problema tampoco estaba ahí.
Conclusión de este paso: la raíz de catálogo era correcta.
Paso 6. Localizar el fallo real: asociaciones faltantes en ps_category_group
Una vez descartados los problemas de menú, de árbol, de jerarquía y de configuración base, quedaba revisar una parte que a menudo se pasa por alto: la asociación de categorías con grupos de clientes.
En PrestaShop, una categoría puede existir, tener padre correcto y estar incluida en el menú, pero si no está asociada a los grupos adecuados, el front-end puede no mostrarla correctamente.
Consulta usada sobre las subcategorías:
SELECT cg.id_category, cg.id_group, cl.name
FROM ps_category_group cg
JOIN ps_category_lang cl
ON cg.id_category = cl.id_category AND cl.id_lang = 1
WHERE cg.id_category IN (10,11,12,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33)
ORDER BY cg.id_category, cg.id_group;
En destino, esta consulta no devolvió nada.
Eso fue el punto decisivo.
La categoría principal Productos sí tenía grupos asignados, pero todas sus hijas y descendientes carecían de asociaciones en ps_category_group. En consecuencia, el menú principal podía mostrar la categoría padre, pero no construir correctamente toda la navegación secundaria y profunda.
Conclusión de este paso: el fallo real no era el menú, sino la falta de asociaciones de las subcategorías con los grupos de clientes.
Paso 7. Aplicar la corrección mínima y segura
En una migración quirúrgica no se cambia todo. Se corrige únicamente lo que falta.
Como la categoría 2 = Productos ya tenía los grupos correctos, lo más limpio era hacer que todas sus descendientes heredaran esos mismos grupos.
Consulta aplicada en destino:
INSERT IGNORE INTO ps_category_group (id_category, id_group)
SELECT hijos.id_category, grupos.id_group
FROM ps_category AS hijos
JOIN ps_category AS padre ON padre.id_category = 2
JOIN ps_category_group AS grupos ON grupos.id_category = 2
WHERE hijos.nleft > padre.nleft
AND hijos.nright < padre.nright;
Esta consulta hace exactamente lo necesario:
- localiza todas las categorías descendientes de
Productos,
- toma los grupos ya asignados a la categoría padre,
- y los replica solo donde faltan.
Sin sobreescribir nada. Sin tocar categorías ajenas. Sin romper lo que ya funciona.
Ese es el espíritu correcto de una migración quirúrgica.
Paso 8. Validar el resultado
Tras aplicar la corrección, se volvió a comprobar la relación entre categorías y grupos.
Consulta de validación:
SELECT c.id_category, c.id_parent, cl.name,
GROUP_CONCAT(cg.id_group ORDER BY cg.id_group SEPARATOR ',') AS grupos
FROM ps_category c
JOIN ps_category_lang cl
ON c.id_category = cl.id_category AND cl.id_lang = 1
LEFT JOIN ps_category_group cg
ON c.id_category = cg.id_category
JOIN ps_category p ON p.id_category = 2
WHERE c.nleft > p.nleft
AND c.nright < p.nright
GROUP BY c.id_category, c.id_parent, cl.name
ORDER BY c.nleft;
Después de la corrección, todas las categorías descendientes de Productos pasaron a quedar correctamente asociadas a los grupos requeridos, y el menú recuperó su comportamiento esperado.
En ese momento, tanto la tienda original como la clonada mostraban ya la misma estructura funcional en el menú de categorías.
Paso 9. Limpiar caché y comprobar el front-end
Como en cualquier intervención de PrestaShop, una vez ajustadas asociaciones o configuraciones internas, es imprescindible vaciar caché.
Dependiendo del entorno, esto puede hacerse desde el panel o directamente sobre el sistema de archivos.
En entornos gestionados por consola, suele ser recomendable limpiar:
rm -rf var/cache/prod/*
rm -rf var/cache/dev/*
Después de ello, se verificó el resultado directamente en el front-end comparando ambas tiendas.
El menú Productos de la tienda clonada volvió a mostrar correctamente toda la estructura de categorías y subcategorías, ya no solo las primeras visibles, sino también niveles más profundos como:
- Bebés Y Mamás
- Accesorios del Bebé
- Accesorios Baño
- Esponjas
- Termómetro
- Chupetes
- Cadenitas
- Látex
- Silicona
- Juguetes
- Alimentación del Bebé
- Biberones
- Tetinas
- Vajillas
- 0-6 Meses
- 6-12 Meses
- 12-18 Meses
- Carne
Resultado final: el menú quedó alineado con la tienda origen.
Qué enseña este caso real
Este caso demuestra una lección importante: en PrestaShop, clonar bien no significa únicamente copiar datos visibles.
Una migración profesional exige revisar también:
- configuración de módulos,
- hooks activos,
- categorías raíz,
- relaciones jerárquicas,
- asociaciones a tienda,
- asociaciones a grupos,
- caché y comportamiento final en front-end.
Muchas incidencias no se deben a que falten productos o categorías, sino a que faltan relaciones internas que hacen posible que la tienda interprete esos datos correctamente.
En este caso, el catálogo existía. El menú también. La estructura jerárquica también. Lo que faltaba era una pieza menos visible, pero decisiva: la tabla ps_category_group.
Conclusión
La diferencia entre una clonación superficial y una migración quirúrgica está precisamente ahí.
Una clonación superficial deja una tienda que “parece funcionar”.
Una migración quirúrgica deja una tienda que funciona de verdad.
El proceso correcto no consiste en tocar módulos al azar ni en rehacer el menú desde cero sin entender qué pasa. Consiste en:
- comprobar si los datos existen,
- identificar qué elemento los consume,
- verificar si las relaciones internas son correctas,
- corregir solo lo que falta,
- validar el resultado final comparando origen y destino.
Cuando se trabaja así, incluso incidencias aparentemente complejas, como la pérdida parcial del menú de categorías tras un clonado, pueden resolverse de forma precisa, segura y sin romper nada de lo que ya estaba bien.
Si tu tienda PrestaShop ha sido clonada, migrada o actualizada y detectas fallos como menús incompletos, categorías invisibles, módulos que no cargan igual o comportamientos distintos entre origen y destino, no siempre hace falta rehacer toda la instalación. Ponte en contacto con nosotros.
En muchos casos, una revisión técnica precisa permite localizar el punto exacto del fallo y reconstruir únicamente lo necesario.
Ese es el objetivo de una migración quirúrgica: rescatar la tienda, conservar lo valioso y devolverle un funcionamiento estable, limpio y coherente.
¿Te ha servido esta guía? En ExtreHost recomendamos siempre realizar una copia de seguridad completa antes de ejecutar scripts SQL. ¡Suerte con tu migración!