Skip to main content

MHM Rentiva v4.26.5: Vendor Dashboard Identity Card and Messaging Parity Fixes

· 5 min read
MaxHandMade
Maintainer

v4.26.5 delivers the results of an extended UX polish session on the vendor dashboard: a premium identity card (Gravatar + last login) at the bottom of the left menu, a fix for vendor bookings not appearing in the messaging form, a premium redesign of message list cards, and a set of silent bug fixes alongside.

👤 Vendor Dashboard Identity Card

The vendor dashboard's left menu previously showed only the username and a "Log Out" link. Now it includes:

  • Gravatar photo (40 px, rounded, white border, soft shadow)
  • User display name (overflow controlled with ellipsis)
  • Last successful login date and time (e.g. Last login: 15/04/2026 04:57)
  • Log Out button moved outside the card as a standalone action; turns red on hover.
<?php
$last_login_raw = (string) get_user_meta($user->ID, 'last_login', true);
if ($last_login_raw !== '') {
$ts = strtotime($last_login_raw);
if ($ts) {
echo date_i18n(get_option('date_format') . ' H:i', $ts);
}
}
?>

last_login user meta — a key read but never written

An interesting discovery: the last_login user meta was already being read in our GDPR/Privacy and DataRetentionManager code — but was never written anywhere. This meant "this user hasn't logged in for N days" decisions in data retention calculations were always based on an empty value.

v4.26.5 closes this gap: SessionManager::set_session_timeout() now accepts the second parameter of the wp_login action (WP_User $user) and updates last_login with current_time('mysql').

add_action('wp_login', array(self::class, 'set_session_timeout'), 10, 2);

public static function set_session_timeout($user_login = '', $user = null): void
{
$user_id = ($user instanceof \WP_User) ? (int) $user->ID : get_current_user_id();
if (! $user_id) return;
update_user_meta($user_id, 'mhm_rentiva_last_activity', time());
update_user_meta($user_id, 'last_login', current_time('mysql'));
}

📥 Messaging: Vendors Now See Their Own Bookings

The Related Booking dropdown in the "New Message" form always came up empty — from the vendor's perspective. The REST endpoint only queried the _mhm_customer_user_id meta, i.e. "bookings I made as a customer". Bookings made by others on the vendor's own vehicles were not visible.

The fix: the endpoint runs two queries, merges the results by ID, deduplicates them, and sorts by post_date DESC:

// Customer-side: the user who made the booking
$customer_query = new WP_Query([
'post_type' => 'vehicle_booking',
'meta_query' => [[
'key' => '_mhm_customer_user_id',
'value' => $user_id,
]],
]);

// Vendor-side: bookings on vehicles owned by this vendor
$vendor_vehicle_ids = get_posts([
'post_type' => 'vehicle',
'author' => $user_id,
'posts_per_page' => -1,
'fields' => 'ids',
]);
if (!empty($vendor_vehicle_ids)) {
$vendor_query = new WP_Query([
'post_type' => 'vehicle_booking',
'meta_query' => [[
'key' => '_mhm_vehicle_id',
'value' => $vendor_vehicle_ids,
'compare' => 'IN',
]],
]);
}

🎨 Premium Message List Cards

Message list cards have moved from plain white boxes to a premium design:

  • Gradient background (#ffffff → #fafbff)
  • Purple pill ID badge (#4F46E5 background, #eef2ff fill)
  • Orange gradient "NEW" label (#f59e0b → #f97316, box-shadow amber glow)
  • On hover, an indigo accent bar appears on the card's left edge and the card lifts 2 px
  • Unread state uses an amber background + left accent bar
  • Mobile breakpoint: padding and typography adapt automatically

🗂️ .hidden — A Rule We Didn't Know Was Missing

The messages page template has three views:

  1. Message list
  2. Conversation (thread) view
  3. New message form

The template tried to hide all three with class="hidden" initially — but the .hidden CSS rule was defined nowhere. As a result, all three rendered as display: block simultaneously. When the user scrolled down, they saw a confusing stack of overlapping panels.

The fix is a CSS utility:

.mhm-messages-section .hidden,
.mhm-messages-section .thread-reply.hidden,
.mhm-messages-section .new-message-form.hidden,
.mhm-messages-section .message-thread.hidden {
display: none !important;
}

Now the three views are mutually exclusive: whichever is active is shown; the others are hidden.

🔁 No More Button Accumulation When Reopening a Thread

When a thread was closed and reopened, the "Close Message" button and "This conversation is closed" notice banner were appended to the DOM again without removing the stale elements first. The result: opening the same thread twice showed two "Close Message" buttons.

// Remove stale elements before re-rendering
$('#message-thread .close-thread-btn').remove();
$('#message-thread .thread-closed-notice').remove();

🔣 Mojibake Box and Translation Fixes

  • The back-arrow () before the "Back to Messages" text in templates/account/messages.php was double-encoded UTF-8 (rendered as â†) and a stray C1 control byte (0xC2 0x90) remained in the template. Fix: <span aria-hidden="true">&larr;</span> HTML entity + PowerShell script to strip the C1 byte.
  • In the Turkish .po file, the "Booking Association" label was translated as "Rezervasyon Derneği" (Booking Society) 😄 — corrected to "İlgili Rezervasyon".

📦 Filemtime Cache Busting

During this session we hit the "browser cache keeps serving old CSS/JS" loop twice. To prevent this going forward, asset enqueues now use filemtime versioning:

$customer_messages_css_ver = file_exists($path)
? MHM_RENTIVA_VERSION . '.' . filemtime($path)
: MHM_RENTIVA_VERSION;
wp_enqueue_style('mhm-customer-messages', $url, [], $customer_messages_css_ver);

Even when the plugin version stays the same, every file change produces a unique query string like ?ver=4.26.5.1744742822 — the browser never serves the old file.

✅ Tests

720 tests, 2601 assertions, 6 skipped — fully green. No regressions.

Download

The next minor version (v4.27.0) is dedicated to the vendor report and dispute system — a unified infrastructure for booking, penalty, and vehicle reports.