Desarrollo de módulos personalizados en PrestaShop 9
Introducción al Desarrollo de Módulos en PrestaShop 9
Con la llegada de PrestaShop 9, el ecosistema de desarrollo ha dado un salto cualitativo hacia la modernidad. Esta versión, basada en Symfony 6 y PHP 8.1+, obliga a los desarrolladores a repensar la arquitectura de sus módulos PrestaShop. Ya no basta con un simple archivo PHP; ahora se requiere un enfoque estructurado, con namespaces, servicios y una clara separación de responsabilidades.
El desarrollo personalizado en esta plataforma implica dominar los hooks PrestaShop, el contenedor de servicios de Symfony y el sistema de widgets. Si vienes de versiones anteriores, notarás que el motor de plantillas Smarty sigue presente, pero la lógica de negocio se desplaza hacia controladores y formularios Symfony.
[INFO] PrestaShop 9 elimina la compatibilidad con PHP 7.x. Asegúrate de que tu entorno de desarrollo ejecute PHP 8.1 como mínimo.
Estructura de un Módulo en PrestaShop 9
La estructura básica de un módulo sigue un patrón predecible, pero con mejoras significativas. Aquí tienes un ejemplo de árbol de directorios para un módulo llamado mimodulo:
mimodulo/
├── mimodulo.php
├── config.xml
├── views/
│ ├── templates/
│ │ ├── admin/
│ │ └── front/
│ └── js/
│ └── app.js
├── src/
│ ├── Controller/
│ ├── Form/
│ ├── Install/
│ └── Service/
├── translations/
├── vendor/
└── composer.json
El archivo principal mimodulo.php
Este archivo sigue siendo el punto de entrada, pero ahora debe extender la clase Module de manera correcta. Observa el uso de namespaces y la inyección de dependencias:
<?php
// mimodulo.php
namespace PrestaShop\Module\Mimodulo;
use PrestaShop\PrestaShop\Core\Module\AbstractModule;
class Mimodulo extends AbstractModule
{
public function __construct()
{
$this->name = 'mimodulo';
$this->tab = 'front_office_features';
$this->version = '1.0.0';
$this->author = 'TuNombre';
$this->need_instance = 0;
$this->ps_versions_compliancy = ['min' => '9.0', 'max' => _PS_VERSION_];
$this->bootstrap = true;
parent::__construct();
$this->displayName = $this->l('Mi Módulo Personalizado');
$this->description = $this->l('Descripción del módulo para PrestaShop 9');
$this->confirmUninstall = $this->l('¿Estás seguro de desinstalar?');
}
public function install()
{
return parent::install()
&& $this->registerHook('displayHeader')
&& $this->registerHook('displayFooter');
}
public function uninstall()
{
return parent::uninstall();
}
}
[TIP] Usa
$this->bootstrap = truepara que el panel de administración cargue los assets de Bootstrap. Esto facilita la creación de formularios de configuración.
Hooks PrestaShop: El Corazón de la Personalización
Los hooks PrestaShop son puntos de enganche que permiten insertar contenido o ejecutar lógica en momentos específicos del ciclo de vida de la tienda. En PrestaShop 9, los hooks se manejan mediante métodos con nombre hook{NombreDelHook}.
Hook de displayHeader
Este hook se ejecuta en el <head> de todas las páginas. Es ideal para cargar CSS/JS global:
public function hookDisplayHeader($params)
{
$this->context->controller->registerStylesheet(
'mimodulo-style',
'modules/' . $this->name . '/views/css/mimodulo.css',
['media' => 'all', 'priority' => 200]
);
$this->context->controller->registerJavascript(
'mimodulo-script',
'modules/' . $this->name . '/views/js/mimodulo.js',
['position' => 'bottom', 'priority' => 200]
);
}
Hook de displayFooter
Perfecto para añadir contenido al final de la página, como un banner o un formulario de suscripción:
public function hookDisplayFooter($params)
{
$this->context->smarty->assign([
'mi_variable' => 'Valor personalizado',
'enlace' => $this->context->link->getModuleLink($this->name, 'display')
]);
return $this->display(__FILE__, 'views/templates/front/footer.tpl');
}
Symfony PrestaShop: Integración Profunda
PrestaShop 9 integra Symfony de manera nativa. Esto significa que puedes crear controladores, formularios y servicios usando la arquitectura Symfony. Para ello, necesitas registrar tu módulo en el contenedor de servicios.
Creación de un Controlador Symfony
Crea un controlador en src/Controller/FrontController.php:
<?php
// src/Controller/FrontController.php
namespace PrestaShop\Module\Mimodulo\Controller\Front;
use PrestaShopBundle\Controller\Front\AbstractFrontController;
use Symfony\Component\HttpFoundation\Response;
class FrontController extends AbstractFrontController
{
public function displayAction()
{
return $this->render('@Modules/mimodulo/views/templates/front/custom_page.html.twig', [
'mensaje' => '¡Hola desde Symfony!'
]);
}
}
Luego, registra la ruta en config/routes.yml:
mimodulo_front_display:
path: /mimodulo/personalizado
methods: [GET]
defaults:
_controller: 'PrestaShop\Module\Mimodulo\Controller\Front\FrontController::displayAction'
[WARNING] Las rutas Symfony deben ser únicas y no solaparse con las rutas nativas de PrestaShop. Usa un prefijo con el nombre de tu módulo.
Formularios con Symfony Forms
Para crear un formulario de configuración avanzado, usa el componente Form de Symfony:
<?php
// src/Form/ConfigurationForm.php
namespace PrestaShop\Module\Mimodulo\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints\NotBlank;
class ConfigurationForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('api_key', TextType::class, [
'label' => 'Clave API',
'constraints' => [new NotBlank()]
])
->add('endpoint', TextType::class, [
'label' => 'URL del endpoint',
'required' => false
]);
}
}
Luego, en tu controlador de administración, procesa el formulario:
public function configureAction(Request $request)
{
$form = $this->createForm(ConfigurationForm::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
// Guardar en configuración
\Configuration::updateValue('MIMODULO_API_KEY', $data['api_key']);
\Configuration::updateValue('MIMODULO_ENDPOINT', $data['endpoint']);
}
return $this->render('@Modules/mimodulo/views/templates/admin/configure.html.twig', [
'form' => $form->createView()
]);
}
Buenas Prácticas y Optimización
Uso de Servicios
En lugar de cargar dependencias directamente, define servicios en config/services.yml:
services:
_defaults:
public: true
mimodulo.api_client:
class: PrestaShop\Module\Mimodulo\Service\ApiClient
arguments:
- '@doctrine.dbal.default_connection'
Luego, inyecta el servicio en tu controlador o hook:
public function hookDisplayFooter($params)
{
$apiClient = $this->get('mimodulo.api_client');
// ...
}
Manejo de Traducciones
PrestaShop 9 usa archivos XLIFF para traducciones. Coloca tus traducciones en translations/es-ES.php:
<?php
// translations/es-ES.php
global $_MODULE;
$_MODULE = [];
$_MODULE['<{mimodulo}prestashop>mimodulo_1234567890'] = 'Texto traducido';
O mejor, usa el sistema de Symfony con archivos .xlf.
Rendimiento y Caché
Los módulos PrestaShop deben ser ligeros. Evita consultas SQL dentro de bucles. Usa caché de Doctrine o Redis:
$cache = $this->get('prestashop.adapter.cache.clearer');
$cache->clear();
Ejemplo Completo: Módulo de Notificaciones Push
Vamos a construir un módulo que muestre notificaciones push en el frontend usando un hook y un controlador Symfony.
Estructura Final
mimodulo_push/
├── mimodulopush.php
├── config.xml
├── views/
│ ├── templates/
│ │ └── front/
│ │ └── notification.tpl
│ └── js/
│ └── push.js
├── src/
│ ├── Controller/
│ │ └── FrontController.php
│ └── Service/
│ └── NotificationService.php
└── config/
└── routes.yml
Código del Servicio
<?php
// src/Service/NotificationService.php
namespace PrestaShop\Module\Mimodulopush\Service;
class NotificationService
{
public function getActiveNotifications()
{
// Lógica para obtener notificaciones de BD
return [
['title' => 'Oferta especial', 'message' => 'Hasta 50% descuento']
];
}
}
Hook en el módulo principal
public function hookDisplayHeader($params)
{
$this->context->controller->registerJavascript(
'push-script',
'modules/' . $this->name . '/views/js/push.js',
['position' => 'bottom']
);
}
public function hookDisplayFooter($params)
{
$service = $this->get('mimodulopush.notification_service');
$notifications = $service->getActiveNotifications();
$this->context->smarty->assign([
'notifications' => $notifications
]);
return $this->display(__FILE__, 'views/templates/front/notification.tpl');
}
Conclusión
El desarrollo personalizado en PrestaShop 9 ya no es opcional; es una necesidad para crear módulos robustos y mantenibles. La combinación de hooks PrestaShop con la arquitectura Symfony PrestaShop permite soluciones escalables y seguras. Recuerda:
- Siempre usa namespaces y autoloading con Composer.
- Registra tus servicios en el contenedor de Symfony.
- Optimiza los hooks para no ralentizar la tienda.
- Aprovecha los formularios Symfony para configuraciones complejas.
[TIP] Únete a la comunidad de PrestaShop en GitHub y al foro oficial. Allí encontrarás ejemplos actualizados y soporte para tus módulos.
El futuro del desarrollo de módulos PrestaShop está en la estandarización y el uso de buenas prácticas. ¡Empieza hoy mismo a migrar tus módulos antiguos a esta nueva arquitectura!
