fix: make admin settings downgrade-safe with legacy write-through mirror - #3308
Conversation
Saving via the new flat dokan_admin_settings option previously left the legacy dokan_* rows stale (and legacy-path saves stripped mapped keys from them), so downgrading to a plugin version without the settings bridge lost the user's edits — and edits made on that old version were silently shadowed by the stale flat option after re-upgrading. - Add LegacyMirror (Hookable): mirrors every dokan_admin_settings_changed slice into the legacy rows, and reconciles on admin_init by comparing the raw rows against a baseline snapshot (dokan_admin_settings_legacy_snapshot), adopting values an older plugin version changed — last write wins. - Gate mapped-key stripping behind LegacySettingsBridge::is_legacy_mirror_enabled(); single-line opt-out: add_filter( 'dokan_admin_settings_legacy_mirror', '__return_false' ). - Add BridgeBootstrap::without_overlay() so physical row reads/writes bypass the overlay projection (update_option would otherwise silently no-op).
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
UAT — Downgrade-safe admin settings (Legacy Mirror)Environment prep: a site running this branch (with WooCommerce), WP-CLI access. "Old version" below means any released Dokan build without the settings bridge (e.g. the current production release zip).
Scenario 1 — New-UI save is visible to old plugin versions (write-through)
✅ Expected: the raw Scenario 2 — Downgrade: old version reads current data
✅ Expected: Vendor Store URL shows Scenario 3 — Edit and save on the old version
Scenario 4 — Re-upgrade: old-version edit wins (reconciliation)
✅ Expected:
Scenario 5 — Regressions (normal operation, no downgrade involved)
Scenario 6 — Strict-mode opt-out (single-line switch)
✅ Expected: raw legacy row is NOT updated (pre-PR strict single-source behavior restored); the new UI and Pass criteria: Scenarios 1–4 demonstrate no data loss in either direction of the downgrade/upgrade round trip; Scenario 5 shows no behavior change during normal operation; Scenario 6 confirms the one-line rollback switch. |
… expectation test_round_trip_preserves_legacy_shape asserted the input key order (fixed, percentage) with assertSame, but to_legacy()'s output order is contractually (percentage, fixed) — locked by its sibling test — so the test could never pass. It shipped in #3202 without a @group tag, so group-filtered runs never executed it. Align the expectation with the locked output contract.
…ings-downgrade-safe-legacy-mirror
All Submissions:
Changes proposed in this Pull Request:
The flat-array settings refactor made
dokan_admin_settingsthe single physical source of truth: new-UI saves never reached the legacydokan_*rows, legacy-path saves actively stripped mapped keys out of those rows, and nothing detected edits made while the bridge was absent. That breaks the downgrade → edit → re-upgrade round trip both ways:dokan_admin_settingssnapshot unconditionally shadows the fresher legacy rows → the user's downgrade-period edits silently vanish.This PR keeps the flat option canonical while making the legacy rows a physical, downgrade-safe mirror:
LegacyMirror(new Hookable,includes/Admin/Settings/Migration/LegacyMirror.php)dokan_admin_settings_changedand fans changed values out to the legacy rows viaLegacySettingsBridge::write_new_to_legacy(), stamping a baseline snapshot (dokan_admin_settings_legacy_snapshot).admin_init, compares the raw rows against the baseline; keys changed while the bridge was not watching (i.e. by an older plugin version) are adopted back intodokan_admin_settings— last write wins. Keys absent from the baseline are never adopted, protecting newly-mapped schema fields. First run materializes the full mirror, healing historically-stripped rows.BridgeBootstrap::without_overlay()(new): mirror/reconcile row I/O runs with the overlay suppressed — otherwiseupdate_option()'s internal old-value read is projected from the flat option, a stale row looks current, and the physical write silently no-ops.How to test the changes in this Pull Request:
wp db query "SELECT option_value FROM wp_options WHERE option_name='dokan_general'"→ the mapped key now physically holds the saved value (previously stale/stripped).wp option patch update dokan_general custom_store_url old-version-edit(or downgrade to a pre-bridge Dokan build and save settings there).dokan_admin_settingsadopts the edited value; both the new UI anddokan_get_option()returnold-version-edit.vendor/bin/phpunit -c phpunit.xml --group admin-settings→ 174 tests pass, including the newLegacyMirrorTestround-trip coverage.Changelog entry
fix: Admin settings survive plugin downgrade/re-upgrade round trips
Previously, settings saved in the new admin settings UI were invisible to older plugin versions (legacy option rows were stale or stripped), and settings saved while running an older version were silently discarded on re-upgrade. Legacy rows are now kept as a write-through mirror of the canonical flat option, and edits made on an older version are reconciled back (last write wins) when returning to the new version.