Releases: frisoftltd/dish-dash
Release list
Fix Minimal Light nav hover, wire real hero background image, improve H1 typography
Diagnoses and fixes the desktop nav hover color issue (cache vs. code root cause confirmed live). Wires the existing dd_hero_bg_image/overlay_color/overlay_opacity fields as an actual hero section background (previously unused/misapplied), with a light Minimal-Light-appropriate overlay treatment distinct from Khana Khazana's dark styling. Improves hero H1 typography (scale, line-height, weight, accent-span treatment).
Nav hover: confirmed live (not just from static code) — fetched demo.dishdash.rw with cache-busting, verified the deployed CSS matches source exactly, and found the actual cause: the tenant's dish_dash_accent_color option is stored as #ffffff. No code change — see RELEASE.md v3.18.45 and CLAUDE.md's Next task for the wp-admin follow-up.
See RELEASE.md v3.18.45 for full detail, and investigation-ml-nav-hover-bg.md for the pre-work investigation.
Redesign Minimal Light header and hero — nav bar, warm accent, dashed-circle hero
Adds a horizontal nav (Home/Menu/Reservation), site search, and a Log in button (replacing drawer-based login access) to Minimal Light's header. Repoints --ml-accent to the existing dish_dash_accent_color option (warm orange, zero ripple into Khana Khazana). Rebuilds the hero with a dashed-circle photo frame, floating card, hours line, and dual CTA buttons (replacing the previous text-link CTA style) — all still driven by existing Homepage Settings fields.
See RELEASE.md v3.18.44 for full detail, and investigation-ml-header-hero-redesign.md for the pre-work investigation.
Status-aware WhatsApp prefill message
The WhatsApp click-to-chat button renders for both pending and confirmed reservations, but the prefilled message was written for pending only. Tapping it on a confirmed booking sent the customer a vague enquiry; worse, a fixed "confirmed" wording would have told customers with a still-pending booking that their table was secured.
The message now branches on the same $is_confirmed check that already drives the status pill and the admin CTA, so the three can never disagree. Confirmed bookings get an explicit confirmation; pending wording is unchanged.
Escaping and digit validation untouched.
Reservation auto-confirm setting + WhatsApp click-to-chat
New setting dd_reservation_require_confirmation (default 1, preserving current behaviour). When off, no-deposit reservations are confirmed on submission instead of arriving as pending.
Admin reservation email now renders a status-driven pill (PENDING / CONFIRMED) and drops the admin CTA entirely when the booking is already confirmed — nothing to action. A WhatsApp click-to-chat button is added in both cases, opening a conversation with the customer with the booking reference prefilled.
Numbers are stored E.164 across multiple countries; the button renders only for a leading '+' and 8-15 digits, and fails safe otherwise. href escaped with esc_attr() per the esc_url %0A stripping rule.
Deposit-required bookings are unaffected and still insert as pending.
Known gap, documented not fixed: auto-confirm leaves no activity-log entry, as DD_Activity_Module::log() requires a staff user and the customer endpoint is nopriv. A system-actor concept is needed and is out of scope here.
Cache-safe opening hours — compute state client-side
Fixes restaurant showing "We're Closed" during open hours on cached pages.
Root cause: DD_Hours::get_state() was computed server-side and baked into page HTML. QUIC.cloud served a snapshot cached while the restaurant was closed, so every visitor saw closed buttons all day regardless of the real state.
Fix: window.DD now carries the static schedule (hours_schedule, hours_tz, closing_soon_min) instead of a computed state. New assets/js/hours.js derives state, close_ts and next_open_ts in the browser on load and re-checks every 60s. Schedule only changes when settings change, so the payload is cache-safe.
Server-side enforcement in dd_cart_add is unchanged and remains the authoritative gate. JS failure modes fail open.
Add GTM (Google Tag Manager) infrastructure — sitewide, independent of GA4
Adds a new dd_gtm_container_id setting and sitewide GTM injection (head script + body noscript iframe), following the existing dd_ga4_measurement_id pattern for the admin field/save logic. Deliberately NOT gated by is_dishdash_page() — GTM is meant to hold future tags (Meta Pixel, Google Ads conversion) whose page scope isn't known at deploy time, unlike GA4 which stays scoped to the ordering funnel. GA4/gtag logic fully untouched. Enables configuring new tracking pixels via GTM's dashboard without future code deploys, and sets up the pattern for other DishDash clients to add their own GTM container later.
See RELEASE.md for full details.
v3.18.39 — Consolidate ddTrack() (GA4 Release F)
Removes 3 byte-identical local ddTrack() copies (cart.js, frontend.js, menu-page.js) in favor of one shared window.ddTrack() in tracking.js. Pure refactor — all 11 call sites verified unchanged in event name and parameters. Added explicit dd-tracking script dependency to all 3 consuming files' enqueues, since correct load order was previously incidental rather than guaranteed. Closes the GA4/tracking investigation's Release F. See RELEASE.md.
v3.18.38 — Fix: MoMo GA4 revenue value
showMomoConfirmation()'s purchase event was missing the value field, recording all MoMo orders as zero revenue in GA4 — not a data problem, a structural one: the function never had lexical access to the order total captured earlier in dd_place_order's closure. Now captured at MoMo-initiation time (currentOrderTotal) and threaded through. Trustworthy by construction: MTN's USSD approval flow only allows accept/reject at the exact quoted amount, so the initiation-time total is guaranteed to equal the confirmed-paid amount. See RELEASE.md.
v3.18.37 — Fix: gate slug mismatch
is_dishdash_page() now correctly matches cart-dd, checkout-dd, my-restaurant-account, and reserve-table via get_global_header_slugs(), fixing missing GA4/gtag and all frontend CSS/JS on these pages. Old broken checks (cart, checkout, my-account) kept for white-label compatibility with other installs. Confirmed live: no customer traffic currently reaches /cart-dd/ or /checkout-dd/ directly, so this is a correctness fix rather than a live revenue leak. The separate, pre-existing broken form on /reserve-table/ (zero JS wired to its fields) remains unfixed — tracked for a future release. See RELEASE.md.
v3.18.36 — MoMo polling duplicate-order fix
ajax_momo_check_status() was calling place_order() with no idempotency key, meaning v3.18.35's dedupe protection was completely inert for mtn_momo orders. cart.js was already sending the key unconditionally on every checkout — this release just threads it through the MoMo pending-transient and back out on poll confirmation, so the existing lookup/insert/race-detection logic (proven in v3.18.35) now covers this path too. Also moves the transient deletion earlier, narrowing the race window as a second layer of defense. Residual double-notification edge case on true simultaneous polls is the same known, deferred gap as v3.18.35's offline/COD case. See RELEASE.md.