SEO overhaul: product schema, dynamic sitemap, favicon, og-image fix

- 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 <noreply@anthropic.com>
This commit is contained in:
2026-06-14 22:50:25 +00:00
parent f89362528a
commit 873a0962c6
4 changed files with 95 additions and 7 deletions
+47 -3
View File
@@ -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';
?>