383 lines
9.3 KiB
PHP
383 lines
9.3 KiB
PHP
<?php
|
|
/**
|
|
* Theme Options Migrator Class
|
|
*
|
|
* Migra configuraciones de wp_options a tabla personalizada wp_apus_theme_components
|
|
*
|
|
* @package Apus_Theme
|
|
* @since 2.0.0
|
|
*/
|
|
|
|
if (!defined('ABSPATH')) {
|
|
exit;
|
|
}
|
|
|
|
class APUS_Theme_Options_Migrator {
|
|
|
|
/**
|
|
* DB Manager instance
|
|
*/
|
|
private $db_manager;
|
|
|
|
/**
|
|
* Nombre de la opción en wp_options
|
|
*/
|
|
const OLD_OPTION_NAME = 'apus_theme_options';
|
|
|
|
/**
|
|
* Nombre del componente en la nueva tabla
|
|
*/
|
|
const COMPONENT_NAME = 'theme';
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
public function __construct() {
|
|
$this->db_manager = new APUS_DB_Manager();
|
|
}
|
|
|
|
/**
|
|
* Mapeo de tipos de datos para cada configuración
|
|
*
|
|
* @return array Mapeo config_key => data_type
|
|
*/
|
|
private function get_data_types_map() {
|
|
return array(
|
|
// Integers (IDs y contadores)
|
|
'site_logo' => 'integer',
|
|
'site_favicon' => 'integer',
|
|
'excerpt_length' => 'integer',
|
|
'archive_posts_per_page' => 'integer',
|
|
'related_posts_count' => 'integer',
|
|
'related_posts_columns' => 'integer',
|
|
|
|
// Booleans (enable_*, show_*, performance_*)
|
|
'enable_breadcrumbs' => 'boolean',
|
|
'show_featured_image_single' => 'boolean',
|
|
'show_author_box' => 'boolean',
|
|
'enable_comments_posts' => 'boolean',
|
|
'enable_comments_pages' => 'boolean',
|
|
'show_post_meta' => 'boolean',
|
|
'show_post_tags' => 'boolean',
|
|
'show_post_categories' => 'boolean',
|
|
'enable_lazy_loading' => 'boolean',
|
|
'performance_remove_emoji' => 'boolean',
|
|
'performance_remove_embeds' => 'boolean',
|
|
'performance_remove_dashicons' => 'boolean',
|
|
'performance_defer_js' => 'boolean',
|
|
'performance_minify_html' => 'boolean',
|
|
'performance_disable_gutenberg' => 'boolean',
|
|
'enable_related_posts' => 'boolean',
|
|
|
|
// Strings (todo lo demás: URLs, textos cortos, formatos, CSS/JS)
|
|
// No es necesario especificarlos, 'string' es el default
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Determinar tipo de dato para una configuración
|
|
*
|
|
* @param string $config_key Nombre de la configuración
|
|
* @param mixed $config_value Valor de la configuración
|
|
* @return string Tipo de dato (string, boolean, integer, json)
|
|
*/
|
|
private function determine_data_type($config_key, $config_value) {
|
|
$types_map = $this->get_data_types_map();
|
|
|
|
// Si está en el mapa explícito, usar ese tipo
|
|
if (isset($types_map[$config_key])) {
|
|
return $types_map[$config_key];
|
|
}
|
|
|
|
// Detección automática por valor
|
|
if (is_array($config_value)) {
|
|
return 'json';
|
|
}
|
|
|
|
if (is_bool($config_value)) {
|
|
return 'boolean';
|
|
}
|
|
|
|
if (is_int($config_value)) {
|
|
return 'integer';
|
|
}
|
|
|
|
// Default: string (incluye textos largos, URLs, etc.)
|
|
return 'string';
|
|
}
|
|
|
|
/**
|
|
* Normalizar valor según tipo de dato
|
|
*
|
|
* @param mixed $value Valor a normalizar
|
|
* @param string $data_type Tipo de dato
|
|
* @return mixed Valor normalizado
|
|
*/
|
|
private function normalize_value($value, $data_type) {
|
|
switch ($data_type) {
|
|
case 'boolean':
|
|
// Convertir a booleano real (maneja strings '0', '1', etc.)
|
|
return filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ?? false;
|
|
|
|
case 'integer':
|
|
return (int) $value;
|
|
|
|
case 'json':
|
|
// Si ya es array, dejarlo así (DB Manager lo codificará)
|
|
return is_array($value) ? $value : json_decode($value, true);
|
|
|
|
case 'string':
|
|
default:
|
|
return (string) $value;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Verificar si ya se realizó la migración
|
|
*
|
|
* @return bool True si ya está migrado, false si no
|
|
*/
|
|
public function is_migrated() {
|
|
// La migración se considera completa si:
|
|
// 1. No existe la opción antigua en wp_options
|
|
// 2. Y existen configuraciones en la tabla nueva
|
|
|
|
$old_options = get_option(self::OLD_OPTION_NAME, false);
|
|
$new_config = $this->db_manager->get_config(self::COMPONENT_NAME);
|
|
|
|
// Si no hay opción antigua Y hay configuraciones nuevas = migrado
|
|
return ($old_options === false && !empty($new_config));
|
|
}
|
|
|
|
/**
|
|
* Ejecutar migración completa
|
|
*
|
|
* @return array Resultado de la migración con éxito, mensaje y detalles
|
|
*/
|
|
public function migrate() {
|
|
// 1. Verificar si ya se migró
|
|
if ($this->is_migrated()) {
|
|
return array(
|
|
'success' => false,
|
|
'message' => 'La migración ya fue realizada anteriormente',
|
|
'already_migrated' => true
|
|
);
|
|
}
|
|
|
|
// 2. Obtener configuraciones actuales de wp_options
|
|
$old_options = get_option(self::OLD_OPTION_NAME, array());
|
|
|
|
if (empty($old_options)) {
|
|
return array(
|
|
'success' => false,
|
|
'message' => 'No hay opciones para migrar en wp_options'
|
|
);
|
|
}
|
|
|
|
// 3. Crear backup antes de migrar
|
|
$backup_result = $this->create_backup($old_options);
|
|
if (!$backup_result['success']) {
|
|
return $backup_result;
|
|
}
|
|
|
|
$backup_name = $backup_result['backup_name'];
|
|
|
|
// 4. Migrar cada configuración
|
|
$total = count($old_options);
|
|
$migrated = 0;
|
|
$errors = array();
|
|
|
|
foreach ($old_options as $config_key => $config_value) {
|
|
// Determinar tipo de dato
|
|
$data_type = $this->determine_data_type($config_key, $config_value);
|
|
|
|
// Normalizar valor
|
|
$normalized_value = $this->normalize_value($config_value, $data_type);
|
|
|
|
// Guardar en tabla personalizada
|
|
$result = $this->db_manager->save_config(
|
|
self::COMPONENT_NAME,
|
|
$config_key,
|
|
$normalized_value,
|
|
$data_type,
|
|
APUS_ADMIN_PANEL_VERSION
|
|
);
|
|
|
|
if ($result !== false) {
|
|
$migrated++;
|
|
} else {
|
|
$errors[] = $config_key;
|
|
}
|
|
}
|
|
|
|
// 5. Verificar resultado de la migración
|
|
if ($migrated === $total) {
|
|
// Éxito total
|
|
// Eliminar opción antigua de wp_options
|
|
delete_option(self::OLD_OPTION_NAME);
|
|
|
|
return array(
|
|
'success' => true,
|
|
'message' => sprintf('Migradas %d configuraciones correctamente', $migrated),
|
|
'migrated' => $migrated,
|
|
'total' => $total,
|
|
'backup_name' => $backup_name
|
|
);
|
|
} else {
|
|
// Migración parcial o con errores
|
|
return array(
|
|
'success' => false,
|
|
'message' => sprintf('Solo se migraron %d de %d configuraciones', $migrated, $total),
|
|
'migrated' => $migrated,
|
|
'total' => $total,
|
|
'errors' => $errors,
|
|
'backup_name' => $backup_name
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Crear backup de las opciones actuales
|
|
*
|
|
* @param array $options Opciones a respaldar
|
|
* @return array Resultado con success y backup_name
|
|
*/
|
|
private function create_backup($options) {
|
|
$backup_name = self::OLD_OPTION_NAME . '_backup_' . date('Y-m-d_H-i-s');
|
|
|
|
$result = update_option($backup_name, $options, false); // No autoload
|
|
|
|
if ($result) {
|
|
return array(
|
|
'success' => true,
|
|
'backup_name' => $backup_name
|
|
);
|
|
} else {
|
|
return array(
|
|
'success' => false,
|
|
'message' => 'No se pudo crear el backup de seguridad'
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Rollback de migración (revertir a estado anterior)
|
|
*
|
|
* @param string $backup_name Nombre del backup a restaurar
|
|
* @return array Resultado del rollback
|
|
*/
|
|
public function rollback($backup_name = null) {
|
|
// Si no se especifica backup, buscar el más reciente
|
|
if ($backup_name === null) {
|
|
$backup_name = $this->find_latest_backup();
|
|
}
|
|
|
|
if ($backup_name === null) {
|
|
return array(
|
|
'success' => false,
|
|
'message' => 'No se encontró backup para restaurar'
|
|
);
|
|
}
|
|
|
|
// Obtener backup
|
|
$backup = get_option($backup_name, false);
|
|
|
|
if ($backup === false) {
|
|
return array(
|
|
'success' => false,
|
|
'message' => sprintf('Backup "%s" no encontrado', $backup_name)
|
|
);
|
|
}
|
|
|
|
// Restaurar en wp_options
|
|
$restored = update_option(self::OLD_OPTION_NAME, $backup);
|
|
|
|
if ($restored) {
|
|
// Eliminar configuraciones de la tabla personalizada
|
|
$this->db_manager->delete_config(self::COMPONENT_NAME);
|
|
|
|
return array(
|
|
'success' => true,
|
|
'message' => 'Rollback completado exitosamente',
|
|
'backup_used' => $backup_name
|
|
);
|
|
} else {
|
|
return array(
|
|
'success' => false,
|
|
'message' => 'No se pudo restaurar el backup'
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Buscar el backup más reciente
|
|
*
|
|
* @return string|null Nombre del backup más reciente o null
|
|
*/
|
|
private function find_latest_backup() {
|
|
global $wpdb;
|
|
|
|
// Buscar opciones que empiecen con el patrón de backup
|
|
$pattern = self::OLD_OPTION_NAME . '_backup_%';
|
|
|
|
$backup_name = $wpdb->get_var($wpdb->prepare(
|
|
"SELECT option_name FROM {$wpdb->options}
|
|
WHERE option_name LIKE %s
|
|
ORDER BY option_id DESC
|
|
LIMIT 1",
|
|
$pattern
|
|
));
|
|
|
|
return $backup_name;
|
|
}
|
|
|
|
/**
|
|
* Listar todos los backups disponibles
|
|
*
|
|
* @return array Lista de nombres de backups
|
|
*/
|
|
public function list_backups() {
|
|
global $wpdb;
|
|
|
|
$pattern = self::OLD_OPTION_NAME . '_backup_%';
|
|
|
|
$backups = $wpdb->get_col($wpdb->prepare(
|
|
"SELECT option_name FROM {$wpdb->options}
|
|
WHERE option_name LIKE %s
|
|
ORDER BY option_id DESC",
|
|
$pattern
|
|
));
|
|
|
|
return $backups;
|
|
}
|
|
|
|
/**
|
|
* Eliminar un backup específico
|
|
*
|
|
* @param string $backup_name Nombre del backup a eliminar
|
|
* @return bool True si se eliminó, false si no
|
|
*/
|
|
public function delete_backup($backup_name) {
|
|
return delete_option($backup_name);
|
|
}
|
|
|
|
/**
|
|
* Obtener estadísticas de la migración
|
|
*
|
|
* @return array Estadísticas
|
|
*/
|
|
public function get_migration_stats() {
|
|
$old_options = get_option(self::OLD_OPTION_NAME, array());
|
|
$new_config = $this->db_manager->get_config(self::COMPONENT_NAME);
|
|
$backups = $this->list_backups();
|
|
|
|
return array(
|
|
'is_migrated' => $this->is_migrated(),
|
|
'old_options_count' => count($old_options),
|
|
'new_config_count' => count($new_config),
|
|
'backups_count' => count($backups),
|
|
'backups' => $backups
|
|
);
|
|
}
|
|
}
|