Cómo crear un módulo de pago en PrestaShop (guía para principiantes)
Introducción: ¿Qué necesitas saber antes de empezar?
Crear un módulo de pago en PrestaShop puede sonar a algo reservado para desarrolladores senior, pero la realidad es que con una estructura clara y los conceptos básicos bien asentados, cualquier persona con nociones de PHP y algo de paciencia puede lograrlo. Este artículo está pensado para ti, que quieres añadir una pasarela de pago PrestaShop personalizada o simplemente entender cómo funciona el sistema por dentro.
Antes de escribir una sola línea de código, es fundamental que entiendas la arquitectura de módulos de PrestaShop. Un módulo no es más que una carpeta con archivos PHP, plantillas TPL, JavaScript, CSS y un archivo de configuración principal. PrestaShop 1.7 y 1.8 utilizan el componente Symfony para el back office, pero los módulos de pago siguen una lógica de hooks muy concreta que no ha cambiado demasiado en los últimos años.
Para este tutorial no necesitas un servidor complejo. Puedes usar tu propio ordenador con XAMPP o cualquier hosting que soporte PHP 7.2 o superior. Si vas a probar en un entorno de producción, te recomiendo que primero lo hagas en local y luego subas todo. Y si tu hosting usa Syspanel (antes conocido como HestiaCP), recuerda que el acceso al panel de control se hace por el puerto 2106, no por el 443 habitual.
Estructura básica de un módulo de pago
Todo desarrollo módulo PrestaShop comienza con una estructura de carpetas estandarizada. Dentro de la carpeta raíz de tu tienda, en /modules, crearás una carpeta con el nombre técnico de tu módulo. Por ejemplo, si tu pasarela se llama "Pago Rápido", el nombre técnico podría ser pagarapido.
La estructura mínima que necesitas es la siguiente:
pagarapido/(carpeta raíz del módulo)pagarapido/pagarapido.php(archivo principal con la clase del módulo)pagarapido/views/templates/front/payment_execution.tpl(plantilla para mostrar el botón de pago)pagarapido/views/templates/front/payment_return.tpl(plantilla de confirmación)pagarapido/logo.png(opcional pero recomendable, 32x32 píxeles)
El archivo principal debe tener el mismo nombre que la carpeta y la clase dentro de él debe llamarse igual. Es decir, si la carpeta es pagarapido, la clase será Pagarapido. Esto es una regla de oro en PrestaShop que no debes saltarte jamás, porque el sistema busca la clase por el nombre del directorio.
El archivo principal del módulo
Vamos a crear el esqueleto del archivo pagarapido.php. Este archivo contendrá la clase principal que extiende de PaymentModule. Esta clase base ya trae muchos métodos preparados que nosotros solo tendremos que sobreescribir.
<?php
if (!defined('_PS_VERSION_')) {
exit;
}
class Pagarapido extends PaymentModule
{
public function __construct()
{
$this->name = 'pagarapido';
$this->tab = 'payments_gateways';
$this->version = '1.0.0';
$this->author = 'Tu Nombre';
$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('Pago Rápido');
$this->description = $this->l('Módulo de pago para principiantes');
$this->confirmUninstall = $this->l('¿Seguro que quieres desinstalar?');
}
public function install()
{
return parent::install()
&& $this->registerHook('paymentOptions')
&& $this->registerHook('paymentReturn')
&& $this->registerHook('displayPaymentReturn');
}
public function uninstall()
{
return parent::uninstall();
}
}
Fíjate en que hemos registrado tres hooks: paymentOptions, paymentReturn y displayPaymentReturn. El primero es el más importante, porque es el que le dice a PrestaShop qué opciones de pago mostrar en el checkout.
El hook paymentOptions: el corazón del módulo
El hook paymentOptions es el que se ejecuta cuando el cliente llega al paso de elegir método de pago. Aquí es donde decides qué opciones mostrar y con qué datos. Vamos a implementarlo:
public function hookPaymentOptions($params)
{
if (!$this->active) {
return [];
}
$option = new \PrestaShop\PrestaShop\Core\Payment\PaymentOption();
$option->setCallToActionText($this->l('Pagar con Pago Rápido'))
->setAction($this->context->link->getModuleLink($this->name, 'payment', [], true))
->setLogo(Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/logo.png'));
return [$option];
}
Este método devuelve un array de PaymentOption. Cada opción representa un método de pago diferente. En nuestro caso, solo devolvemos una, pero podrías devolver varias si tu módulo ofrece diferentes formas de pago (tarjeta, PayPal, transferencia, etc.).
La línea más importante es setAction(). Aquí le decimos a PrestaShop a qué URL debe redirigir al cliente cuando seleccione esta opción. getModuleLink genera una URL amigable que apunta al controlador payment de nuestro módulo.
Creando el controlador de pago
Necesitamos un controlador frontal que procese la solicitud de pago. Para ello, creamos la carpeta controllers/front/ dentro del módulo y añadimos un archivo llamado payment.php:
class PagarapidoPaymentModuleFrontController extends ModuleFrontController
{
public $ssl = true;
public function initContent()
{
parent::initContent();
$cart = $this->context->cart;
if ($cart->id_customer == 0 || $cart->id_address_delivery == 0 || $cart->id_address_invoice == 0) {
Tools::redirect('index.php?controller=order');
}
$this->context->smarty->assign([
'total' => $cart->getOrderTotal(true, Cart::BOTH),
'module_name' => $this->module->name,
'return_url' => $this->context->link->getModuleLink($this->module->name, 'confirmation', [], true)
]);
$this->setTemplate('module:pagarapido/views/templates/front/payment_execution.tpl');
}
}
Este controlador hace tres cosas importantes:
- Verifica que el carrito tiene un cliente válido y direcciones asignadas.
- Calcula el total del pedido.
- Prepara los datos para la plantilla que mostrará el botón de "Confirmar pago".
La plantilla de ejecución del pago
Ahora creamos la plantilla payment_execution.tpl en views/templates/front/. Esta es la página donde el cliente ve el resumen de lo que va a pagar y confirma la operación:
<div class="card">
<div class="card-body">
<h3>{l s='Resumen de tu pedido' mod='pagarapido'}</h3>
<p>{l s='Vas a pagar un total de' mod='pagarapido'} <strong>{$total|string_format:"%.2f"} €</strong></p>
<form method="post" action="{$return_url}">
<input type="hidden" name="id_cart" value="{$cart->id}">
<button type="submit" class="btn btn-primary btn-lg">
{l s='Confirmar pago' mod='pagarapido'}
</button>
</form>
</div>
</div>
Observa que el formulario envía los datos al controlador confirmation. Es en este punto donde normalmente se integraría con una pasarela de pago PrestaShop real. En este ejemplo, simulamos una confirmación inmediata, pero en un caso real aquí harías una llamada API a tu proveedor de pagos.
Confirmación y creación del pedido
Ahora creamos el controlador confirmation.php que procesará el pago y creará el pedido en PrestaShop:
class PagarapidoConfirmationModuleFrontController extends ModuleFrontController
{
public function postProcess()
{
$cart = $this->context->cart;
$customer = new Customer($cart->id_customer);
// Aquí iría la verificación real con tu pasarela de pago
$payment_status = Configuration::get('PS_OS_PAYMENT');
$message = 'Pago realizado correctamente con Pago Rápido';
$this->module->validateOrder(
$cart->id,
$payment_status,
$cart->getOrderTotal(true, Cart::BOTH),
$this->module->displayName,
$message,
[],
null,
false,
$cart->secure_key
);
Tools::redirect(
$this->context->link->getPageLink('order-confirmation', true, null, [
'id_cart' => $cart->id,
'id_module' => $this->module->id,
'id_order' => $this->module->currentOrder,
'key' => $customer->secure_key
])
);
}
}
El método validateOrder es el que se encarga de todo el proceso de creación del pedido. Necesita el ID del carrito, el estado del pedido, el total, el nombre del módulo, un mensaje opcional y la clave segura del cliente.
Configuración y ajustes del módulo
Para que tu módulo de pago PrestaShop sea configurable, debes añadir una pestaña de configuración en el back office. Esto se hace implementando el método getContent():
public function getContent()
{
$output = '';
if (Tools::isSubmit('submit' . $this->name)) {
$api_key = Tools::getValue('PAGARAPIDO_API_KEY');
Configuration::updateValue('PAGARAPIDO_API_KEY', $api_key);
$output .= $this->displayConfirmation($this->l('Configuración guardada'));
}
return $output . $this->renderForm();
}
private function renderForm()
{
$fields_form = [
'form' => [
'legend' => ['title' => $this->l('Configuración de la API')],
'input' => [
[
'type' => 'text',
'label' => $this->l('API Key'),
'name' => 'PAGARAPIDO_API_KEY',
'required' => true
]
],
'submit' => ['title' => $this->l('Guardar')]
]
];
$helper = new HelperForm();
$helper->module = $this;
$helper->name_controller = $this->name;
$helper->token = Tools::getAdminTokenLite('AdminModules');
$helper->currentIndex = AdminController::$currentIndex . '&configure=' . $this->name;
$helper->title = $this->displayName;
$helper->submit_action = 'submit' . $this->name;
$helper->default_form_language = (int) Configuration::get('PS_LANG_DEFAULT');
$helper->fields_value['PAGARAPIDO_API_KEY'] = Configuration::get('PAGARAPIDO_API_KEY');
return $helper->generateForm([$fields_form]);
}
[!TIP]
Guarda siempre los datos sensibles como claves API en la tablaconfigurationde PrestaShop, nunca en archivos planos. Así podrás acceder a ellos desde cualquier parte del código conConfiguration::get().
Hooks adicionales: paymentReturn y displayPaymentReturn
El hook paymentReturn se usa para mostrar información después de que el pedido se ha completado. Es útil para mostrar un número de referencia o instrucciones de pago:
public function hookPaymentReturn($params)
{
if (!$this->active || !isset($params['objOrder'])) {
return;
}
$order = $params['objOrder'];
if ($order->getCurrentOrderState()->id != Configuration::get('PS_OS_ERROR')) {
$this->context->smarty->assign([
'reference' => $order->reference,
'total_paid' => $order->total_paid
]);
return $this->display(__FILE__, 'views/templates/front/payment_return.tpl');
}
}
Y la plantilla payment_return.tpl:
<div class="alert alert-success">
<h3>{l s='¡Pago completado con éxito!' mod='pagarapido'}</h3>
<p>{l s='Tu pedido con referencia' mod='pagarapido'} <strong>{$reference}</strong>
{l s='ha sido procesado. Total pagado:' mod='pagarapido'} <strong>{$total_paid} €</strong></p>
</div>
Errores comunes y cómo solucionarlos
Durante el desarrollo módulo PrestaShop, te encontrarás con varios problemas típicos. Aquí van los más frecuentes:
Error de clase no encontrada: Verifica que el nombre de la carpeta, el archivo PHP y la clase dentro del archivo sean exactamente iguales. PrestaShop es muy estricto con esto y el más mínimo cambio de mayúsculas hará que falle.
El módulo no aparece en el listado: Comprueba que el archivo principal tiene la extensión .php y que no hay errores de sintaxis. Un simple <?php sin cerrar puede hacer que el módulo no cargue.
El hook paymentOptions no se ejecuta: Asegúrate de que el módulo está activo y que has registrado el hook tanto en install() como en el método hookPaymentOptions. También verifica que el carrito tiene todos los datos necesarios.
Problemas con SSL: Si tu tienda usa SSL (lo cual es obligatorio para pasarelas de pago), asegúrate de que el controlador tiene public $ssl = true;. De lo contrario, el navegador bloqueará la conexión.
[!WARNING]
Nunca subas un módulo con errores de sintaxis a producción. Un solo error puede dejar tu tienda completa inaccesible. Prueba siempre en local o en un entorno de staging antes de subir a tu hosting.
Consideraciones de seguridad y buenas prácticas
La seguridad en un módulo de pago PrestaShop no es opcional. Aquí tienes algunas prácticas imprescindibles:
- Valida siempre los datos de entrada: Usa
Tools::getValue()en lugar de acceder directamente a$_POSTo$_GET. - Escapa todas las salidas: En las plantillas TPL, usa
|escape:'htmlall'para cualquier dato que provenga del usuario. - Utiliza tokens CSRF: En formularios sensibles, añade un token con
Tools::getToken(false). - No guardes contraseñas en texto plano: Si necesitas almacenar credenciales de API, usa cifrado con
Rijndaelque ya incluye PrestaShop. - Comprueba la identidad del cliente: Antes de crear un pedido, verifica que el cliente logueado coincide con el propietario del carrito.
// Ejemplo de verificación de identidad
if ($cart->id_customer != $this->context->customer->id) {
Tools::redirect('index.php?controller=authentication');
}
Probando el módulo en local
Para probar tu módulo de pago PrestaShop sin arriesgar tu tienda en producción, te recomiendo instalar un servidor local con XAMPP o Laragon. También puedes usar Docker si ya estás familiarizado.
Los pasos son:
- Descarga e instala PrestaShop en tu servidor local.
- Copia la carpeta
pagarapidodentro demodules/. - Ve al back office en
/adminy localiza el módulo en el listado. - Haz clic en "Instalar" y luego en "Configurar".
- Introduce una clave API de prueba.
- Realiza un pedido de prueba con un cliente ficticio.
Si tu hosting usa Syspanel y necesitas subir el módulo a producción, recuerda que el acceso al panel de administración de archivos se realiza a través del puerto 2106. Por ejemplo: https://tudominio.com:2106. Desde ahí podrás gestionar los archivos del servidor cómodamente.
Preguntas frecuentes (FAQ)
**¿Puedo crear un módulo de pago sin saber PHP
