Skip to main content

MHM Rentiva v4.27.1: i18n Locale-Leak Hotfix — Vehicle Settings Labels No Longer Frozen at First-Install Language

· 4 min read
MaxHandMade
Maintainer

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:

  1. Plugin is installed on a Turkish WordPress site; the Vehicle Settings page is visited once.
  2. The site is switched to English (or a Turkish DB backup is restored onto an English site).
  3. 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.php4 new regression tests, 13 assertions:

  1. Leaked label arrays are cleaned (Turkish, English, and mixed content)
  2. Migration is idempotent — second call is a no-op, does not overwrite a legitimate post-migration rename
  3. Fresh install — no legacy option present; flag is still set (skips future calls)
  4. mhm_custom_* — user custom fields are not touched

✅ Verification

CheckResult
PHPCS release scope0 error, 0 warning
PHPUnit732/732 (+4 new), 6 skipped, 0 regressions
Plugin Check (PCP)0 error, 3 trivial warnings (.distignore-excluded)

📦 Installation

mhm-rentiva.4.27.1.zipPlugins → 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