.omni') vs. el que buscaba validate. * - FIX restauracion de BD: db_offset se calculaba con -size en vez de -HEADER_SIZE. * - FIX barra de progreso de importacion (escribia en .omni-progress.json en vez de .progress.json). * - MIGRACION: reemplazo de URLs ahora es SEGURO con datos serializados de PHP * (antes un REPLACE plano corrompia widgets/theme_mods/opciones serializadas). * - SEGURIDAD: proteccion anti Zip-Slip al extraer; el mu-plugin de recovery ahora * auto-expira (2h) y solo concede permisos a usuarios autenticados. RETIRADO: ese mu-plugin ya * no existe (ver el ultimo bloque). * - GRANDES (>1GB): FIX del timeout al subir archivos grandes (el ensamblado del * ultimo fragmento agotaba max_execution_time) con set_time_limit(0) en la subida * y en la descarga; reemplazo de URLs paginado por lotes para acotar memoria. * - MIGRACION: FIX de la restauracion tras cambiar la BD: la sesion del admin se * invalida y admin-ajax dejaba de despachar los pasos finales; ahora se registra * wp_ajax_nopriv_omnimigrate_import y esos pasos se autorizan por token de importacion. * - FIX: la exportacion de BD usa siempre el exportador PHP (formato que el importador * sabe parsear); se evita que mysqldump contamine el .sql con un warning. * Verificado end-to-end: subida y restauracion de un backup de 1.07 GiB por HTTP real. * * CHANGELOG 2.1.2 (restauracion entre sitios distintos): * - FIX CRITICO: los archivos se extraian en wp-content/wp-content/ (el exportador antepone * 'wp-content/' y el importador lo volvia a anteponer): el sitio restaurado quedaba sin * plugins, tema ni medios. Compatible con los backups ya creados. * - FIX: 'Finalizar' respondia con Content-Type text/html y el navegador lo daba por error * ('Error desconocido'), lanzando un rollback que fallaba. Ahora responde JSON y un fallo * en la limpieza final ya no revierte una restauracion completada. * - Al restaurar se mantiene activo este plugin y nunca se sobrescribe a si mismo. * - Aviso claro de que se restauran los usuarios del origen (y con cuales entrar). * - Mas variantes de URL al migrar (codificadas, //host), errores SQL contabilizados, * variables de sesion SQL en cada lote, conexion con puerto/socket y utf8mb4. * - Comprobacion del prefijo de tablas y registro de importacion (.import.log). * * CHANGELOG 2.1.3 (revision adversarial de la restauracion entre sitios): * - FIX CRITICO exportacion: las exclusiones (cache, upgrade...) se comparaban por nombre a * cualquier profundidad y se perdia codigo de plugins (p. ej. elementor/core/upgrade); * ahora se comparan por ruta desde wp-content. Ya no se excluye node_modules. * - SEGURIDAD: backups, volcados SQL, token y registros en una carpeta con nombre secreto * (uploads/lyn-backups//), nombres de backup con sufijo aleatorio, protecciones * Apache 2.2/2.4 + IIS, migracion de backups antiguos. Aviso en servidores nginx. * - SEGURIDAD: el mu-plugin de recovery ya no concede permisos (RETIRADO: ya no existe, ver el * ultimo bloque); upload_id validado (evita path traversal); import exige la capacidad * 'import'; deserializado sin instanciar clases del sitio (solo stdClass). * - Importacion aislada: mientras corre solo esta activo este plugin y ningun tema; los * mu-plugins y drop-ins del backup se instalan al finalizar. * - Reintentos seguros: bloqueo por paso y progreso guardado en el servidor (export e import), * lotes de exportacion a prueba de cortes y disco lleno, snapshot idempotente, subida * idempotente del ultimo trozo, finalizacion idempotente. * - Integridad: se rechazan backups truncados o con cabeceras danadas. * - URLs: sin duplicados aunque el destino contenga al origen (http://a -> http://a:8080), * paginacion por clave primaria (sin bucles), LIKE escapado, tablas sin clave primaria * seguras con datos serializados, siteurl/home fijados al final. * - Barra de progreso operativa tras el cambio de base de datos (token). * * CHANGELOG 2.2.0 (velocidad en sitios grandes + modales propios): * - RENDIMIENTO: la barra de progreso consultaba el servidor cada 2 s aunque la consulta * anterior no hubiera terminado. En sitios pesados (cada peticion tarda 3-4 s en cargar * WordPress) y con pocos procesos PHP (Local usa 2) se acumulaban hasta 37 consultas y los * lotes de exportacion esperaban detras: 2 GB / 90.000 archivos tardaban ~26 min. Ahora hay * una sola consulta a la vez y el intervalo se adapta a lo que tarda el servidor. * - RENDIMIENTO: modo rapido (mu-plugin lyn-backup-fast.php, se instalaba y retiraba solo): las * peticiones AJAX de OmniMigrate cargaban solo este plugin, sin los demas ni el tema. RETIRADO: * el plugin ya no genera ningun PHP en wp-content/mu-plugins (ver mas abajo), y si queda un * lyn-backup-fast.php de una version anterior se borra al actualizar. * - RENDIMIENTO exportacion: lotes de 15 s (antes 10) sin pausa entre lotes; cada archivo se * copia con un fopen + fstat + stream_copy_to_stream (antes 5 comprobaciones aparte y bucle * de lectura); la lista de archivos se retoma por posicion en bytes (antes se releia desde el * principio en cada lote) y se escribe sin cargarla entera en memoria. * - RENDIMIENTO importacion: extraccion con cache de carpetas y copia directa; lotes de base * de datos por tiempo; tamano de los trozos de subida segun el limite del servidor (con 25 MB * fijos la subida fallaba siempre en hostings con upload_max_filesize menor). * - Modales propios (confirmaciones y avisos) en lugar de los del navegador; restaurar exige * marcar una casilla de confirmacion. * - En las paginas publicas el plugin ya no hace nada (antes comprobaba carpetas en cada visita). * Correcciones de la revision adversarial (24 fallos confirmados, varios ya de 2.1.x): * - Carpeta de backups igual en todas las peticiones aunque un plugin filtre upload_dir (S3, * WP-Stateless...) y nunca en una ruta s3://; antes la restauracion no encontraba su estado. * - Modo rapido (ya retirado): leia GET+POST (no cookies), dejaba fuera los pasos que comprueban * permisos (inicio de exportacion, validar, restaurar del servidor), solo actuaba con la * version que lo escribio y no se usaba en multisitio; los pasos de importacion se autorizan * solo con token. * - Base de datos: conexion perdida a mitad de lote -> se repite la sentencia y, si vuelve a * fallar, se detiene (antes la importacion "terminaba bien" con tablas sin importar); nunca * se corta un lote tras DROP/CREATE; un CREATE TABLE que falla detiene la importacion; * volcados SQL con escrituras comprobadas; rollback que no reescribe la BD si no se toco y * que responde bien si se repite. * - Exportacion: disco o cuota llenos ya no se confunden con un archivo que cambia; uniones * de Windows incluidas con proteccion de bucles; nombres con caracteres de control y fechas * anteriores a 1970 que el importador rechazaba; limpieza del temporal tras un error. * - URLs dentro de objetos serializados de clases del sitio tambien se migran (sin instanciar * clases: se recorre el texto serializado). * - Interfaz: doble clic sobre los modales, pagina bloqueada durante el proceso, aviso al * salir a mitad, sin la ventana de "sesion caducada" de WordPress encima del progreso, trozos * de subida que se adaptan al limite real, filas borradas por la retencion y aviso si un * borrado falla. * * Segunda revision adversarial: * - La tabla de opciones se importa con otro nombre y sustituye a la del sitio de golpe al * final (RENAME TABLE): un corte a mitad ya no deja WordPress sin poder arrancar ni impide * deshacer. * - Un INSERT que falla (disco o tabla llenos, fila demasiado grande) detiene la importacion * para deshacerla; repetir un lote ya ejecutado en parte no duplica filas ni aborta. * - Colaciones y juegos de caracteres que el servidor no conoce (MySQL 8 <-> MariaDB 11) se * traducen al fallar el CREATE; las sensibles a acentos o mayusculas pasan a binaria para no * juntar valores distintos en una clave unica. * - Exportacion: sin vistas (una vista rota impedia toda copia), columnas generadas fuera del * INSERT y sentencias que nunca superan max_allowed_packet del propio servidor. * - URLs: tampoco se actualizan columnas generadas; los serializados que unserialize() rechaza * (enums, Serializable de clases ausentes) se recorren en lugar de romperse. * - Carpeta de backups fija (wp-content/uploads/lyn-backups), con migracion de la ubicacion * anterior solo dentro del mismo disco (si no, se avisa para moverla a mano). * - El permiso temporal de una restauracion se renueva mientras avanza (antes caducaba a las * 2 h) y una restauracion interrumpida (pestana cerrada, fallo al deshacer) se puede deshacer * despues desde un aviso de la pagina (hasta 7 dias). * - Claves duplicadas: solo se toleran al repetir un lote cortado; una colision real detiene y * deshace la restauracion. Un CREATE sin COLLATE (MySQL 5.7, MariaDB 10) conserva la * colacion de su origen en vez de tomar la de MySQL 8, que juntaba valores distintos. * - Copias de versiones anteriores: vistas y columnas generadas se restauran (antes la * restauracion fallaba o dejaba esas tablas vacias); colaciones utf8mb3 de MariaDB 11. * - Peticiones que esperaban en cola ya no pueden continuar una importacion que se esta * deshaciendo; el cambio de la tabla de opciones es repetible; tras deshacer se vacia la * cache de objetos (Redis, Memcached). * * Cuarta revision adversarial: * - Solo se copian, restauran y deshacen las tablas de ESTE sitio: las de otra instalacion de * la misma base de datos (otro sitio del hosting, un clon de WP Staging) ya no se tocan. * - Mientras la base de datos esta a medias (importar, URLs, deshacer) los visitantes ven un * aviso de mantenimiento (503) y no escriben filas que choquen con la copia; al deshacer, gana * la fila del snapshot. * - Enlaces simbolicos a carpetas (uploads en Pantheon, Capistrano, Bedrock) incluidos, y aviso * al terminar si algo no se ha podido copiar. * - Reemplazo de URLs con memoria acotada (Elementor, Divi) y reanudable fila a fila; inicio de * la exportacion repetible tras un timeout del proxy; subidas rechazadas o abandonadas borradas. * - La restauracion sin terminar ya no se pierde al intentar otra; su aviso caduca a los 7 dias * y muestra la fecha de la copia; varias pestanas comparten el permiso. * - Uniones de Windows comparadas por identidad de carpeta (antes, con nombres cortos 8.3, no * se detectaban bucles ni carpetas excluidas); la retencion nunca borra la copia recien hecha. * - Pasos comparados tal cual (una variante como 'Init' ya no ejecuta otro paso) y avisos * propios si el backup a borrar ya no existia o su nombre no es valido; boton para repetir el * deshacer si falla. * * Quinta revision adversarial: * - Otra instalacion de la misma base de datos se reconoce tambien si comparte los usuarios de * este sitio (CUSTOM_USER_TABLE), y las tablas de usuarios que usa este sitio nunca se dan por * ajenas; las tablas de otra instalacion que no se copian constan en el registro y en el aviso. * - Una restauracion nueva solo hereda la copia de la base de datos de una anterior sin terminar * en un reintento poco despues del fallo (antes podia devolver el sitio a una copia de dias). * - Fechas de las copias en la hora del sitio (antes en UTC). * - URLs en tablas sin clave primaria: con presupuesto de tiempo y reanudables sin reescribir dos * veces, y sin saltarse valores largos que empiezan igual. * - Al repetir un lote cortado consta el error real de MySQL (tabla llena, bloqueo). * - Con una restauracion anterior sin terminar, el modal de restaurar pregunta a que estado debe * volver deshacer si la nueva falla (antes se decidia en silencio por la antiguedad del aviso); * las copias de la base de datos que se apartan aparecen en la pagina para descargarlas o * eliminarlas. * - URLs en tablas sin clave con columnas latin1/cp1251: tambien los valores con acentos; un * bloqueo al preparar la tabla detiene el paso en vez de darla por hecha. * * Revision de WordPress.org, punto 2 (nonce y capacidad antes de procesar peticiones): * - Repasadas las 87 lecturas de $_GET, $_POST, $_REQUEST, $_FILES y $_COOKIE del plugin, una * por una. Todas estaban ya detras de nonce + capacidad, asi que no ha habido que cambiar * codigo; lo que faltaba era poder demostrarlo, y ahora consta aqui: * . Las siete acciones AJAX con su propio nonce y su capacidad: omnimigrate_export y omnimigrate_get_log con * 'export', omnimigrate_import, omnimigrate_upload_chunk y omnimigrate_restore_server con 'import', * omnimigrate_save_settings con 'manage_options', y el tema de la pantalla con 'export'. * . Las tres acciones de la pantalla (descargar, descargar un volcado y eliminar) con un nonce * distinto cada una y su capacidad. * . Los cuatro parametros de $_GET que lee enqueue_assets() solo eligen que aviso se pinta * tras una redireccion del propio plugin; no se guarda ni se ejecuta nada con ellos. * . WP-CLI y la copia programada no leen entrada: RELLENAN $_POST con las opciones elegidas, * porque es de donde las lee el paso 'init', y lo dejan como estaba al salir. * - Las dos acciones 'nopriv' (omnimigrate_import y omnimigrate_progress) son las unicas que no pueden exigir * nonce, y solo en los pasos posteriores al cambio de la base de datos: la cookie de sesion se * valida contra la tabla de usuarios, que en ese momento acaba de ser reemplazada por la del * backup, asi que cualquier nonce es invalido por definicion. Esos pasos se autorizan con un * token de 64 caracteres aleatorios guardado en el almacen de copias, fuera de la raiz web y * en una carpeta de nombre secreto, comparado con hash_equals() y con caducidad. 'validate' y * 'resume', que son los dos pasos que SI pueden, siguen exigiendo nonce y capacidad. * * Revision de WordPress.org, punto 3 (prefijos de 4 caracteres como minimo): * - 'Omni' y 'omni_' tenian 3. Todo pasa al prefijo del slug del plugin, que es el que ya usaban * las opciones (omnimigrate_*) y las constantes (OMNIMIGRATE_*): * . Las 13 clases: Omni_Main -> OmniMigrate_Main, y asi las demas. * . Las 8 acciones AJAX, que son hooks de verdad (wp_ajax_*), y sus nonces: omni_export -> * omnimigrate_export, omni_import, omni_progress, omni_get_log, omni_save_settings, * omni_upload_chunk, omni_restore_server y omni_tema. * . Los 3 parametros con los que la pantalla se llama a si misma (descargar, descargar un * volcado y eliminar), que no son del espacio de nombres de nadie pero asi no queda ni un * 'omni_' de tres letras en el codigo. * - No ha hecho falta migrar nada: las opciones, el meta del tema, las dos tareas de cron, el * filtro y los handles de los scripts YA llevaban el prefijo largo, asi que nadie pierde sus * ajustes ni su programacion al actualizar. * - LA EXTENSION .omni NO SE TOCA. No es ninguna de las categorias de su tabla (no es una * funcion, ni un hook, ni una opcion) y hay copias de 1 a 4 GB ya hechas que tienen que seguir * restaurandose. Tampoco los nombres de fichero (class-omnimigrate-main.php), que no son * identificadores, ni las clases de CSS, ni el objeto omniBackup del JavaScript, que no estan * en el espacio de nombres de PHP. * * Revision de WordPress.org, punto 4 (localizar ficheros y carpetas correctamente): * - El almacen de copias pasa de wp-content/uploads/lyn-backups a WP-CONTENT/OMNIMIGRATE, con el * nombre del plugin. Ya no finge estar dentro de la carpeta de subidas, que es lo que estaba * mal. Dentro sigue la subcarpeta de nombre secreto y las protecciones de Apache 2.2/2.4, * IIS y listado de directorio. * - NO se usa wp_upload_dir(): esa funcion lee la opcion 'upload_path' de la base de datos y * pasa por el filtro 'upload_dir'. A mitad de una restauracion la tabla de opciones es la de * OTRO sitio y los plugins cargados no son los mismos de una peticion a la siguiente, asi que * el estado, el token y la copia para deshacer se buscarian donde no estan. Una carpeta propia * bajo wp-content es la excepcion que las propias normas describen para los plugins de copias. * - Lo que hubiera en las dos ubicaciones anteriores se trae solo: si todavia no hay almacen * nuevo se adopta la clave de la carpeta vieja y se mueve entera con un solo rename(), asi * viajan tambien el estado de una restauracion a medias, su token y su copia para deshacer. Si * no se puede (otro disco), el panel mueve los .omni uno a uno y avisa de lo que no pudo. * - Al desinstalar se barren los ficheros de trabajo de las DOS ubicaciones, y se anaden los que * faltaban (bloqueos, marcador de mantenimiento y volcados sin fecha en el nombre). * * Revision de WordPress.org, punto 5 (no forzar limites de PHP globalmente): * - batch_seconds() ya SOLO LEE max_execution_time; antes lo quitaba, y la llama tambien el * diagnostico de la pantalla, que no tiene por que cambiarle nada a la peticion. Quitar el * limite es cosa de los sitios que de verdad tardan, y cada uno lo hace al entrar: el lote de * exportar, el de importar, la descarga de un fichero, la subida de un fragmento y la copia * programada. Los dos lotes lo hacen antes de llegar a la cuenta, asi que sale igual que antes. * - Y el lote, medido despues de quitar el modo rapido: cada lote es una peticion, y cada peticion * carga WordPress con TODOS los plugins del sitio. En un sitio con 14 plugins (WPML, The Events * Calendar) eso son unos 6 s por lote frente a 0,3 s cargando solo este, y por eso una copia * que tardaba 29 s paso a tardar 48 s. Restaurar no lo nota, porque desde el paso 'snapshot' el * aislamiento deja activo solo este plugin; copiar si lo nota, porque el sitio tiene que seguir * funcionando, con sus plugins, mientras se hace. Para pagar ese arranque menos veces, el * copiado de archivos pide un lote de 45 s donde el servidor da margen de sobra * (max_execution_time sin limite o de 180 s para arriba) y se queda en los 15 s de siempre * donde el margen es justo; los 45 s van por debajo de los 60 s que espera nginx de serie. El * limite del servidor se recuerda ANTES de que el punto de entrada lo quite, porque leyendolo * despues saldria siempre 0 y hasta un hospedaje que corta pronto acabaria con el lote largo. * - Y para que un lote largo no pueda salir caro, el copiado guarda el progreso cada 10 s DENTRO * del lote, no solo al cerrarlo: si la peticion muere a medias, el reintento sigue desde ahi en * vez de repetir el lote entero. Comprobado matando un lote con SIGKILL a los 12 s de 17: el * progreso guardado sobrevivio, la cola de 47 MB que el lote muerto dejo escrita se descarto al * reanudar, y el .omni resultante salio byte a byte igual al de una copia de corrido. * * Revision de WordPress.org, punto 6 (usar el subidor de ficheros de WordPress): * - Los fragmentos de una subida ya no se guardan con move_uploaded_file() sino con * wp_handle_upload(), que comprueba el error de PHP, vuelve a comprobar is_uploaded_file(), * pasa el fichero por los filtros de subida del sitio y hace el movimiento el mismo. * - Con dos ajustes: 'test_type' => false, porque un fragmento es un corte de bytes de un .omni * por la mitad y no tiene tipo MIME ni extension (el fichero se comprueba entero y por su * cabecera en el paso 'validate'); y un filtro de 'upload_dir' que se pone y se quita alrededor * de la llamada, para que el fragmento caiga en la carpeta protegida de esa subida y no en * uploads//, donde se serviria por web. * * Revision de WordPress.org, punto 7 (llamadas SQL): * - ARREGLADO UN FALLO DE VERDAD, que es lo que ha salido de repasar las consultas una por una: * los nombres de tabla y de columna se citaban con real_escape_string(), que escapa comillas, * barras invertidas y saltos de linea pero NO el acento grave, que es justo el caracter que * cierra un identificador en MySQL. Y los nombres de tabla no los decide el plugin: salen de * SHOW FULL TABLES, y despues de una restauracion son los que venian DENTRO del fichero .omni * que ha subido el usuario. Ahora hay un solo quote_identifier() que dobla el acento grave y * lo usan los 20 sitios donde se mete un identificador en una consulta. Probado creando de * verdad una tabla con un acento grave en el nombre y en una columna, volcandola y volviendo a * importar el volcado sin un solo error. * - Los valores siguen yendo en sentencias preparadas con bind_param() o por * real_escape_string(), que para un valor si es lo correcto. Ninguna consulta concatena nada * que venga de $_GET, $_POST ni de una cookie. * - La conexion propia (el new mysqli que cita la revision) NO se puede sustituir por $wpdb, y * el motivo esta escrito entero encima de OmniMigrate_Database::connect(): $wpdb no lee en streaming * (get_results() carga el resultado entero: una tabla de 2 GB pediria 2 GB de PHP, y * _do_query() es privado), le quedarian puestas las variables de sesion de la importacion para * el resto de la peticion, no expone los codigos de error con los que se decide el reintento * de un lote cortado, con un db.php tipo HyperDB podria servir los metadatos desde una replica * distinta de la que se volca, y ante un fallo imprime HTML o llama a wp_die(), que en una * peticion AJAX rompe el JSON y dejaria una restauracion a medias sin poder deshacerla. * - De $wpdb SI se reutiliza su lectura de DB_HOST (parse_db_host: puertos, sockets, IPv6) y su * criterio de juego de caracteres, y los nombres de tabla salen de sus propiedades. * * Revision de WordPress.org, punto 8 (escribir en sitios no permitidos): * - EL PLUGIN YA NO GENERA NINGUN PHP. Los dos mu-plugins que escribia * (wp-content/mu-plugins/lyn-backup-fast.php y lyn-recovery.php) han desaparecido. El modo * rapido se ha quitado del todo; lo que hacia el de recuperacion se consigue ahora escribiendo * en la TABLA DE OPCIONES, que es la unica tabla que una restauracion nunca suelta (se importa * con otro nombre y se cambia de golpe con un RENAME): * . Desde el paso 'snapshot' (copia para deshacer ya hecha, ningun fichero tocado todavia), * active_plugins queda con este plugin y nada mas, y una opcion autocargada enciende el * guardian: 503 de mantenimiento para los visitantes, URLs del destino y sitio sin tema. * . Esas mismas filas se dejan escritas DENTRO de la tabla de opciones importada antes de su * RENAME, y se comprueban: asi el cambio atomico no abre ni un instante en el que el sitio * cargue los plugins del sitio de ORIGEN. Si no se pueden escribir, no se hace el RENAME. * . Al terminar se deja la lista de plugins que venia en el backup; al deshacer, la real del * sitio de destino, que se apunta antes de tocar nada. * . Tras cada escritura se invalida la cache de opciones: con Redis o Memcached, el alloptions * de antes del cambio cargaria los plugins del sitio de origen. * - Si queda un mu-plugin de una version anterior se borra al actualizar, al activar y al * desactivar, y ni se copia ni se restaura desde dentro de un backup antiguo. */ if ( ! defined( 'ABSPATH' ) ) exit; define( 'OMNIMIGRATE_FILE', __FILE__ ); define( 'OMNIMIGRATE_DIR', plugin_dir_path( __FILE__ ) ); require_once OMNIMIGRATE_DIR . 'lib/class-omnimigrate-i18n.php'; require_once OMNIMIGRATE_DIR . 'lib/class-omnimigrate-tema.php'; require_once OMNIMIGRATE_DIR . 'lib/class-omnimigrate-archive.php'; require_once OMNIMIGRATE_DIR . 'lib/class-omnimigrate-database.php'; require_once OMNIMIGRATE_DIR . 'lib/class-omnimigrate-export.php'; require_once OMNIMIGRATE_DIR . 'lib/class-omnimigrate-import.php'; require_once OMNIMIGRATE_DIR . 'lib/class-omnimigrate-main.php'; require_once OMNIMIGRATE_DIR . 'lib/class-omnimigrate-schedule.php'; // LO PRIMERO DE TODO, y en CUALQUIER peticion (tambien las publicas): si hay una restauracion en // curso, el sitio esta a medias. Mientras lo esta, este plugin es el unico activo en la tabla de // opciones, asi que es el que tiene que servir el 503 de mantenimiento a los visitantes, dar las // URLs del sitio de destino y dejar el sitio sin tema, para que no se cargue el functions.php de // un tema a medio sobrescribir. Antes esto lo hacia un fichero PHP que el plugin generaba en // wp-content/mu-plugins y que WordPress.org no permite. Sin restauracion en curso, esto es un // isset() sobre las opciones que el nucleo ya ha leido: ni una consulta de mas. OmniMigrate_Import::restore_guard(); // Al activar se reprograman las copias automaticas guardadas; al desactivar se retiran sus // tareas. Las dos cosas barren tambien los mu-plugins que generaban las versiones anteriores. register_activation_hook( __FILE__, array( 'OmniMigrate_Main', 'activate' ) ); register_deactivation_hook( __FILE__, array( 'OmniMigrate_Main', 'deactivate' ) ); // El idioma, antes que nada: decide que .mo se carga para este plugin y deja puesto el // selector de la pantalla. Son dos add_filter/add_action; no traduce nada todavia. OmniMigrate_I18n::init(); // Las copias automaticas, fuera del if de abajo: el cron de WordPress NO es una peticion del // panel (is_admin() es false), asi que ahi dentro no se enterarian de que les toca trabajar. // Son dos add_action y nada mas; en una visita normal no hacen nada. OmniMigrate_Schedule::init(); // Los comandos de consola solo existen cuando se ejecuta WP-CLI: ni se carga el fichero en una // peticion normal. if ( defined( 'WP_CLI' ) && WP_CLI ) { require_once OMNIMIGRATE_DIR . 'lib/class-omnimigrate-cli.php'; WP_CLI::add_command( 'omni', 'OmniMigrate_CLI' ); } // Solo en el panel y en admin-ajax (is_admin() es true en ambos): en las paginas publicas // el plugin no tiene nada que hacer. if ( is_admin() ) { // El tema de la pantalla: un solo add_action para guardarlo por AJAX. OmniMigrate_Tema::init(); new OmniMigrate_Main(); }