---
title: Upgrade scripts — actualizar modulo sin perder datos
section: examples
slug: upgrade-module
description: "Escribir scripts de actualizacion para modulos PrestaShop: upgrade-X.X.X.php, migraciones de BD, cambios de configuracion y testing de upgrades."
keywords: prestashop upgrade modulo actualizacion migracion base datos script version
last_updated: 2025-01-15
source_url: "https://ayudaprestashop.es/examples/upgrade-module"
---

# Upgrade scripts — actualizar modulo sin perder datos

> Escribir scripts de actualizacion para modulos PrestaShop: upgrade-X.X.X.php, migraciones de BD, cambios de configuracion y testing de upgrades.

## Como funciona el upgrade en PS

Cuando subes una nueva version de tu modulo, PrestaShop compara la version instalada (en BD) con la version del archivo `.php` principal. Si difieren, ejecuta automaticamente todos los scripts de `upgrade/` cuya version sea mayor que la instalada y menor o igual que la nueva.

*Orden de ejecucion*

```text
Version instalada: 1.0.0
Version nueva:     1.3.0

PS ejecuta en orden:
  upgrade/upgrade-1.1.0.php  ✓
  upgrade/upgrade-1.2.0.php  ✓
  upgrade/upgrade-1.2.5.php  ✓
  upgrade/upgrade-1.3.0.php  ✓

NO ejecuta:
  upgrade/upgrade-1.0.0.php  ✗ (version actual o menor)
  upgrade/upgrade-1.4.0.php  ✗ (mayor que la nueva version)
```

## Estructura de scripts de upgrade

*Arbol de archivos*

```text
modules/ecom_mimodulo/
├── ecom_mimodulo.php          # version = '1.3.0'
└── upgrade/
    ├── upgrade-1.1.0.php      # Anadir tabla nueva
    ├── upgrade-1.2.0.php      # Anadir columna + migrar datos
    ├── upgrade-1.2.5.php      # Registrar nuevo hook
    └── upgrade-1.3.0.php      # Renombrar config keys
```

*Formato basico de un script de upgrade*

```php
<?php
/**
 * upgrade/upgrade-1.1.0.php
 *
 * Naming OBLIGATORIO: upgrade-{version}.php
 * Funcion OBLIGATORIA: upgrade_module_{version_con_underscores}($module)
 */
if (!defined('_PS_VERSION_')) {
    exit;
}

function upgrade_module_1_1_0($module)
{
    // $module es la instancia de tu modulo
    // Devolver true = exito, false = error (PS aborta el upgrade)

    // ... hacer cambios ...

    return true;
}
```

## Ejemplo: anadir columna a tabla

*upgrade/upgrade-1.1.0.php — ALTER TABLE seguro*

```php
<?php
if (!defined('_PS_VERSION_')) {
    exit;
}

function upgrade_module_1_1_0($module)
{
    $db = Db::getInstance();
    $prefix = _DB_PREFIX_;

    // 1. Verificar si la columna ya existe (idempotencia)
    $columns = $db->executeS(
        "SHOW COLUMNS FROM `{$prefix}ecom_mimodulo` LIKE 'priority'"
    );

    if (empty($columns)) {
        $result = $db->execute(
            "ALTER TABLE `{$prefix}ecom_mimodulo`
             ADD COLUMN `priority` INT(10) UNSIGNED NOT NULL DEFAULT 0
             AFTER `position`"
        );
        if (!$result) {
            return false;
        }
    }

    // 2. Anadir indice si no existe
    $indexes = $db->executeS(
        "SHOW INDEX FROM `{$prefix}ecom_mimodulo` WHERE Key_name = 'idx_priority'"
    );
    if (empty($indexes)) {
        $db->execute(
            "ALTER TABLE `{$prefix}ecom_mimodulo`
             ADD INDEX `idx_priority` (`priority`)"
        );
    }

    // 3. Crear tabla nueva si es necesario
    $db->execute(
        "CREATE TABLE IF NOT EXISTS `{$prefix}ecom_mimodulo_log` (
            `id_log` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
            `id_mimodulo` INT(10) UNSIGNED NOT NULL,
            `action` VARCHAR(50) NOT NULL,
            `date_add` DATETIME NOT NULL,
            PRIMARY KEY (`id_log`),
            KEY `id_mimodulo` (`id_mimodulo`)
        ) ENGINE=" . _MYSQL_ENGINE_ . " DEFAULT CHARSET=utf8mb4"
    );

    return true;
}
```

## Ejemplo: migrar datos

*upgrade/upgrade-1.2.0.php — migrar datos entre estructuras*

```php
<?php
if (!defined('_PS_VERSION_')) {
    exit;
}

function upgrade_module_1_2_0($module)
{
    $db = Db::getInstance();
    $prefix = _DB_PREFIX_;

    // Escenario: migrar de config serializada a tabla propia
    // Antes: Configuration::get('ECOM_ITEMS') = serialized array
    // Ahora: tabla ecom_mimodulo_items

    // 1. Crear tabla nueva
    $db->execute(
        "CREATE TABLE IF NOT EXISTS `{$prefix}ecom_mimodulo_items` (
            `id_item` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
            `name` VARCHAR(255) NOT NULL,
            `value` TEXT,
            `position` INT(10) UNSIGNED NOT NULL DEFAULT 0,
            `active` TINYINT(1) NOT NULL DEFAULT 1,
            `date_add` DATETIME NOT NULL,
            PRIMARY KEY (`id_item`)
        ) ENGINE=" . _MYSQL_ENGINE_ . " DEFAULT CHARSET=utf8mb4"
    );

    // 2. Migrar datos de Configuration a tabla
    $oldData = Configuration::get('ECOM_ITEMS');
    if ($oldData) {
        $items = json_decode($oldData, true);
        if (!$items) {
            // Intentar unserialize (formato antiguo)
            $items = @unserialize($oldData);
        }

        if (is_array($items)) {
            foreach ($items as $i => $item) {
                $db->insert('ecom_mimodulo_items', [
                    'name'     => pSQL($item['name'] ?? 'Item ' . $i),
                    'value'    => pSQL($item['value'] ?? ''),
                    'position' => (int) $i,
                    'active'   => 1,
                    'date_add' => date('Y-m-d H:i:s'),
                ]);
            }
        }

        // 3. Eliminar config vieja
        Configuration::deleteByName('ECOM_ITEMS');
    }

    // 4. Renombrar config keys para consistencia
    $renames = [
        'ECOM_OLD_KEY_1' => 'ECOM_MIMODULO_ENABLED',
        'ECOM_OLD_KEY_2' => 'ECOM_MIMODULO_TITLE',
    ];

    foreach ($renames as $oldKey => $newKey) {
        $value = Configuration::get($oldKey);
        if ($value !== false) {
            Configuration::updateValue($newKey, $value);
            Configuration::deleteByName($oldKey);
        }
    }

    return true;
}
```

## Ejemplo: registrar nuevos hooks

*upgrade/upgrade-1.2.5.php — registrar hooks nuevos*

```php
<?php
if (!defined('_PS_VERSION_')) {
    exit;
}

function upgrade_module_1_2_5($module)
{
    // Registrar hooks que no existian en versiones anteriores
    $newHooks = [
        'displayProductExtraContent',
        'actionCartSave',
        'displayBackOfficeHeader',
    ];

    foreach ($newHooks as $hook) {
        if (!$module->isRegisteredInHook($hook)) {
            if (!$module->registerHook($hook)) {
                // No abortar por un hook — log y continuar
                PrestaShopLogger::addLog(
                    'ecom_mimodulo: Failed to register hook ' . $hook,
                    2 // Warning
                );
            }
        }
    }

    // Desregistrar hooks obsoletos
    $oldHooks = ['displayHeader']; // Ya no lo necesitamos
    foreach ($oldHooks as $hook) {
        $module->unregisterHook($hook);
    }

    // Actualizar valor de configuracion
    if (Configuration::get('ECOM_MIMODULO_VERSION') === false) {
        Configuration::updateValue('ECOM_MIMODULO_VERSION', $module->version);
    }

    return true;
}
```

## Buenas practicas

- [ ] SIEMPRE verificar si el cambio ya existe antes de aplicarlo (idempotencia)
- [ ] Nunca usar DROP TABLE — solo ALTER TABLE ADD/MODIFY
- [ ] Hacer backup de datos antes de migrar (SELECT INTO temporales)
- [ ] Devolver false SOLO si el error es critico y el modulo no puede funcionar
- [ ] Usar PrestaShopLogger para registrar warnings no criticos
- [ ] Testear upgrade desde CADA version anterior soportada
- [ ] Incluir en el nombre de funcion la version con underscores exactos
- [ ] No acceder a $this — usar el parametro $module
- [ ] No asumir que el modulo esta activo durante el upgrade

## Rollback manual

*Script de rollback (ejecutar manualmente si falla)*

```php
<?php
/**
 * NO es parte del sistema de upgrade de PS.
 * Es un script auxiliar para revertir cambios si algo sale mal.
 * Ejecutar via CLI: php modules/ecom_mimodulo/upgrade/rollback-1.2.0.php
 */
require_once dirname(__DIR__, 3) . '/config/config.inc.php';

$db = Db::getInstance();
$prefix = _DB_PREFIX_;

echo "Rollback 1.2.0 — Revertir migracion de datos\n";

// 1. Restaurar Configuration desde tabla
$items = $db->executeS("SELECT * FROM `{$prefix}ecom_mimodulo_items` ORDER BY position");
if ($items) {
    Configuration::updateValue('ECOM_ITEMS', json_encode($items));
    echo "  Config ECOM_ITEMS restaurada con " . count($items) . " items\n";
}

// 2. Restaurar keys renombradas
Configuration::updateValue('ECOM_OLD_KEY_1', Configuration::get('ECOM_MIMODULO_ENABLED'));
Configuration::updateValue('ECOM_OLD_KEY_2', Configuration::get('ECOM_MIMODULO_TITLE'));
Configuration::deleteByName('ECOM_MIMODULO_ENABLED');
Configuration::deleteByName('ECOM_MIMODULO_TITLE');

// 3. Forzar version en BD a la anterior
$db->execute(
    "UPDATE `{$prefix}module` SET version = '1.1.0'
     WHERE name = 'ecom_mimodulo'"
);

echo "Rollback completado. Version en BD: 1.1.0\n";
```


---

*Fuente: [https://ayudaprestashop.es/examples/upgrade-module](https://ayudaprestashop.es/examples/upgrade-module). Version Markdown generada automaticamente para consumo por LLMs.*
