Rentiva v4.38.1 — Audit-driven patch
A small but important patch on top of v4.38.0. After the Vendor Directory release we ran a /wp-conductor post-merge audit on the v4.37.0 → v4.38.0 chain — two real findings and a dormant production defect surfaced from the new test coverage. v4.38.1 closes them all so the six-release deploy bundle is clean.
What changed
🔴 YÜKSEK — Admin slug edit collision
When you edited a vendor's profile slug from the WordPress admin, the save path was writing the slug directly via update_user_meta() instead of going through VendorSlugManager::change_slug(). A leftover // later TODO from v4.37.0 Phase 1.3.
The practical impact: two admins (or admin + a vendor self-editing) submitting the same raw slug to different vendors would both succeed. VendorProfileProvider::lookup_by_slug() returns the first match, so the second vendor's public profile URL silently rendered the wrong vendor — for paying Pro customers, on a marketplace, indefinitely.
The save path now routes through change_slug(), which already handles sanitize + collision suffix (-2, -3...) + history sanitize atomically.
🟡 ORTA — Directory vehicle_count vs Profile inconsistency
VendorDirectoryProvider::count_active_vehicles_for() counted every publish vehicle, regardless of _mhm_vehicle_lifecycle_status. Profile-side collect_vehicles() filters by lifecycle='active'. So a vendor with 2 active + 3 paused vehicles showed "5 vehicles" on the directory card and "2 vehicles" on the profile page. Marketplace data inconsistency = trust degradation.
Fixed by adding the same meta_query lifecycle filter to the count query.
🐛 Dormant production defect — pagination strict-type TypeError
The new combination tests in this patch surfaced something the existing v4.38.0 tests had never exercised: the directory pagination partial passed $big = 999999999 (int) as the first argument to str_replace(). PHP 8.1+ strict types throw TypeError.
Existing tests never seeded enough vendors to push past per_page=12, so the bug stayed dormant. Production sites running PHP 8.x would have crashed the directory page the moment a 13th active vendor pushed the result set past one page. Cast to string explicitly — same pattern WP core uses in identical callers.
This is the strongest argument for not having shipped v4.38.0 alone.
📌 Phase 5/6/7 paper-cuts
Three small parity fixes that the v4.38.0 audit had pre-documented as deferred:
- VendorDirectorySeo register guard — early return when an SEO plugin (Yoast / Rank Math / AIOSEO / SEOPress / The SEO Framework / SmartCrawl) owns the contract or the
mhm_rentiva_vendor_directory_seo_disablefilter is true. Parity withVendorProfileSeo's register guard. Plus a DocBlock spelling out the 3-arg filter signature forbuild_meta_description($default, $vendor_count, $vehicle_count). - VendorDirectoryCacheInvalidator — two parity guards:
!is_string($meta_key)short-circuit on the user_meta hooks (rare WP edge case wheremeta_keyarrives as an array —VendorProfileCacheInvalidatoralready had this guard), and a no-op early-return when$new_status === $old_statuson the lifecycle hook (parity with the existingon_comment_statusno-op in the same class). Avoids spurious cache flushes that defeat the 30-min directory cache. - Pagination/sort combination tests +
.currentscope — three new tests covering pagination overflow, alpha sort with city filter, and paged query string on page 2. Verifies the.currentpagination class stays scoped under.mhm-vendor-directory-paginationso theme.currentrules can't hijack the styling.
Pipeline gates
- PHPUnit: 1044 → 1058 tests, 3289 → 3320 assertions, 7 skipped, 0 fail
- PHPCS: 0 errors (full project, CI parity gate)
- Independent code review:
merge ready, no KRİTİK/YÜKSEK findings
Deploy notice
Ship v4.38.1 together with the v4.37.0 + v4.37.1 + v4.37.2 + v4.37.3 + v4.38.0 chain — six releases in a single mhmrentiva.com deploy. No separate upgrade path needed.
