Skip to main content

Rentiva v4.38.1 — Audit-driven patch

· 3 min read
MaxHandMade
Maintainer

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_disable filter is true. Parity with VendorProfileSeo's register guard. Plus a DocBlock spelling out the 3-arg filter signature for build_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 where meta_key arrives as an array — VendorProfileCacheInvalidator already had this guard), and a no-op early-return when $new_status === $old_status on the lifecycle hook (parity with the existing on_comment_status no-op in the same class). Avoids spurious cache flushes that defeat the 30-min directory cache.
  • Pagination/sort combination tests + .current scope — three new tests covering pagination overflow, alpha sort with city filter, and paged query string on page 2. Verifies the .current pagination class stays scoped under .mhm-vendor-directory-pagination so theme .current rules 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.