MHM Rentiva v4.27.4–v4.27.6: Migration Lane Architecture, License Slug Forwarding, WordPress.org Polish
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:ignorecomments for warnings the project's ruleset already excludes (auditerror_log()calls,mhm_rentiva_prefixed hooks Plugin Check refuses to recognise, acceptedmeta_query/post__not_inperformance tradeoffs, ledger queries with core-controlled table names bound through$wpdb->prepare()). $pending_messagestemplate-scope variable →$mhm_rentiva_pending_messagesto honour Plugin Check's prefix convention.readme.txtChangelog section trimmed to fit WP.org's 5000-character limit; older releases linked to GitHub.changelog-tr.jsonbackfill 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
| Check | v4.27.4 | v4.27.5 | v4.27.6 |
|---|---|---|---|
| PHPUnit | 740/740, 2642 assertions, 6 skipped | unchanged | unchanged |
| PHPCS | 0 / 0 | 0 / 0 | 0 / 0 |
| Plugin Check ERROR | unchanged | unchanged | 1 → 0 |
🎓 Lessons captured (memory)
feedback_migration_lane_architecture.md— when activation hooks stamp version BEFOREplugins_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.
