MHM Rentiva v4.27.1: i18n Locale-Leak Hotfix — Vehicle Settings Labels No Longer Frozen at First-Install Language
A few hours after the v4.27.0 WordPress.org submission readiness release, a critical bug was caught: On an English WordPress site, the Vehicle Settings page was displaying Turkish labels. This is a global plugin; English is the primary language. The bug was submission-blocker severity. v4.27.1 fixes it.
🐛 Bug Scenario
Typical reproduction steps:
- Plugin is installed on a Turkish WordPress site; the Vehicle Settings page is visited once.
- The site is switched to English (or a Turkish DB backup is restored onto an English site).
- The admin panel still shows Turkish labels: Günlük Fiyat, Model Yılı, Plaka, Klima, Yedek Lastik...
Yet every __( 'Daily Price', 'mhm-rentiva' ) call in the source code correctly returns the English value for the current WordPress locale. So why was the admin UI still showing Turkish?
🔍 Root Cause
VehicleMeta::ensure_default_options() performed the following on the first admin page load:
$default_details = self::get_default_details(); // Array with TRANSLATED __() calls
// ...
if (get_option('mhm_vehicle_details', array()) === array()) {
update_option('mhm_vehicle_details', $default_details); // 🔥 Wrote Turkish values to DB
}
Inside get_default_details():
return array(
'price_per_day' => __('Daily Price', 'mhm-rentiva'), // Turkish site → "Günlük Fiyat"
'year' => __('Model Year', 'mhm-rentiva'), // Turkish site → "Model Yılı"
// ...
);
__() returns the translation for the locale active at the moment of the call. With a Turkish site, this returned "Günlük Fiyat" and wrote it to wp_options.
Later, in the get_all_available_details() render flow:
$details = self::get_default_details(); // live __() → English (site is EN now)
$stored = get_option('mhm_vehicle_details'); // FROZEN Turkish
foreach ($stored as $key => $label) {
$details[$key] = $label; // Override: Turkish wins
}
The frozen translation always overwrote the live translation.
🛠️ Fix
1. Stop auto-persisting
The three update_option('mhm_vehicle_*', $translated_defaults) calls inside VehicleMeta::ensure_default_options() were removed entirely. It continues to seed mhm_selected_* (key lists only — no translated strings).
2. Clean up existing installs
New method VehicleMeta::migrate_remove_auto_populated_labels() — a one-time migration guarded by the mhm_rentiva_v4271_labels_migrated flag:
foreach (['mhm_vehicle_details', 'mhm_vehicle_features', 'mhm_vehicle_equipment'] as $key) {
$stored = get_option($key, null);
if (is_array($stored) && !empty($stored)) {
delete_option($key);
}
}
Migration is triggered inside the existing version-drift block on the plugins_loaded hook — runs across admin, cron, and WP-CLI flows.
3. User custom fields are preserved
mhm_custom_details, mhm_custom_features, mhm_custom_equipment — fields added by the user via "Add Custom" live in separate options. The migration does not touch them.
⚖️ Trade-off
If you renamed a core field via "Edit Names" (e.g. "Daily Price" → "Rental Rate"), you will need to re-apply that rename once after upgrading. This is a rare scenario — but the bug affected every install. The trade-off is fair.
🧪 Tests
tests/Migration/LocaleLeakLabelsMigrationTest.php — 4 new regression tests, 13 assertions:
- Leaked label arrays are cleaned (Turkish, English, and mixed content)
- Migration is idempotent — second call is a no-op, does not overwrite a legitimate post-migration rename
- Fresh install — no legacy option present; flag is still set (skips future calls)
mhm_custom_*— user custom fields are not touched
✅ Verification
| Check | Result |
|---|---|
| PHPCS release scope | 0 error, 0 warning |
| PHPUnit | 732/732 (+4 new), 6 skipped, 0 regressions |
| Plugin Check (PCP) | 0 error, 3 trivial warnings (.distignore-excluded) |
📦 Installation
mhm-rentiva.4.27.1.zip → Plugins → Add New → Upload Plugin, or use the Rentiva Pro auto-updater.
Requirements: PHP 8.1+, WordPress 6.7+.
🔜 Next
- v4.27.2: Search Results UX improvements + Shortcode Review Backlog (combined patch)
- v4.28.0: Popular Routes shortcode/block/widget (new feature)
- v4.29.0: Vendor Report / Appeal System (new subsystem)
🎓 Lesson
This bug was caught a few hours after the v4.27.0 WordPress.org submission readiness release. The zero PHPCS / zero PCP validation suite had passed, but neither PHPCS nor PCP can see a runtime bug (existing DB state overwriting __() output). Real admin UI testing is the only safeguard. We needed a smoke test run before WordPress.org submission — v4.27.1 establishes this pattern: manual verification is mandatory for any UI that routes through the translation layer.
GitHub Release: v4.27.1
