Estructura de un modulo PrestaShop

Actualizado: 2024-12-01

Un modulo PrestaShop es un plugin PHP autonomo que extiende las funcionalidades de la tienda sin modificar el core. Toda la logica, templates, assets y configuracion del modulo viven dentro de un unico directorio bajo /modules/nombre-del-modulo/.

💡
Convencion de nombres

El nombre del directorio del modulo debe coincidir exactamente con el nombre de la clase principal y el valor de $this->name. Usa solo letras minusculas y guiones bajos (mi_modulo), sin guiones ni espacios.

#Estructura basica

Estructura de directorios de un modulo completo
bash
mymodule/
├── mymodule.php                  # Archivo principal del modulo (requerido)
├── config.xml                    # Cache de configuracion (auto-generado)
├── logo.png                      # Logo del modulo (80x80px)
│
├── config/                       # Configuracion Symfony (PS 1.7+)
│   ├── routes.yml                # Definicion de rutas
│   └── services.yml              # Registro de servicios DI
│
├── controllers/
│   ├── admin/
│   │   └── AdminMyModuleController.php
│   └── front/
│       ├── main.php              # ModuleFrontController principal
│       └── ajax.php              # Controlador AJAX
│
├── src/                          # Clases PHP (PSR-4 autoloading)
│   ├── Entity/
│   │   └── MyEntity.php          # Entidad Doctrine (PS 1.7+)
│   ├── Repository/
│   │   └── MyEntityRepository.php
│   └── Service/
│       └── MyService.php
│
├── views/
│   ├── templates/
│   │   ├── hook/                 # Templates de hooks
│   │   │   ├── displayHome.tpl
│   │   │   └── displayProductButtons.tpl
│   │   ├── admin/                # Templates del admin
│   │   │   └── configure.tpl
│   │   └── front/                # Templates del front office
│   │       └── mypage.tpl
│   ├── js/
│   │   ├── front.js
│   │   └── admin.js
│   └── css/
│       ├── front.css
│       └── admin.css
│
├── translations/                 # Archivos de traduccion .xlf
│   ├── es.xlf
│   ├── en.xlf
│   └── fr.xlf
│
├── upgrade/                      # Scripts de actualizacion
│   ├── install-1.0.1.php
│   └── install-1.0.2.php
│
├── override/                     # Overrides especificos del modulo
│   └── classes/
│       └── Product.php
│
└── vendor/                       # Dependencias (Composer)
    └── autoload.php

#Archivo principal

El archivo mymodule.php es el corazon del modulo. Debe contener una clase con el mismo nombre del directorio que extiende Module (o una de sus subclases como PaymentModule, CarrierModule, etc.).

mymodule/mymodule.php
php
<?php

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

class MyModule extends Module
{
    public function __construct()
    {
        $this->name          = 'mymodule';          // Mismo que el directorio
        $this->tab           = 'front_office_features'; // Categoria en el marketplace
        $this->version       = '1.0.0';
        $this->author        = 'Tu Empresa';
        $this->need_instance = 0;                   // 0 = no instanciar en admin
        $this->bootstrap     = true;                // Usar Bootstrap en admin
        $this->ps_versions_compliancy = [
            'min' => '1.7.0',
            'max' => _PS_VERSION_,
        ];

        parent::__construct();  // Siempre despues de definir $this->name

        $this->displayName = $this->trans(
            'Mi Modulo',
            [],
            'Modules.Mymodule.Admin'
        );
        $this->description = $this->trans(
            'Descripcion de mi modulo para PrestaShop.',
            [],
            'Modules.Mymodule.Admin'
        );
    }

    /**
     * Instalacion del modulo
     */
    public function install(): bool
    {
        return parent::install()
            && $this->registerHook('displayHome')
            && $this->registerHook('actionValidateOrder')
            && $this->registerHook('actionFrontControllerSetMedia')
            && $this->installDatabase();
    }

    /**
     * Desinstalacion del modulo
     */
    public function uninstall(): bool
    {
        return parent::uninstall()
            && $this->uninstallDatabase();
    }

    /**
     * Pagina de configuracion en el admin
     */
    public function getContent(): string
    {
        $output = '';

        if (Tools::isSubmit('submit' . $this->name)) {
            $myValue = Tools::getValue('MY_CONFIG_VALUE');
            Configuration::updateValue('MY_CONFIG_VALUE', $myValue);
            $output .= $this->displayConfirmation(
                $this->trans('Configuracion guardada', [], 'Admin.Notifications.Success')
            );
        }

        return $output . $this->renderConfigForm();
    }

    private function renderConfigForm(): string
    {
        $helper = new HelperForm();
        // ... configuracion del HelperForm
        return $helper->generateForm([/* fields */]);
    }

    private function installDatabase(): bool
    {
        $sql = 'CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'mymodule_data` (
            `id_mymodule` int(10) unsigned NOT NULL AUTO_INCREMENT,
            `id_order` int(10) unsigned NOT NULL,
            `data` text,
            `created_at` datetime NOT NULL,
            PRIMARY KEY (`id_mymodule`)
        ) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8mb4;';

        return Db::getInstance()->execute($sql);
    }

    private function uninstallDatabase(): bool
    {
        return Db::getInstance()->execute(
            'DROP TABLE IF EXISTS `' . _DB_PREFIX_ . 'mymodule_data`'
        );
    }

    // Hook handler
    public function hookDisplayHome(array $params): string
    {
        $this->context->smarty->assign([
            'greeting' => 'Hola desde mi modulo',
        ]);

        return $this->display(__FILE__, 'views/templates/hook/displayHome.tpl');
    }
}

#Templates y vistas

Los templates de hooks van en views/templates/hook/. El nombre del archivo debe coincidir con el nombre del hook que lo renderiza (sin el prefijo hook).

views/templates/hook/displayHome.tpl
smarty
{**
 * Template para el hook displayHome
 *}
<div class="mymodule-home-block">
    <h2>{l s='Bienvenido' mod='mymodule'}</h2>
    <p>{$greeting|escape:'html':'UTF-8'}</p>
</div>
⚠️
Siempre escapa las variables Smarty

Usa siempre |escape:'html':'UTF-8' en variables de usuario para prevenir XSS. Las variables del sistema de PS ya estan escapadas.

#Scripts de upgrade

upgrade/install-1.0.1.php
php
<?php

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

/**
 * Script de actualizacion a la version 1.0.1
 * Se ejecuta automaticamente al actualizar el modulo
 */
function upgrade_module_1_0_1($module)
{
    // Añadir nueva columna a la tabla
    $sql = 'ALTER TABLE `' . _DB_PREFIX_ . 'mymodule_data`
        ADD COLUMN `status` tinyint(1) NOT NULL DEFAULT 1 AFTER `data`';

    if (!Db::getInstance()->execute($sql)) {
        return false;
    }

    // Registrar nuevo hook
    return $module->registerHook('actionOrderHistoryAddAfter');
}
Descargar en Markdown Pensado para pegar en ChatGPT, Claude u otra IA. Incluye solo el contenido de esta pagina.