From 873a0962c6c3d71141830db564dac0e8601f7994 Mon Sep 17 00:00:00 2001 From: Myron Blair Date: Sun, 14 Jun 2026 22:50:25 +0000 Subject: [PATCH] SEO overhaul: product schema, dynamic sitemap, favicon, og-image fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - product.php: set metaTitle, metaDescription, canonicalUrl, ogImage, ogType=product, productSchema (JSON-LD with price/availability/reviews), and breadcrumbs variables for header.php to consume - sitemap.php: dynamic XML sitemap generated from DB — includes all 30 active products + static pages; robots.txt now points here - header.php: fix favicon links (favicon.ico in root + icon-192.png); fix productSchema output (was double-encoding via json_encode) - robots.txt: point Sitemap directive to /sitemap.php Co-Authored-By: Claude Sonnet 4.6 --- includes/header.php | 8 +++++--- product.php | 50 ++++++++++++++++++++++++++++++++++++++++++--- robots.txt | 2 +- sitemap.php | 42 +++++++++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 7 deletions(-) create mode 100644 sitemap.php diff --git a/includes/header.php b/includes/header.php index 97b6387..c20f491 100644 --- a/includes/header.php +++ b/includes/header.php @@ -54,7 +54,7 @@ $customerUser = $isLoggedIn ? CustomerAuth::getUser() : null; - + @@ -78,8 +78,10 @@ $customerUser = $isLoggedIn ? CustomerAuth::getUser() : null; - - + + + + diff --git a/product.php b/product.php index a7170ee..b3fd904 100644 --- a/product.php +++ b/product.php @@ -23,9 +23,6 @@ if (!$product) { exit; } -$pageTitle = $product['name'] . " - Tom's Java Jive"; -$pageDescription = truncate(strip_tags($product['description']), 160); - // Get product reviews $reviews = db()->fetchAll( "SELECT * FROM reviews WHERE product_id = :id AND is_approved = 1 ORDER BY created_at DESC LIMIT 10", @@ -49,6 +46,53 @@ $mainImage = !empty($images) ? $images[0] : '/assets/images/placeholder-product. $salePrice = $product['sale_price']; $price = $product['price']; $inStock = $product['stock'] > 0; +$displayPrice = $salePrice ?? $price; + +// SEO meta +$categoryLabel = ucfirst($product['category'] ?? 'Coffee'); +$metaTitle = $product['name'] . ' ' . $categoryLabel . " Coffee | Tom's Java Jive"; +$metaDescription = truncate(strip_tags($product['description'] ?? ''), 155) + ?: $product['name'] . ' flavored artisan coffee beans freshly roasted in Weatherford, TX. Available in whole bean and ground. Ships nationwide.'; +$metaKeywords = strtolower($product['name']) . ' coffee, ' . strtolower($categoryLabel) . ' coffee, flavored coffee beans, artisan coffee, buy coffee online'; +$canonicalUrl = 'https://tomsjavajive.com/product.php?id=' . $productId; +$ogType = 'product'; +$ogImage = (strpos($mainImage, 'http') === 0) ? $mainImage : 'https://tomsjavajive.com' . $mainImage; + +// Structured data — Product schema +$productSchemaData = [ + '@context' => 'https://schema.org', + '@type' => 'Product', + 'name' => $product['name'] . ' ' . $categoryLabel . ' Coffee', + 'url' => $canonicalUrl, + 'image' => $ogImage, + 'description' => $metaDescription, + 'brand' => ['@type' => 'Brand', 'name' => "Tom's Java Jive"], + 'offers' => [ + '@type' => 'Offer', + 'priceCurrency' => 'USD', + 'price' => number_format((float) $displayPrice, 2, '.', ''), + 'availability' => $inStock ? 'https://schema.org/InStock' : 'https://schema.org/OutOfStock', + 'url' => $canonicalUrl, + 'seller' => ['@type' => 'Organization', 'name' => "Tom's Java Jive"], + ], +]; +if ($reviewCount > 0) { + $productSchemaData['aggregateRating'] = [ + '@type' => 'AggregateRating', + 'ratingValue' => round($avgRating, 1), + 'reviewCount' => $reviewCount, + 'bestRating' => 5, + 'worstRating' => 1, + ]; +} +$productSchema = json_encode($productSchemaData, JSON_UNESCAPED_SLASHES); + +// Breadcrumbs +$breadcrumbs = [ + ['name' => 'Home', 'url' => 'https://tomsjavajive.com/'], + ['name' => 'Shop', 'url' => 'https://tomsjavajive.com/shop.php'], + ['name' => $product['name'], 'url' => $canonicalUrl], +]; require_once __DIR__ . '/includes/header.php'; ?> diff --git a/robots.txt b/robots.txt index 4eb8727..7e99f8c 100644 --- a/robots.txt +++ b/robots.txt @@ -8,4 +8,4 @@ Disallow: /checkout.php Disallow: /payment.php Disallow: /config/ Disallow: /install/ -Sitemap: https://tomsjavajive.com/sitemap.xml +Sitemap: https://tomsjavajive.com/sitemap.php diff --git a/sitemap.php b/sitemap.php new file mode 100644 index 0000000..98d7802 --- /dev/null +++ b/sitemap.php @@ -0,0 +1,42 @@ +fetchAll( + "SELECT product_id, updated_at FROM products WHERE is_active = 1 ORDER BY created_at DESC" +); + +echo '' . "\n"; +echo '' . "\n"; + +// Static pages +$staticPages = [ + ['loc' => '/', 'priority' => '1.0', 'changefreq' => 'weekly'], + ['loc' => '/shop.php', 'priority' => '0.9', 'changefreq' => 'daily'], + ['loc' => '/about.php', 'priority' => '0.6', 'changefreq' => 'monthly'], + ['loc' => '/contact.php', 'priority' => '0.5', 'changefreq' => 'monthly'], + ['loc' => '/login.php', 'priority' => '0.3', 'changefreq' => 'monthly'], + ['loc' => '/register.php','priority' => '0.3', 'changefreq' => 'monthly'], +]; + +foreach ($staticPages as $p) { + $loc = htmlspecialchars($base . $p['loc']); + echo " {$loc}{$now}{$p['changefreq']}{$p['priority']}\n"; +} + +// Product pages +foreach ($products as $product) { + $loc = htmlspecialchars($base . '/product.php?id=' . $product['product_id']); + $lastmod = substr($product['updated_at'] ?? $now, 0, 10); + echo " {$loc}{$lastmod}weekly0.8\n"; +} + +echo '';