Skip to main content

MHM Rentiva v4.27.2: Settings Testing Pollution Hotfix + Duplicate Addon Notice Dedupe

· 5 min read
MaxHandMade
Maintainer

After the v4.27.1 i18n hotfix, a user reported three more bugs — all originating from the same fresh-install scenario, all triggered by pressing "Run All Diagnostics" once on the Settings Testing page. v4.27.2 breaks the chain.

🐛 Bug 1: All Text Fields Show "1" on Fresh Install

Scenario:

  1. Plugin is freshly installed.
  2. User goes to Settings → Settings Testing tab and presses "Run All Diagnostics".
  3. Returns to General Settings — Brand Name = "1", Cancellation Deadline = 1, Payment Deadline = 1, Support Email, Brand Logo URL, etc. all show "1".
  4. Pressing "Reset to Defaults" fixes it.

Root Cause

SettingsTester::test_settings_save() was converting empty strings to '1' to trigger a "change detected save":

// Fresh install: $current_str == ''
if ( in_array( $current_str, array( '0', '1', '' ) ) ) {
$test_value = ( $current_str === '1' ) ? '0' : '1'; // → '1'
}

This '1' payload was then passed to the real sanitizer. The sanitizer rewrote ALL fields for the target tab (not just the key under test). The restore mechanism only reverted the explicitly tested keys → collateral writes to other tab fields persisted in the DB.

The critical point: On a fresh install, when the General test runs:

  • brand_name → '1' (test flip, then restored) ✓
  • currency → '1' (flip + restore) ✓
  • dark_mode → sanitizer wrote it, test never touched it → stayed in DB
  • support_email → sanitizer wrote admin@... as default, then flipped to '1', not restored → stayed in DB
  • ... and more

Fix

1. Harness fix — full snapshot/restore

// NEW v4.27.2: snapshot the ENTIRE option, restore the ENTIRE option.
$option_existed_before = false !== get_option( $option_name, false );
$full_option_snapshot = (array) get_option( $option_name, array() );

// ... test runs, sanitizer pollutes DB ...

if ( $option_existed_before ) {
update_option( $option_name, $full_option_snapshot );
} else {
delete_option( $option_name );
}

The test now leaves the DB truly read-only. Collateral writes are automatically undone.

2. Migration — clean up existing installs

SettingsCore::migrate_clean_test_pollution() — one-time flagged migration (mhm_rentiva_v4272_test_pollution_cleaned):

$polluted_keys = array(
'mhm_rentiva_brand_name', 'mhm_rentiva_email_from_name',
'mhm_rentiva_email_from_address', 'mhm_rentiva_support_email',
'mhm_rentiva_booking_url', 'mhm_rentiva_login_url',
'mhm_rentiva_currency', /* ... */
);

foreach ($polluted_keys as $key) {
$value = $settings[$key] ?? null;
if ('0' === $value || '1' === $value) {
unset($settings[$key]); // fallback to default
}
}

Only cleans text, email, URL, currency fields that carry the pollution signature ('0' / '1'). Numeric fields (deadlines) are not touched — the user may genuinely have entered 1 (rare). Legitimate string values are preserved.

🐛 Bug 2: Duplicate Limit Notice on Add-ons Page

The Lite limit warning was appearing twice on the Additional Services admin page — once above and once below the stats cards.

Root Cause

AddonMenu::add_addon_page_title() emitted the notice inside a nested <div class="wrap"> block. The WordPress core admin-notice relocator JS then:

  • Placed the standard copy after the wp-header-end marker
  • Left the original copy inside the inner wrap
  • → Two copies

Fix

The notice is now emitted in a separate admin_notices callback — AddonMenu::render_addon_limit_notice() — at priority 20. It fires AFTER the inner wrap is closed, and WordPress places it exactly once.

🐛 Bug 3: Settings Testing "Defaults Set" Phantom Key FAILs

The Settings Testing page reported "Defaults Set: FAIL" for setting keys that do not exist anywhere:

  • mhm_rentiva_timezone (not in General)
  • mhm_rentiva_db_auto_optimize (not in Core)
  • mhm_rentiva_wp_optimization_enabled (not in Core)
  • mhm_rentiva_my_account_url (not in Frontend)

Fix

Removed these phantom keys from the check list. Additionally, the "Email Address Valid" and "Email Validation Works" FAILs were a side-effect of Bug 1 ('1'is_email('1') = false) — they clear automatically once the pollution migration runs.

🧪 Tests

tests/Migration/SettingsTestPollutionMigrationTest.php5 new tests, 19 assertions:

  1. Text/email/URL/currency pollution is cleaned
  2. Legitimate user values are preserved
  3. Numeric fields (deadlines) are not touched
  4. Post-migration legitimate "1" rename is not overwritten (idempotent)
  5. Flag is set on fresh install

✅ Verification

CheckResult
PHPCS release0 error / 0 warning
PHPUnit737/737 (+5 new, 732→737), 6 skipped, 0 regressions
Plugin Check (PCP)0 error, 3 trivial warnings (unchanged)

⚠️ Upgrade Note

Users who pressed "Run All Diagnostics" and saw Brand Name = 1: the migration runs automatically on the next admin page load. You do NOT need to press "Reset to Defaults". Text/email/URL/currency fields will revert to their defaults.

Numeric deadlines (Cancellation / Payment) are not touched — the migration cannot distinguish these from a deliberate user choice. Manually set the deadlines in the Booking tab to 24 hours / 30 minutes (or your preferred values).

📦 Installation

mhm-rentiva.4.27.2.zipPlugins → Add New → Upload Plugin, or use the Rentiva Pro auto-updater.

Requirements: PHP 8.1+, WordPress 6.7+.

🎓 Lesson

All three of these bugs — like the v4.27.1 i18n hotfix — are in the runtime DB-state class. Neither PHPCS, PCP, nor the unit test suite can catch them. They only surface when testing a fresh-install scenario through the real admin UI. The feedback_runtime_smoke_test.md memory note now reads "fresh-install UI smoke test mandatory before every major release" — the next major release will integrate this pattern into the checklist.

In context: we shipped 3 releases in one day — v4.27.0 (WPCS submission prep) → v4.27.1 (i18n locale leak) → v4.27.2 (Settings Testing pollution + duplicate Addon notice). Each with zero regressions and new regression tests. The agile patch pipeline works.

🔜 Next

  • v4.28.0: Popular Routes shortcode/block/widget (new feature)
  • v4.29.0: Vendor Report / Appeal System (new subsystem)
  • The v4.27.x roadmap is closed — the next umbrella is v4.28.0

GitHub Release: v4.27.2