/meta/OG/JSON-LD, and echoes the seller_code // into JS (so all existing API calls still work by code). The full // interactive body (products, reviews, follow) stays client-side. // // PHP 7.4 — no match(), no str_starts_with(). // ============================================================ require_once __DIR__ . '/config/config.php'; // ── Canonical slugify ────────────────────────────────────────── function jh_slugify($s) { $s = mb_strtolower(trim((string)$s), 'UTF-8'); $s = str_replace('&', ' and ', $s); $s = preg_replace('/[^a-z0-9]+/', '-', $s); $s = preg_replace('/-+/', '-', $s); $s = trim($s, '-'); return $s !== '' ? $s : 'store'; } function e($s) { return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); } // ── Resolve seller: prefer ?id= (pretty URL), fall back to ?code= ── $sid = isset($_GET['id']) ? (int) $_GET['id'] : 0; $code = isset($_GET['code']) ? trim((string)$_GET['code']) : ''; $S = null; if ($sid > 0 || $code !== '') { try { $pdo = db(); if ($sid > 0) { $st = $pdo->prepare( "SELECT id, shop_name, seller_code, bio, profile_photo, location, seller_type FROM seller_profiles WHERE id = ? AND status = 'active' LIMIT 1" ); $st->execute([$sid]); } else { $st = $pdo->prepare( "SELECT id, shop_name, seller_code, bio, profile_photo, location, seller_type FROM seller_profiles WHERE seller_code = ? AND status = 'active' LIMIT 1" ); $st->execute([strtoupper($code)]); } $S = $st->fetch(); } catch (Exception $ex) { $S = null; } } // ── If found via code= (legacy link), 301 to the canonical /store/ URL ── if ($S && $sid === 0 && $code !== '') { $slug = jh_slugify($S['shop_name']); header('Location: ' . JH_BASE_URL . '/store/' . (int)$S['id'] . '/' . $slug . '/', true, 301); exit; } // ── SEO head values ────────────────────────────────────────────── $SITE = 'Jirani Hub Market'; if ($S) { $shop = $S['shop_name']; $slug = jh_slugify($shop); $canonical = JH_BASE_URL . '/store/' . (int)$S['id'] . '/' . $slug . '/'; $og_img = JH_BASE_URL . '/icons/og-default.png'; if (!empty($S['profile_photo'])) $og_img = $S['profile_photo']; $raw_bio = trim((string)($S['bio'] ?? '')); if ($raw_bio === '') { $raw_bio = $shop . ' — local seller on Jirani Hub Market, serving Dagoretti South. Shop now with same-day Nairobi delivery.'; } $meta_desc = mb_substr($raw_bio, 0, 158, 'UTF-8'); if (mb_strlen($raw_bio, 'UTF-8') > 158) $meta_desc .= '…'; $page_title = $shop . ' — ' . $SITE; $jsonld = json_encode([ [ '@context' => 'https://schema.org', '@type' => 'Store', 'name' => $shop, 'description' => $meta_desc, 'image' => $og_img, 'url' => $canonical, 'address' => ['@type' => 'PostalAddress', 'addressLocality' => $S['location'] ?: 'Dagoretti, Nairobi'], ], [ '@context' => 'https://schema.org', '@type' => 'BreadcrumbList', 'itemListElement' => [ ['@type'=>'ListItem','position'=>1,'name'=>'Home', 'item'=>JH_BASE_URL.'/'], ['@type'=>'ListItem','position'=>2,'name'=>'Browse','item'=>JH_BASE_URL.'/browse/'], ['@type'=>'ListItem','position'=>3,'name'=>$shop, 'item'=>$canonical], ], ], ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); } else { // Unknown seller — shell renders, client JS shows its own error. http_response_code(404); $page_title = 'Seller not found — ' . $SITE; $meta_desc = 'This seller could not be found on Jirani Hub Market.'; $canonical = JH_BASE_URL . '/browse/'; $og_img = JH_BASE_URL . '/icons/og-default.png'; $jsonld = ''; } ?> <?= e($page_title) ?>