Fix: AbstractAction::save_job_info() now flushes the WordPress object cache before calling update_option(). The 2.1.1 fix only flushed on SQL import completion in RestoreDatabaseTask, but SQL import is split into BATCH_SIZE=100-statement chunks across multiple HTTP requests (needs_continue) to avoid PHP max_execution_time. This affects any restore where the source site’s SQL dump exceeds ~100 statements — a standard WP install with 15-30 tables (DROP + CREATE + INSERT each) plus chunked INSERTs for large tables typically exceeds this, so the bug can fire even on a first restore if the source is sized normally. Symptom: wp_options gets DROPed/CREATEd/INSERTed during a chunk, save_job_info is called at the chunk boundary, update_option reads the stale cached value as $old_value, $wpdb->update() returns 0 rows, add_option fallback is also skipped (cache says value exists), so restore_info is never persisted. The next GET /restore/{id} returns 404 Not Found. Flushing before each save_job_info call fixes this and also guards against future tasks that touch the DB (Issue #49).
2.1.2
Fix: Backup now excludes wp-content/object-cache.php, wp-content/advanced-cache.php (WordPress drop-ins), and wp-content/mu-plugins/ from archives. Previously these were copied from source and overwrote destination-specific files — the source provider’s Redis/Memcached drop-in config would clash with the destination’s cache plugin config (PHP fatal -> 500), and source-provider-specific mu-plugins (WAF, CDN, security) would overwrite destination-provider mu-plugins that the destination hosting ships (Issue #42).
Fix: BackupDatabaseTask now emits mysqldump-compatible session setup at the head of the dump file (SET NAMES utf8mb4, TIME_ZONE=’+00:00′, FOREIGN_KEY_CHECKS=0, UNIQUE_CHECKS=0, SQL_MODE=’NO_AUTO_VALUE_ON_ZERO,ALLOW_INVALID_DATES’, SQL_NOTES=0) and restores @OLD_* variables in the footer. This fixes restore failures when migrating from MySQL 5.7 to 8.0, where stricter default SQL_MODE rejected 0000-00-00 dates (post_date_gmt on legacy sites) and AUTO_INCREMENT=0 rows, and where an implicit TIME_ZONE mismatch shifted datetime values between source and destination (Issue #43).
2.1.1
Fix: RestoreDatabaseTask now flushes the WordPress object cache after completing SQL import. Without this, update_option() on freshly restored wp_options sees stale cached values as $old_value and skips the add_option() fallback, leaving $wpdb->update() returning 0 rows. As a result, RestoreAction::save_job_info() failed to persist restore_info to the actual DB, causing GET /restore/{id} to return 404 right after restore completion (Issue #36).
2.1.0
Fix: restore download fully downloads multi-GB archives by looping Range-chunk reads within a single request. The loop exits when remaining time is below DOWNLOAD_TIMEOUT so it never starts a 30s wp_remote_get with only a few seconds of task budget left.
Fix: backup excluded the plugin’s own work directories (uploads/{brand}-backup, uploads/{brand}-restore) only via a regex that did not match brand names containing underscores (e.g., onamae_mig) — rewrote to use Config::get_brand() so backups no longer pull in their own archives (snowball growth).
Fix: handle_backup / handle_restore now return an error if deleting a stale FAILED job fails, instead of silently proceeding to start() with leftover state.
API change: POST /backup and POST /restore now accept an optional backup_id / restore_id from the caller. The plugin reuses an existing job if one exists, or starts a new job with the supplied id otherwise. Omitting the id keeps the previous behavior (auto-generated id). This lets the batch layer tie a job to wordpress_migrations.backup_key so retries resume the same work directory instead of creating a new one each time.
Security: sanitize_job_id now rejects invalid IDs (returning empty string) instead of silently stripping disallowed characters, to prevent accidental ID collisions (e.g. a/b and ab both reducing to the same job) and path traversal via externally supplied ids.
Cleanup: remove the unused continue field from RestoreDownloadTask::download_chunk() now that the loop is driven by the task’s remaining time.
2.0.2
Remove flush_rewrite_rules() from RestoreFinishTask (delegate to batch-side wp-cli).