[object Object]

← back to Ventura Claw Leads

Add per-vertical sample rails to home page (food/beauty/retail/creative)

05ae6c75d1f12618789dff5aa2aa6f1cbc9ebc7e · 2026-05-07 11:22:52 -0700 · Steve Abrams

Home was showing only category-chip counts plus the existing 'Featured'
rail (claim+tier-gated, only 9 cards). With 1,819 corridor-seeded
listings, the home page should preview the directory's depth, not just
gate-keep behind a search box.

Top 4 verticals by count get a 6-card preview rail with 'See all N →'
link. Cards prioritize photographed/claimed/premier rows then random,
so the rail rotates per request and rewards owners who fill out their
page. Today's home: 28 unique business links vs. 9 before — a 3x lift
in click targets without changing any other section.

JSON-LD LocalBusiness + BreadcrumbList already exists on
/business/<slug>; no structured-data work needed this tick.

Files touched

Diff

commit 05ae6c75d1f12618789dff5aa2aa6f1cbc9ebc7e
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu May 7 11:22:52 2026 -0700

    Add per-vertical sample rails to home page (food/beauty/retail/creative)
    
    Home was showing only category-chip counts plus the existing 'Featured'
    rail (claim+tier-gated, only 9 cards). With 1,819 corridor-seeded
    listings, the home page should preview the directory's depth, not just
    gate-keep behind a search box.
    
    Top 4 verticals by count get a 6-card preview rail with 'See all N →'
    link. Cards prioritize photographed/claimed/premier rows then random,
    so the rail rotates per request and rewards owners who fill out their
    page. Today's home: 28 unique business links vs. 9 before — a 3x lift
    in click targets without changing any other section.
    
    JSON-LD LocalBusiness + BreadcrumbList already exists on
    /business/<slug>; no structured-data work needed this tick.
---
 routes/public.js      | 29 ++++++++++++++++++++++++++++-
 views/public/home.ejs | 38 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 66 insertions(+), 1 deletion(-)

diff --git a/routes/public.js b/routes/public.js
index c6a82a7..9da3dc9 100644
--- a/routes/public.js
+++ b/routes/public.js
@@ -49,10 +49,37 @@ router.get('/', async (req, res, next) => {
     `);
     const verticalCountMap = Object.fromEntries(verticalCounts.map(r => [r.vertical, r.n]));
 
+    // Per-vertical sample rails. Pick the 4 verticals with the most active
+    // listings (currently food/beauty/retail/creative ≈ 1,690 of 1,819).
+    // For each, pull 6 sample businesses prioritizing those with photos
+    // and claimed status — they look nicer in the rail and reward owners
+    // who've put work into their page. Random within each priority bucket
+    // so the rail rotates per request.
+    const TOP_RAIL_VERTICALS = Object.entries(verticalCountMap)
+      .sort((a, b) => b[1] - a[1])
+      .slice(0, 4)
+      .map(([k]) => k);
+    const verticalSamples = {};
+    for (const vk of TOP_RAIL_VERTICALS) {
+      const rows = await db.many(`
+        SELECT id, slug, business_name, vertical, headline, neighborhood, city, state,
+               tier, claim_status, verified, photo_path
+          FROM businesses
+         WHERE status = 'active' AND vertical = $1
+         ORDER BY (photo_path IS NOT NULL) DESC,
+                  (claim_status IN ('self','claimed')) DESC,
+                  tier = 'premier' DESC, tier = 'standard' DESC,
+                  RANDOM()
+         LIMIT 6
+      `, [vk]);
+      if (rows.length) verticalSamples[vk] = rows;
+    }
+
     res.render('public/home', {
       title: 'Ventura Claw — directory of Ventura Blvd small businesses',
       metaDescription: `Find local restaurants, salons, retail, fitness, pet, auto detail, cleaning, and creative businesses on Ventura Blvd. ${stats.total} listings across Sherman Oaks, Studio City, Encino, Tarzana, and Woodland Hills — owners claim and update their own page.`,
-      stats, featured, recentlyJoined, verticals: VERTICALS, verticalCountMap
+      stats, featured, recentlyJoined, verticals: VERTICALS, verticalCountMap,
+      verticalSamples
     });
   } catch (err) { next(err); }
 });
diff --git a/views/public/home.ejs b/views/public/home.ejs
index a830514..8f4d92a 100644
--- a/views/public/home.ejs
+++ b/views/public/home.ejs
@@ -62,6 +62,44 @@
   </div>
 </section>
 
+<% if (typeof verticalSamples !== 'undefined' && verticalSamples) {
+     // Render rails in the same order verticalCountMap dictates (largest first).
+     // Each rail = 6-card preview + a "see all N <vertical>" link to the filter.
+     verticals.forEach(function(vv){
+       var rows = verticalSamples[vv.key];
+       if (!rows || rows.length < 3) return;
+       var totalForV = verticalCountMap[vv.key] || rows.length;
+%>
+  <section class="find-page" style="padding-top:24px">
+    <div style="display:flex;align-items:baseline;justify-content:space-between;flex-wrap:wrap;gap:12px;margin:0 0 16px">
+      <h2 style="margin:0"><span aria-hidden="true"><%= vv.icon %></span> <%= vv.label %> on Ventura Blvd</h2>
+      <a href="/find?vertical=<%= vv.key %>" class="muted" style="font-size:13px;font-weight:600;text-decoration:underline">
+        See all <%= totalForV %> →
+      </a>
+    </div>
+    <div class="business-grid" style="grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:14px">
+      <% rows.forEach(function(b){ %>
+        <a class="business-card" href="/business/<%= b.slug %>" style="padding:14px 16px">
+          <% if (b.photo_path) { %>
+            <div class="biz-card-hero biz-card-hero-photo" style="aspect-ratio:16/9;margin:-14px -16px 12px">
+              <img src="<%= b.photo_path %>" alt="<%= b.business_name %>" loading="lazy" decoding="async">
+            </div>
+          <% } else { %>
+            <div class="biz-card-hero vertical-hero-<%= b.vertical %>" aria-hidden="true" style="aspect-ratio:16/9;margin:-14px -16px 12px">
+              <%- include('../partials/vertical-glyph', { verticalKey: b.vertical }) %>
+            </div>
+          <% } %>
+          <p class="biz-name" style="font-size:15px;margin:2px 0"><%= b.business_name %></p>
+          <p class="biz-loc" style="font-size:11px;margin:0"><%= [b.neighborhood, b.city].filter(Boolean).join(' · ') %></p>
+          <% if (b.claim_status === 'self' || b.claim_status === 'claimed') { %>
+            <p class="muted" style="font-size:10px;margin:4px 0 0;letter-spacing:0.05em;text-transform:uppercase">✓ Claimed</p>
+          <% } %>
+        </a>
+      <% }); %>
+    </div>
+  </section>
+<% }); } %>
+
 <section class="faq">
   <h2>Common questions</h2>
   <details class="faq-item">

← 5cc49d8 Sitemap covers paginated pages; head supports rel=prev/next  ·  back to Ventura Claw Leads  ·  Add 37 vertical+city combo pages to sitemap; unclaimed banne d421ce8 →