//Desarrollo web a medida

Cómo crear un módulo de PrestaShop desde cero

Vamos a crear un módulo de PrestaShop completo y funcional: un bloque de HTML editable desde el back-office que se muestra en la portada de la tienda. Instalar, configurar, guardar y mostrar: con esas cuatro piezas se hacen casi todos los demás.

Responsable de una tienda online preparando pedidos junto al portátil

Este tutorial explica cómo se construye un módulo de PrestaShop paso a paso. Si lo que necesitas es que te lo desarrollemos nosotros, esto es lo que hacemos en módulos y conectores a medida.

Para crear un módulo de PrestaShop desde cero basta una carpeta, un archivo PHP y un hook. Vamos a construir uno completo y funcional: un bloque de HTML que el gestor de la tienda edita desde el back-office y que se pinta en la portada. Es el ejemplo más corto que recorre entero el ciclo de un módulo —instalación, configuración, guardado y presentación—, y con esas cuatro piezas ya se pueden hacer casi todas las demás.

  • Requisitos: PHP y HTML a nivel básico, y haberte movido antes por el back-office de PrestaShop.
  • Dificultad: media.
  • Versiones: el código está escrito para PrestaShop 1.7, 8 y 9, que comparten esta arquitectura de módulos. Si vienes de 1.6, la estructura cambió.

Antes de programar un módulo de PrestaShop: cuándo compensa y cuándo no

PrestaShop trae unos doscientos módulos nativos y el marketplace tiene miles. Programar el tuyo compensa cuando la funcionalidad es propia de tu negocio o cuando lo que hay en el mercado te obliga a instalar diez veces más de lo que necesitas.

Lo que no debe ir en un módulo es la apariencia de la tienda: eso es el tema. Y sobre todo, nunca toques el núcleo. Modificar archivos de classes/ o controllers/ funciona hasta la primera actualización, y entonces se pierde: o pierdes tus cambios, o te quedas sin poder actualizar. El sistema de hooks existe precisamente para no tener que hacerlo.

La estructura mínima de un módulo de PrestaShop

Un módulo es una carpeta dentro de modules/ con un archivo PHP que se llama igual:

modules/
└── airearte_html/
    ├── airearte_html.php
    └── views/
        └── templates/
            └── hook/
                └── home.tpl

El nombre de la carpeta, el del archivo y la propiedad $this->name tienen que coincidir exactamente. La clase es ese mismo nombre con las iniciales en mayúscula y conservando los guiones bajos: para airearte_html, la clase es Airearte_Html. Funciona porque en PHP los nombres de clase no distinguen mayúsculas, y es la convención que siguen los propios módulos nativos (ps_emailsubscription declara Ps_Emailsubscription). Si algo de esto no cuadra, PrestaShop no lista el módulo y no da ninguna pista de por qué.

Para no escribir el esqueleto a mano existe el generador oficial de módulos, que pide nombre, descripción, autor y los hooks que quieras registrar, y te devuelve el andamiaje listo. Necesita cuenta en prestashop.com.

Primer plano del código de un módulo de PrestaShop en la pantalla de un desarrollador
El archivo principal del módulo: una clase que extiende Module y poco más.

El archivo principal del módulo

<?php

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

class Airearte_Html extends Module
{
    public function __construct()
    {
        $this->name = 'airearte_html';
        $this->tab = 'front_office_features';
        $this->version = '1.0.0';
        $this->author = 'Airearte';
        $this->need_instance = 0;
        $this->ps_versions_compliancy = ['min' => '1.7.0.0', 'max' => _PS_VERSION_];
        $this->bootstrap = true;

        parent::__construct();

        $this->displayName = $this->l('Bloque HTML en la portada');
        $this->description = $this->l('Muestra en la portada un HTML editable desde el back-office.');
    }
}

Dos detalles que se pasan por alto. displayName y description van después de parent::__construct(), porque antes de esa llamada el sistema de traducciones todavía no está listo. Y ps_versions_compliancy evita que alguien lo instale en una versión donde no funciona: es la diferencia entre un aviso claro y un error a mitad de la instalación.

Instalar y desinstalar el módulo

La instalación hace dos cosas: registrar el hook donde queremos aparecer y dejar la configuración con un valor inicial.

const CLAVE = 'AIREARTE_HTML_CONTENIDO';

public function install()
{
    return parent::install()
        && $this->registerHook('displayHome')
        && Configuration::updateValue(self::CLAVE, '');
}

public function uninstall()
{
    return parent::uninstall()
        && Configuration::deleteByName(self::CLAVE);
}

La clave de configuración, en una constante. Puede parecer manía, pero es el fallo más común de este tipo de módulos: se guarda con un nombre y se lee con otro, el formulario aparenta funcionar, y en la portada no sale nada. Con una constante el error no se puede cometer.

Y desinstalar limpia lo que se creó. Un módulo que deja su configuración tirada en la tabla ps_configuration es basura acumulada que nadie va a ir a buscar.

La página de configuración en el back-office

Cuando el gestor pulsa «Configurar», PrestaShop llama a getContent(). Ese método hace las dos cosas: procesa el envío si lo hay y devuelve el formulario.

public function getContent()
{
    $salida = '';

    if (Tools::isSubmit('submitAirearteHtml')) {
        $contenido = Tools::getValue('AIREARTE_HTML_CONTENIDO');

        if (!Validate::isCleanHtml($contenido)) {
            $salida .= $this->displayError($this->l('El contenido no es válido.'));
        } else {
            Configuration::updateValue(self::CLAVE, $contenido, true);
            $salida .= $this->displayConfirmation($this->l('Cambios guardados.'));
        }
    }

    return $salida . $this->renderForm();
}

Tres cosas importan aquí:

  • El nombre que se comprueba en Tools::isSubmit() tiene que ser el mismo que el del botón de envío del formulario. Es la segunda causa de «le doy a guardar y no pasa nada».
  • Validate::isCleanHtml() rechaza el HTML con <script> y con manejadores de eventos. Estamos dejando que alguien meta HTML en la portada de la tienda: sin esta comprobación, el módulo es un agujero abierto.
  • El tercer parámetro de Configuration::updateValue() es el que permite guardar HTML. Sin ese true, PrestaShop escapa las etiquetas y lo que se guarda es el código en texto plano.

El formulario se monta con HelperForm, que se encarga de darle el aspecto del panel:

protected function renderForm()
{
    $campos = [[
        'form' => [
            'legend' => ['title' => $this->l('Contenido'), 'icon' => 'icon-cogs'],
            'input' => [[
                'type' => 'textarea',
                'label' => $this->l('HTML'),
                'name' => 'AIREARTE_HTML_CONTENIDO',
                'autoload_rte' => true,
                'cols' => 100,
                'rows' => 20,
            ]],
            'submit' => ['title' => $this->l('Guardar')],
        ],
    ]];

    $helper = new HelperForm();
    $helper->module = $this;
    $helper->identifier = $this->identifier;
    $helper->submit_action = 'submitAirearteHtml';
    $helper->currentIndex = AdminController::$currentIndex . '&configure=' . $this->name;
    $helper->token = Tools::getAdminTokenLite('AdminModules');
    $helper->tpl_vars = [
        'fields_value' => [self::CLAVE => Configuration::get(self::CLAVE)],
    ];

    return $helper->generateForm($campos);
}

'autoload_rte' => true convierte el textarea en el editor visual del panel. Es una línea y le cambia la vida a quien vaya a usar el módulo todos los días.

Pintarlo en la portada: el hook devuelve, no imprime

Esta es la parte donde más gente se atasca, y casi siempre por el mismo motivo:

public function hookDisplayHome($params)
{
    $this->context->smarty->assign([
        'airearte_html' => Configuration::get(self::CLAVE),
    ]);

    return $this->fetch('module:airearte_html/views/templates/hook/home.tpl');
}

Un hook de visualización tiene que devolver el HTML, no imprimirlo. Si usas echo, el contenido sale igualmente, pero fuera de sitio: se escribe en el momento en que PHP ejecuta el hook, no en el punto de la plantilla donde le toca. El resultado típico es el bloque asomando por encima de la cabecera, o partiendo el diseño. Se ve raro, se busca en el CSS, y el problema estaba en una palabra.

La plantilla es de una línea:

{if $airearte_html}
    <div class="airearte-html">{$airearte_html nofilter}</div>
{/if}

El modificador nofilter es obligatorio: el Smarty de PrestaShop escapa por defecto todo lo que se imprime, así que sin él verías las etiquetas en pantalla en lugar del bloque. Y es exactamente por eso que antes había que validar el HTML al guardarlo: aquí ya no hay red.

Los errores que más tiempo cuestan al crear un módulo

  1. Nombre de carpeta, archivo, clase y $this->name descuadrados. El módulo no aparece en la lista y no hay mensaje de error.
  2. Guardar con una clave y leer con otra. Guarda sin quejarse y no muestra nada.
  3. El submit_action y el Tools::isSubmit() distintos. El botón no hace nada.
  4. echo en lugar de return en un hook de visualización.
  5. Olvidar el true de updateValue() al guardar HTML, o el nofilter en la plantilla.
  6. Tocar archivos del núcleo «sólo esta vez». Nunca es sólo esta vez.

Cuando algo no cuadre, activa el modo depuración en config/defines.inc.php (_PS_MODE_DEV_ a true) y borra la caché desde Parámetros avanzados. PrestaShop cachea las plantillas con ganas: una parte considerable de los «no funciona» son en realidad «no se ha recargado».

De aquí en adelante

Con este esqueleto ya puedes registrar otros hooks, añadir tablas propias, encolar tu CSS o llamar a una API externa. El salto de dificultad no está en la primera versión: está en mantenerla cuando llegue la siguiente versión mayor de PrestaShop, cuando cambie el mínimo de PHP o cuando haya que sincronizar la tienda con el ERP y aparezcan los casos raros.

Esa parte es la que cubrimos en módulos y conectores a medida, y también trabajamos sobre la tienda entera en desarrollo de tiendas online. Si no tienes claro si lo tuyo necesita un módulo, cuéntanoslo: cuando lo resuelve algo que ya existe, lo decimos.

Publicado en noviembre de 2016. Revisado y actualizado a PrestaShop 1.7, 8 y 9 en agosto de 2026.

//Artículos relacionados
  • Programa estándar o software a medida: cómo saber cuál necesitas

    Desarrollo web a medida

    Programa estándar o software a medida: cómo saber cuál necesitas

    Casi nadie llega a plantearse un desarrollo a medida de entrada: se llega después de haber probado dos o tres programas del mercado. La pregunta no es cuál es mejor, sino cuál encaja con lo que tú haces.

    Leer artículo
  • Cómo crear un plugin de WordPress desde cero

    Desarrollo web a medida

    Cómo crear un plugin de WordPress desde cero

    Para crear un plugin de WordPress desde cero basta un archivo PHP con una cabecera de seis líneas. Vemos la estructura mínima, cómo funcionan las acciones y los filtros, y qué errores evitar antes de subirlo a producción.

    Leer artículo
  • Software de gestión en la nube o en tu servidor: qué cambia de verdad

    Desarrollo web a medida

    Software de gestión en la nube o en tu servidor: qué cambia de verdad

    La pregunta ya no es si mover el programa de gestión a internet: casi todo está ahí. La útil es otra, y casi nadie la hace a tiempo: quién administra el sistema y dónde viven tus datos.

    Leer artículo