CodePoint Server-to-Server Migration — changelog archive
========================================

Releases from 2.7.7 back to 1.0.0. The most recent releases are listed in
readme.txt and on the plugin's WordPress.org page.

= 2.7.7 =
* Fix: 2.7.6's Connect-always-resets behavior was too broad — reconnecting to the SAME site mid-migration (e.g. re-checking the comparison table) would also wipe progress. Connect now only resets when the source actually changes (or nothing was in progress yet); reconnecting to a site you're already migrating keeps every counter exactly as it was. A confirmation line now states clearly whether progress was kept or this is a fresh start
* This does not change plain resume (closing the tab and reopening) — that path never calls Connect and was never affected

= 2.7.6 =
* Fix: connecting to a new source no longer reuses leftover progress from a previous attempt. Previously, pasting a different (or the same) key and pressing Connect kept stale byte counts, manifest offsets, and sweep state from whatever was run before — which could surface as "Manifest missing" or, worse, silently reuse a stale local file check. Connect now always starts every counter from zero and clears any locally-cached manifest/database dump, so switching which old site you're migrating from is safe without pressing Reset first. The mirror-cleanup preference and Advanced exclusions are kept, since those are deliberate choices, not progress

= 2.7.5 =
* Design: removed the "Verified" status indicator from the migration-path card — just the plain "Migrating from / Migrating to" summary now
* No functional changes

= 2.7.4 =
* Design: replaced the dark instrument-panel migration-path card with a plain light card matching the rest of the UI — no dark background, no motion, no decorative brackets. Clear "Migrating from / Migrating to" labels, domain in monospace, a static arrow, and a quiet checkmark
* No functional changes

= 2.7.3 =
* Fix: root-level wp-content drop-ins (object-cache.php, advanced-cache.php, db.php, sunrise.php, and similar) are now protected the same way mu-plugins is — excluded from the source scan, and hard-refused on write on the destination regardless of the source's plugin version. Previously these were only protected from mirror-cleanup deletion, not from being overwritten during transfer, which could replace a working caching drop-in with an incompatible one and take the whole site down on the very next request

= 2.7.2 =
* Design: replaced the pulsing "LINKED" status badge with a quiet checkmark + "Verified" label, and the glowing traveling dot with a slow, subtle shimmer sweep along the connection line — a calmer, more editorial feel in place of the earlier game-HUD styling
* No functional changes

= 2.7.1 =
* Design: reworked the domain-flow indicator into a bolder signal-readout panel — dark instrument-style card with targeting corners, a live-linked status pip, and a pulse that visibly travels from the old domain to the new one
* Copy: clearer, plainer orientation text on both the OLD-site and NEW-site tabs
* Sharper corner radius across cards and controls for a more precise, technical feel
* No functional changes

= 2.7.0 =
* Visual redesign: modern light UI with a signal-violet/circuit-teal accent system, monospace type for every technical value (domains, paths, keys), and an animated domain-flow indicator showing OLD SITE -> NEW SITE once connected, so it's always clear which install is which
* New: short orientation text at the top of each tab explaining which role that site is playing
* No functional changes — all migration, security, and state-machine behavior is identical to 2.6.3

= 2.6.3 =
* Fix: mu-plugins protection is now enforced on the DESTINATION regardless of the source's version — 2.6.2's fix only worked once both sides were updated, since the exclusion lived in the source's scan. The file writer itself now unconditionally refuses to write anything under mu-plugins, so an un-updated or third-party source can never overwrite host-managed infrastructure (object caches, security modules) on the destination
* This closes the failure mode where a partially-transferred mu-plugins directory (mismatched file versions mid-copy) caused a site-wide fatal error

= 2.6.2 =
* Fix: mu-plugins is now excluded from the file transfer itself, not only from mirror-cleanup deletion. Previously the old site's mu-plugins content could be scanned and streamed onto the destination, colliding with host-managed mu-plugins (object caches, security modules) already there. mu-plugins on the destination is now left completely untouched: not scanned, not transferred, not swept.

= 2.6.1 =
* New: deferred hard permalink flush — finalize and cutover plant a flag, and the next request runs flush_rewrite_rules(true) against the swapped database, also rewriting the .htaccess WordPress block when writable. Prevents post-migration 404s on inner pages, including on fresh installs whose .htaccess never had the rewrite block
* New: the persistent object cache (Redis/Memcached) is flushed at swap time — it still holds the pre-swap site's options and content, which could otherwise be served as ghost data after finalize

= 2.6.0 =
* New: mirror cleanup (on by default) — after the file transfer, a resumable sweep removes files on the new site that the old site doesn't have, so the result is a true mirror rather than a merge. Protected and never deleted: mu-plugins, languages, root-level drop-ins (object-cache.php etc.), this plugin, its work directory, and anything excluded in Advanced
* New: pre-flight warning when the destination carries a caching drop-in from its previous setup, which can misbehave after the swap
* The database was already a clean swap — all previous destination tables move to the spold_ rollback backup at finalize

= 2.5.4 =
* New: when staging completes, a modal appears making the final step unmissable — explains that nothing is switched yet, carries the keep-admin option, and finalizes in place (completion summary with skip list shown inside the modal). Also appears when reloading a page whose migration is already staged. Dismissible — the Finalize card keeps working as before

= 2.5.3 =
* Fix: the Start button stayed visible while a migration was running — WordPress core button styles were overriding the hidden attribute; Start/Pause now swap correctly
* New: the progress area shows the file currently being transferred (path, live-updating, truncated for long paths)

= 2.5.2 =
* Fix: migrations halted with "No migration in progress" after the database pull — the 2.5.0 rewrite left one transition pointing at the removed extract phase; stranded runs now self-heal into the import phase on Resume
* New: skipped files are logged with path and reason (invalid path / outside wp-content / permissions, capped at 200) and shown as an expandable list on the finalize completion screen, so "3 files skipped" becomes actionable

= 2.5.1 =
* Compliance: annotated the streamed-file write with the PluginDirectoryWrite justification — the write restores the migrated site's wp-content (never this plugin's own folder, which is explicitly refused in the same loop). No functional changes

= 2.5.0 =
* Rearchitected file transfer: direct server-to-server streaming replaces zip build + extract. libzip rewrites the entire archive on every incremental close, making large sites O(n2) in disk I/O — the root cause of multi-GB migrations crawling or timing out. Files now stream in resumable 16MB framed batches straight into place: each file is read once, written once, with per-file byte-offset resume for oversized files
* Removed: ZipArchive requirement, the extraction phase, and the 2x disk-space requirement on the source
* Progress now shows real byte-level transfer progress (transferred / total)
* Every streamed path remains traversal-checked and realpath-confined before writing

= 2.4.2 =
* Fix: timeouts on large (multi-GB, media-heavy) sites — the file scan is now a resumable, time-bounded directory walk instead of a single-request recursive scan, and each zip tick is capped at 48MB of file payload so ZipArchive::close() can no longer write gigabytes in one request
* UX: the progress bar now shows a distinct "scanning files… N found" stage before zipping begins
* Compliance: final Plugin Check stragglers annotated (ABSPATH write in extraction, schema import, session-continuity inserts, cutover update); Tested up to 7.0
* Symlinked directories inside wp-content are no longer followed during the scan (loop protection)

= 2.4.1 =
* Compliance: full Plugin Check pass — table/column identifiers now use the %i placeholder with $wpdb->prepare() throughout (export, import, finalize swap, cutover, cleanup, uninstall); remaining direct operations carry precise, line-accurate phpcs justifications
* Compliance: uninstall now removes the work directory via WP_Filesystem; wp_is_writable() replaces is_writable()
* Compliance: Requires at least bumped to WordPress 6.2 (required for the %i placeholder); Tested up to 6.9
* No functional changes — all behavior identical to 2.4.0

= 2.4.0 =
* New: DNS reality check on the domain cutover — the Run button verifies whether the target domain resolves to this server, shows both IPs on mismatch (with a Cloudflare/proxy caveat), and asks for confirmation instead of blocking
* New: step-by-step DNS sequence checklist in the cutover tab, including this server's IP address ready to paste into the A record, the SSL-certificate prerequisite, and propagation guidance
* Docs: FAQ entry on when to change DNS and why the plugin cannot do it

= 2.3.0 =
* Fix: domain cutover no longer flips siteurl/home mid-run (which broke admin-ajax with 400s and could strand a half-replaced database) — the address now changes atomically after the last table, so the site keeps working throughout
* New: "Keep my current admin account" on finalize (default on) — the operator's user and session are carried into the migrated database, so the swap no longer logs you out (unless the same username exists on the old site)
* New: proper completion screens after finalize and cutover — plain-language explanation of what changed, why this page may stop responding, and a one-click button to the correct admin (stay, log in again, or continue on the new URL)

= 2.2.0 =
* New: side-by-side comparison table after connecting — WordPress, PHP, and database versions, table prefix, content size vs free space, active theme — with mismatches highlighted as warnings (informational, never blocking)
* New: "Advanced: choose what to migrate" panel with theme and plugin checkboxes; everything selected by default, active theme and its parent locked; unticked items are excluded from the transfer
* New: re-running a migration now resets the source-side job automatically, fixing stale-manifest reuse after a destination reset

= 2.1.0 =
* Rearchitected post-migration cleanup to be universal and builder-agnostic: (1) purge always-safe DB caches, (2) delete known regenerable cache directories when present (Elementor, Divi, Beaver Builder, Oxygen, Bricks, Breakdance, Avada, Autoptimize, SG Optimizer, wp-content/cache page caches), (3) rewrite absolute URLs inside all static CSS across uploads — covering locally-hosted fonts and hardcoded-URL assets from ANY plugin
* All cleanup steps are best-effort, time-bounded (cannot stall finalize), and no-ops when the relevant plugin is absent

= 2.0.4 =
* Fix: CORS font errors after migration — absolute URLs inside static CSS files under uploads/elementor (locally-hosted Google Fonts, custom fonts, custom icons) are now rewritten on disk during finalize and domain cutover, since these are unreachable by database search-replace

= 2.0.3 =
* Fix: mixed-case source table prefixes were silently lowercased, breaking the capabilities/user_roles rewrite and locking admins out after finalize
* New: automatic post-swap cleanup on finalize AND after domain cutover — clears all transients, forces permalink regeneration, and purges Elementor generated CSS (files + postmeta) so page-builder sites render correctly on the new URL immediately

= 2.0.2 =
* Fix: fatal error during import when serialized data contains objects of classes not present on the destination (e.g. ActionScheduler_SimpleSchedule from WooCommerce) — incomplete-class objects now pass through untouched and re-serialize losslessly
* Fix: immutable objects (PHP enums, readonly properties) in serialized data no longer cause fatals during URL rewriting

= 2.0.1 =
* Fix: memory exhaustion (HTTP 500) during database import on sites with very large rows — memory limit raised, export batches reduced, INSERTs now flushed in bounded 100-row chunks
* Fix: the migration loop now stops with a clear message after 5 consecutive server errors instead of retrying forever
* Progress remains resumable across all fixes — press Resume to continue a stuck migration

= 2.0.0 =
* Security: expiring, single-use connection keys, verified by a constant-time secret comparison on the paired site
* Security: brute-force lockout on transfer endpoints (10 attempts / 15 min)
* Security: randomized, access-protected work directory (htaccess + random path)
* Security: strict path validation (wp-content-only, traversal/realpath checks)
* Security: strict SQL identifier validation before any query interpolation
* Compliance: full escaping, sanitization, and internationalization
* Compliance: assets properly enqueued; no inline scripts or styles
* Compliance: uninstall.php with clean removal (rollback tables preserved)
* UX: plain-HTTP transport warning during pre-flight

= 1.1.0 =
* Pre-flight checks, per-site exclusions, one-time keys, domain cutover tool

= 1.0.0 =
* Initial version

