Cómo crear un módulo de PrestaShop 9: del esqueleto a producción

64 Views

Un módulo de PrestaShop puede ser extremadamente pequeño.

En su forma más básica, el directorio del módulo contiene un archivo PHP principal con el mismo nombre que el directorio.

Pero un módulo de producción suele necesitar mucho más:

  • servicios;
  • hooks;
  • tablas de base de datos;
  • controladores Symfony;
  • comandos CLI;
  • configuración;
  • registros;
  • scripts de actualización;
  • comprobaciones de seguridad;
  • pruebas.

PrestaShop 9 utiliza Symfony 6.4 y continúa la migración de la plataforma hacia una arquitectura Symfony moderna. Esto hace que un diseño limpio de módulos orientado a servicios sea más importante que nunca.

Esta guía recorre la arquitectura de un módulo de PrestaShop 9 completo sin quedarse en «Hello World».

Nota sobre la versión: Esta guía se verificó el 22 de septiembre de 2026 con la documentación vigente para desarrolladores de PrestaShop 9.

1. Definir la responsabilidad del módulo

Antes de crear archivos, define de qué se encarga el módulo.

Un buen módulo tiene un objetivo de negocio claro.

Ejemplos:

filtrado de stock
importación de proveedor
monitorización de seguridad
reglas de venta adicional
exportación de pedidos

Evita un módulo que poco a poco asuma funciones sin relación entre sí.

Si un mismo módulo incluye:

  • SEO;
  • stock;
  • seguridad;
  • envíos;
  • analítica;
  • importación;

resulta difícil mantenerlo y probarlo.

2. Elegir el nombre técnico

El tutorial de módulos de PrestaShop exige un nombre técnico compuesto por caracteres alfanuméricos en minúsculas.

Por ejemplo:

mymodule

El archivo principal del módulo debe tener el mismo nombre:

/modules/mymodule/mymodule.php

La documentación oficial desaconseja los guiones bajos en los nombres técnicos porque no funcionan bien con los dominios de traducción.

3. Empezar con una estructura de carpetas limpia

Una estructura orientada a producción podría ser así:

mymodule/
├── mymodule.php
├── composer.json
├── config/
│   ├── services.yml
│   └── routes.yml
├── src/
│   ├── Controller/
│   ├── Service/
│   ├── Repository/
│   ├── Command/
│   ├── Domain/
│   └── ApiPlatform/
├── views/
│   ├── templates/
│   ├── css/
│   └── js/
├── sql/
│   ├── install.php
│   └── uninstall.php
├── upgrade/
└── translations/

No necesitas todas las carpetas desde el principio.

Añade estructura cuando surja una responsabilidad.

4. Mantener pequeña la clase principal del módulo

La clase principal del módulo no debe contener toda la lógica de negocio.

Debe coordinar elementos como:

  • metadatos;
  • instalación;
  • registro de hooks;
  • puntos de entrada de configuración.

Evita escribir:

2.000 líneas

dentro de:

class MyModule extends Module

Traslada la lógica de aplicación a servicios.

5. Clase principal básica del módulo

Un módulo mínimo empieza con algo como:

<?php

if (!defined('_PS_VERSION_')) {
    exit;
}

class MyModule extends Module
{
    public function __construct()
    {
        $this->name = 'mymodule';
        $this->version = '1.0.0';
        $this->author = 'Your Company';
        $this->bootstrap = true;

        parent::__construct();

        $this->displayName = $this->l('My Module');
        $this->description = $this->l('Example PrestaShop 9 module.');
    }
}

La clase real de producción suele incluir más metadatos y lógica de instalación.

6. Diseñar la instalación antes que las funciones

Decide qué crea la instalación.

Entre los recursos posibles están:

  • hooks;
  • claves de configuración;
  • tablas de base de datos;
  • pestañas;
  • permisos.

La instalación debe fallar de forma controlada.

Por ejemplo:

public function install()
{
    return parent::install()
        && $this->registerHook('displayHeader')
        && $this->installDatabase();
}

Si falla la creación de la base de datos, no dejes el módulo a medio instalar sin comunicar el problema.

7. Registrar hooks de forma intencionada

Los hooks permiten a los módulos responder a eventos de PrestaShop o mostrar contenido.

La convención de PrestaShop distingue:

actionSomething

de:

displaySomething

Los hooks de acción responden a eventos.

Los hooks de visualización generan contenido.

Registra los hooks durante la instalación:

$this->registerHook('displayHeader');

Después implementa:

public function hookDisplayHeader(array $params)
{
    // logic
}

8. Evitar tareas pesadas en hooks globales

Un hook puede ejecutarse en todas las páginas.

No pongas:

  • solicitudes a la API del proveedor;
  • consultas enormes a la base de datos;
  • análisis completos del catálogo;

dentro de un hook de visualización global.

Lo ideal es que un hook de visualización muestre datos ya preparados.

Si hay que actualizar los datos, utiliza:

  • caché;
  • cron;
  • cola;
  • proceso en segundo plano.

9. Crear servicios para la lógica de negocio

Una clase de servicio debe representar una responsabilidad de la aplicación.

Ejemplo:

ProductSyncService
IntegrityScanner
UpsellRuleEvaluator
StockFilterService

El controlador debe llamar al servicio.

El servicio no debe depender de HTTP salvo que su responsabilidad lo requiera.

Esto permite reutilizar el código desde:

  • Back Office;
  • CLI;
  • cron;
  • API.

10. Utilizar inyección de dependencias

La arquitectura Symfony de PrestaShop 9 admite la inyección de dependencias.

En lugar de:

$repo = new ProductRepository();
$logger = new Logger();

en cada método, inyecta las dependencias.

Conceptualmente:

public function __construct(
    ProductRepository $repository,
    LoggerInterface $logger
) {
    $this->repository = $repository;
    $this->logger = $logger;
}

Entre las ventajas están:

  • facilidad de prueba;
  • dependencias claras;
  • sustitución más sencilla;
  • validación del contenedor.

11. Configurar los servicios

Un archivo de servicios de módulo típico podría utilizar:

services:
  _defaults:
    public: false
    autowire: true
    autoconfigure: true

  Vendor\Module\:
    resource: '../src/'

Ajusta con cuidado los límites de los recursos.

No registres automáticamente clases que no deberían ser servicios.

12. Los controladores de PrestaShop 9 deben ser servicios

La documentación actual de PrestaShop 9 indica expresamente que los controladores modernos deben definirse como servicios.

Un controlador puede configurarse con:

services:
  Vendor\Module\Controller\Admin\ExampleController:
    autowire: true
    autoconfigure: true
    tags:
      - { name: controller.service_arguments }

o mediante los valores predeterminados de los servicios.

Si el controlador no se registra correctamente, fallará.

13. Mantener ligeros los controladores

Un controlador debe:

  1. aceptar la solicitud;
  2. autorizar;
  3. validar la entrada;
  4. llamar al servicio;
  5. devolver la respuesta.

No escribas SQL directo ni lógica de importación dentro de los métodos del controlador.

Los controladores ligeros facilitan:

  • probar;
  • reutilizar;
  • mantener.

14. Utilizar rutas para las páginas modernas

Las páginas modernas del Back Office deben utilizar el enrutamiento Symfony.

Conceptualmente, un archivo de rutas podría ser así:

mymodule_dashboard:
  path: /mymodule/dashboard
  methods: [GET]
  defaults:
    _controller: 'Vendor\Module\Controller\Admin\DashboardController::index'

Utiliza los nombres de rutas de forma coherente.

Evita colisiones con otros módulos.

15. Crear páginas de configuración teniendo en cuenta el ámbito

Un módulo sencillo puede guardar ajustes en la configuración de PrestaShop.

Pero decide si los valores son:

  • globales;
  • del grupo de tiendas;
  • específicos de una tienda.

Los errores multitienda suelen surgir por ignorar el ámbito.

Un ajuste como:

URL de la API del proveedor

puede ser distinto en cada tienda.

Otro ajuste como:

servidor global de licencias

puede ser compartido.

Define primero el significado de negocio.

16. Diseñar tablas de base de datos escalables

Si el módulo necesita persistencia, diseña las tablas según los patrones reales de acceso.

Para una tabla de cola:

CREATE TABLE ps_mymodule_queue (
  id_queue BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  id_shop INT UNSIGNED NOT NULL,
  status VARCHAR(32) NOT NULL,
  payload LONGTEXT NULL,
  attempts INT UNSIGNED NOT NULL DEFAULT 0,
  created_at DATETIME NOT NULL,
  updated_at DATETIME NOT NULL,
  PRIMARY KEY (id_queue)
);

Después pregunta qué consultas se ejecutarán.

Si los procesos de trabajo filtran con frecuencia por:

id_shop + status

añade un índice adecuado.

17. Evitar entradas de usuario directas en SQL

Nunca concatenes valores no fiables en SQL.

Incorrecto:

$sql = "SELECT * FROM table WHERE name = '" . $_GET['name'] . "'";

Utiliza las funciones auxiliares de base de datos de PrestaShop y un escape seguro, o consultas DBAL parametrizadas cuando corresponda.

Los datos del proveedor tampoco son fiables.

Un flujo XML remoto no debe considerarse seguro solo porque proceda de un socio comercial.

18. Añadir scripts de actualización para cambios de esquema

Un módulo de producción evoluciona.

Cuando cambie el esquema, añade lógica de actualización versionada.

Ejemplo:

upgrade/upgrade-1.1.0.php

La actualización debe:

  • realizar un cambio coherente;
  • indicar claramente el fallo;
  • poder volver a ejecutarse de forma segura cuando sea posible.

No ocultes migraciones de base de datos en código de ejecución arbitrario.

19. Separar la versión del código de la lógica de migración de datos

Una corrección que solo cambie PHP no requiere necesariamente una migración de base de datos.

Un cambio de esquema sí.

Ejemplos que requieren migración:

  • nueva tabla;
  • nueva columna;
  • nuevo índice;
  • nueva clave de configuración obligatoria.

Mantén un versionado con sentido.

20. Añadir comandos CLI para tareas pesadas

PrestaShop utiliza el componente Symfony Console.

Los desarrolladores de módulos pueden añadir comandos personalizados.

Utiliza CLI para:

  • importaciones;
  • exportaciones;
  • análisis de integridad;
  • limpieza;
  • procesamiento de imágenes;
  • procesos de colas.

Un comando puede programarse mediante cron.

Esto es mucho más seguro que exigir a un administrador que mantenga abierta una pestaña del navegador.

21. Devolver códigos de salida útiles

Los comandos CLI deben devolver:

0 = éxito
distinto de cero = fallo

Esto permite que:

  • cron;
  • la monitorización;
  • CI/CD;

detecten errores.

No muestres «fallo» y devuelvas éxito de todos modos.

22. Añadir bloqueos a comandos largos

Las ejecuciones de cron pueden solaparse.

Si el comando se ejecuta cada minuto pero tarda tres minutos, pueden aparecer procesos de trabajo duplicados.

Utiliza:

  • concesión temporal en base de datos;
  • bloqueo de Symfony;
  • bloqueo de Redis;
  • bloqueo del sistema de archivos.

El bloqueo debe poder recuperarse después de una caída.

23. Permitir reanudar tareas por lotes

No proceses millones de registros como una única operación opaca.

Guarda:

cursor
procesados
fallidos
reintento

Así, una caída no obliga a reiniciar la tarea desde cero.

24. Registrar contexto estructurado

Los registros deben responder:

  • ¿qué tienda?
  • ¿qué producto?
  • ¿qué tarea?
  • ¿qué identificador externo?
  • ¿qué error?

Ejemplo:

[run=203]
[shop=2]
[product=119019]
Falta la correspondencia de categoría del proveedor

Esto es mucho más útil que:

Algo salió mal

25. No registrar secretos

Nunca escribas:

  • token de API;
  • contraseña;
  • secreto de cliente OAuth;
  • datos de pago;

en los registros.

Sanea el contexto de las excepciones antes de guardarlo.

26. Añadir recursos API cuando sea necesario

Los módulos de PrestaShop 9 pueden exponer recursos mediante la nueva API de administración.

La convención es:

src/ApiPlatform/Resources

Utilízalo cuando el módulo necesite una integración externa estructurada.

No crees un endpoint PHP público personalizado solo porque sea más rápido para hacer un prototipo.

27. Definir ámbitos API restringidos

Si tu módulo expone:

ejecutar análisis de seguridad
leer informe del análisis

crea ámbitos separados como:

security_scan_run
security_report_read

No exijas permisos del núcleo sin relación con estas funciones.

28. Validar las cargas de archivos

Si el módulo importa archivos, valida:

  • tamaño;
  • extensión;
  • tipo MIME;
  • resultado correcto del analizador.

Un nombre de archivo que termine en .xml no demuestra que el archivo contenga XML válido.

Una URL .jpg puede devolver HTML.

Valida el contenido real.

29. Proteger las descargas remotas

Las URL remotas pueden generar riesgos de falsificación de solicitudes del lado del servidor.

Si administradores o proveedores proporcionan URL, restringe los destinos peligrosos.

No permitas que un módulo acceda a direcciones arbitrarias de la red interna sin controles.

Utiliza:

  • validación de URL;
  • listas de esquemas permitidos;
  • tiempo de espera;
  • límites de tamaño de respuesta.

30. Gestionar explícitamente la multitienda

Cada consulta debe preguntarse:

¿Este registro es global o específico de una tienda?

Si es específico de una tienda, incluye id_shop en:

  • tabla;
  • índice;
  • restricciones únicas;
  • claves de caché.

Ejemplo:

UNIQUE(id_shop, supplier_key)

puede ser correcto donde:

UNIQUE(supplier_key)

bloquearía incorrectamente otra tienda.

31. Probar el contexto de tienda en cron

Las tareas CLI no tienen un contexto de tienda del Back Office elegido por una persona.

Establece o pasa explícitamente el contexto de tienda.

No dependas de la última tienda seleccionada por un empleado.

32. Crear respuestas de error claras

Las llamadas Ajax o API deben devolver errores estructurados.

Ejemplo:

{
  "success": false,
  "code": "CATEGORY_MAPPING_MISSING",
  "message": "Supplier category 341 is not mapped."
}

Esto es más fácil de gestionar que una página de excepción de Symfony sin procesar.

33. Probar la instalación desde el ZIP de la versión

Los entornos de desarrollo pueden ocultar errores de empaquetado.

Antes de publicar:

  1. crea el ZIP;
  2. instálalo en una instancia limpia de PrestaShop 9;
  3. configúralo;
  4. ejecuta las funciones críticas.

Esto detecta:

  • archivos de Composer ausentes;
  • mayúsculas y minúsculas incorrectas en nombres de archivo;
  • recursos ausentes;
  • archivos de compilación ignorados.

34. Probar actualizaciones desde versiones anteriores

Una instalación nueva no basta.

Instala:

v1.0.0

con datos realistas.

Después actualiza a:

v1.1.0

Verifica:

  • esquema;
  • configuración;
  • datos de negocio;
  • hooks.

Muchos errores de producción solo existen en las rutas de actualización.

35. Añadir análisis estático

Utiliza herramientas como:

  • PHPStan;
  • PHP CS Fixer;
  • comprobaciones de estándares de código.

El análisis estático detecta:

  • tipos de argumentos incorrectos;
  • clases ausentes;
  • ramas imposibles;
  • problemas con valores que pueden ser nulos.

Esto es especialmente valioso al admitir varias versiones de PHP.

36. Añadir pruebas automatizadas

No todo necesita una prueba completa en el navegador.

Utiliza:

  • pruebas unitarias para servicios;
  • pruebas de repositorios para persistencia;
  • pruebas de integración para instalación y actualización;
  • pruebas funcionales para controladores.

Céntrate primero en los flujos que pueden dañar los datos de negocio.

Ejemplos:

  • exportación de pedidos;
  • actualización de stock;
  • creación de productos.

37. Admitir solo lo que realmente pruebas

No declares:

PrestaShop 1.7–9.x

salvo que pruebes realmente ese rango.

Una promesa de compatibilidad más limitada que funciona es mejor que una amplia que genere solicitudes de soporte.

38. Documentar los requisitos operativos

Si tu módulo requiere:

  • cron;
  • CLI;
  • directorio con permisos de escritura;
  • clave de API;
  • extensión PHP;

indícalo claramente.

Los administradores no deberían descubrir los requisitos operativos a partir de errores.

39. Planificar el comportamiento de desinstalación

Decide qué implica desinstalar.

¿Debe eliminar:

  • la configuración?
  • el historial de colas?
  • los registros de auditoría?
  • las correspondencias de negocio?

Para datos importantes, considera ofrecer una opción separada de «eliminar datos» en vez de destruirlo todo automáticamente.

40. Lista de comprobación de un módulo listo para producción

Arquitectura

  • clase principal del módulo pequeña
  • lógica de negocio en servicios
  • repositorios separados
  • controladores ligeros
  • dependencias inyectadas

Base de datos

  • esquema de instalación
  • índices útiles
  • migraciones de actualización
  • restricciones multitienda

Trabajo en segundo plano

  • comando CLI
  • bloqueo
  • procesamiento por lotes
  • estado de reintento
  • seguimiento del progreso

Seguridad

  • autorización
  • CSRF cuando corresponda
  • SQL seguro
  • validación de archivos
  • eliminación de secretos de los datos registrados

Publicación

  • instalación del ZIP en una instancia limpia probada
  • actualización probada
  • análisis estático
  • pruebas de flujos críticos
  • desinstalación probada

Preguntas frecuentes

¿Cuál es la estructura mínima de un módulo de PrestaShop?

Un módulo necesita una carpeta y un archivo PHP principal con el mismo nombre técnico. Los módulos de producción suelen añadir servicios, rutas, controladores y otros elementos de estructura.

¿El nombre técnico puede contener guiones bajos?

El tutorial oficial de PrestaShop 9 desaconseja los guiones bajos porque no funcionan correctamente con los dominios de traducción.

¿Los controladores Symfony son servicios en PrestaShop 9?

Sí. La documentación actual indica que los controladores de PrestaShop 9 deben configurarse como servicios.

¿Debe estar la lógica de negocio en la clase principal del módulo?

Prefiere servicios para una lógica de negocio importante. Mantén la clase principal centrada en el ciclo de vida del módulo y sus puntos de integración.

¿Puede un módulo añadir comandos de consola?

Sí. PrestaShop utiliza Symfony Console y los módulos pueden aportar comandos personalizados.

¿Pueden los módulos ampliar la API de administración?

Sí. PrestaShop 9 puede cargar automáticamente los recursos API de un módulo desde src/ApiPlatform/Resources cuando el módulo está instalado y activado.

¿Deben ejecutarse las importaciones largas en un controlador?

No. Utiliza CLI, cron o procesos de colas con procesamiento por lotes y seguimiento del progreso.

¿Qué debo probar antes de vender un módulo?

Como mínimo: instalación limpia, configuración, funciones críticas, actualización, comportamiento multitienda cuando corresponda, empaquetado y desinstalación.

Guías y recursos relacionados de PrestaShop 9