Skip to main content

MHM Rentiva v4.27.4–v4.27.6: Migration Lane Architecture, License Slug Forwarding, WordPress.org Polish

· 4 min read
MaxHandMade
Maintainer

A retrospective covering three patch releases shipped in succession on 2026-04-23: a critical migration architecture fix (v4.27.4), per-product license binding compatibility (v4.27.5), and WordPress.org submission readiness (v4.27.6). Backfilling these blog posts now in the wake of the v4.30.x security sprint.

v4.27.4 — Migration Lane Architecture Fix (CRITICAL)

The v4.27.1 (i18n locale leak) and v4.27.2 (Settings Testing pollution) data-cleanup migrations never actually ran on upgraded sites — the regression cleared during v4.27.0 prep had quietly broken the migration trigger.

Root cause

plugins_loaded migration callback used a single short-circuit:

if ( $stored_version === MHM_RENTIVA_VERSION ) {
return; // skip ALL migrations
}

But mhm_rentiva_single_site_activation() (which fires BEFORE plugins_loaded on any ZIP-replace upgrade path) had already stamped the new version into the option. By the time plugins_loaded fired, $stored === $current was true → all flag-gated cleanups got skipped forever.

Live evidence at mhmrentiva.com: Brand Name displayed as 1, currency stats rendered as 0,00 1 instead of 0,00 ₺ (because the v4.27.2 pollution migration never executed).

Fix — two-lane architecture

plugins_loaded callback split into two independent lanes:

  • Lane A (schema drift, version-gated): runs only when $stored !== $current. Idempotent across multiple loads of the same version.
  • Lane B (flag-gated data cleanups): runs on every request, but each migration has its own mhm_rentiva_<flag> option that flips after successful run. Genuinely idempotent.

Both lanes have their own error containment so a failure in Lane B never blocks Lane A or vice versa.

Test coverage

tests/Migration/MigrationLaneIndependenceTest.php — 3 new tests, 8 assertions guarding the split.

Empirical verification

Chrome DevTools MCP browser tour of mhmrentiva.com after deployment: 0 duplicate notices, stats display 0,00 ₺ (U+20BA), Brand Name reads "MHM Rentiva". Manual one-time Reset to Defaults across 11 admin tabs cleared residual state from the period when migrations weren't running.

v4.27.5 — License Client Per-Product Slug Forwarding

Pairs with mhm-license-server v1.8.0+ which introduced per-product license binding. Before v4.27.5, a customer could buy a cheap MHM Currency Switcher Monthly key and use it to activate Rentiva Pro — server had no way to enforce that the license was issued for a specific product.

Change

LicenseManager::activate() and validate() request bodies now include product_slug => 'mhm-rentiva'. The server checks this against the license row's stored slug and rejects mismatches with a product_mismatch error.

Bonus fix

Additional Services admin page rendered two Documentation buttons — the global all_admin_notices docs hook + the page's own header both fired. The hook now skips the vehicle_addon screen; the page header's button is the single source.

v4.27.6 — WordPress.org Submission Polish

Plugin Check (PCP) compliance for WordPress.org plugin directory submission: 1 ERROR + 115 WARNING → 0 ERROR + 61 WARNING. The remaining warnings are all false positives caused by Plugin Check not reading the project's phpcs.xml prefix configuration.

Concrete fixes

  • unlink()wp_delete_file() in the demo image importer (the only real ERROR).
  • Reasoned phpcs:ignore comments for warnings the project's ruleset already excludes (audit error_log() calls, mhm_rentiva_ prefixed hooks Plugin Check refuses to recognise, accepted meta_query / post__not_in performance tradeoffs, ledger queries with core-controlled table names bound through $wpdb->prepare()).
  • $pending_messages template-scope variable → $mhm_rentiva_pending_messages to honour Plugin Check's prefix convention.
  • readme.txt Changelog section trimmed to fit WP.org's 5000-character limit; older releases linked to GitHub.
  • changelog-tr.json backfill for v4.27.5 + new v4.27.6 entry.

No functional change

740/740 PHPUnit still passes. PHPCS clean. The plugin behaves identically — only the Plugin Check noise was reduced.

✅ Verification across all three

Checkv4.27.4v4.27.5v4.27.6
PHPUnit740/740, 2642 assertions, 6 skippedunchangedunchanged
PHPCS0 / 00 / 00 / 0
Plugin Check ERRORunchangedunchanged1 → 0

🎓 Lessons captured (memory)

  • feedback_migration_lane_architecture.md — when activation hooks stamp version BEFORE plugins_loaded, the version gate breaks all flag-gated migrations. Always split version-drift and data-cleanup lanes.
  • feedback_empirical_dom_verification.md — DOM-level verification through Chrome DevTools MCP is the only way to catch runtime-DB-state bugs that 100% PHPUnit + 0 PHPCS happily ship.

🔜 Next

The v4.27.x umbrella closed here. Next major was v4.28.0 (Popular Routes) — but the security audit of the cross-product attack surface re-prioritised the roadmap into the License Security Hardening sprint (v4.30.x), shipped 2026-04-24/25.


GitHub Releases: v4.27.4 · v4.27.5 · v4.27.6