Product names already include 'Whole Bean Coffee' / 'Ground Coffee' so
appending the category label was doubling the suffix. Now only appends
if the product name doesn't already contain 'coffee'.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fresh Tom's Java Jive logo with coffee cup, Tom's Java Jive text,
Artisan Coffee Roaster, and www.tomsjavajive.com. Bump logo display
height to 65px to suit square aspect ratio.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add contact.php (was 404, linked from footer and returns page)
- Add shippingDetails and hasMerchantReturnPolicy to product schema
- Add priceValidUntil to product Offer schema
- Improve merchant feed descriptions (use DB description when present)
- Add handling/transit times and return_policy_label to feed
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extract account/cart/checkout styles into dedicated CSS files; remove inline styles and orphaned style blocks from HTML. Wire $extraHead on all account pages, cart.php, and checkout.php.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Split style.css into home.css (hero, features, newsletter, splash) and
products.css (product grid/cards). Each page loads only what it needs
via $extraHead. style.css now contains only truly shared styles.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Merged Company + Support into a single Help column, removed Sub
Categories section. Tightened grid gap, padding, and list spacing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- merchant-feed.php: RSS 2.0 feed with all active products; includes
title, description, image_link, price, availability, brand, shipping,
google_product_category for each item; URL to submit in Merchant Center
- header.php: placeholder GSC meta tag (replace PASTE_GSC_CODE_HERE with
verification content value from Search Console)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>
- LoyaltyProgram now loads tiers from loyalty_tiers DB table in constructor
with fallback to hardcoded defaults if table is empty
- awardPoints() accepts order_id param with duplicate-prevention check so
points cannot be double-awarded for the same order
- Inserts balance_after into loyalty_transactions for accurate history
- payment-status.php: award points after Stripe checkout session or
PaymentIntent confirmed as paid
- create-checkout-session.php: award points in demo mode payment path
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Missing ob_start() meant HTML was output before POST handler ran,
so header() redirects silently failed after saving changes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Combined the large hero section and two-row filter section into a single
compact dark header bar. Category and type pills are inline with a divider,
search/sort sit in the header row. Reduced section top padding.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove service worker registration from footer (SW is already self-unregistering)
- Add mobile-web-app-capable meta to fix deprecation warning
- Remove missing icon references from manifest (only 192/512 PNGs exist)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
DB column is stripe_session_id but code was writing to stripe_checkout_session,
causing a 500 on checkout and breaking payment status checks.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Partial DOM update was missing item row totals, shipping recalc, and
grand total. Reload ensures all numbers are always correct.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Button used add-to-cart/data-id instead of add-to-cart-btn/data-product-id.
Added inline onclick to match shop and product pages.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
SW was caching shop pages and JS files, serving stale versions without
the inline onclick handler. Replacing with self-unregistering SW.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All api/*.php files include functions.php but none called session_start(),
so $_SESSION writes were lost after each request. Cart appeared to work
(API returned cart_count:1) but nothing was ever saved.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Service worker was caching main.js (cache-first strategy) so event listeners
may not have been running. Added filemtime version param to main.js like CSS.
Also added inline onclick to shop page buttons so they work regardless of
whether event delegation is functional.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prefixed is_active, category, product_type_id, name, description, and ORDER BY columns with table alias p to resolve ambiguity with the product_types JOIN.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Shows how many active products are linked to each type, linked to the filtered products list.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add display:block to .product-card-image so padding-top aspect ratio works on anchor tags
- Add Cache-Control: no-transform header to disable Cloudflare Rocket Loader (was deferring main.js and breaking add-to-cart click handlers)
- Add Sub Categories filter row on shop page using product_types table
- Show category · sub-category on product cards
- Add Sub Categories section to footer
- Preserve subcat param across category/sort filter links
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- faq.php: accordion FAQ with Orders, Coffee & Products, Coffee Freshness & Storage, and Account sections
- shipping.php: rates table (3-5 days after processing), processing time, delivery flow
- returns.php: three-tier policy (your/our/shared responsibility) adapted from DripShipper
- track-order.php: order lookup by order number + email, progress steps, tracking link
- privacy.php: full privacy policy adapted for Toms Java Jive
- footer.php: added Privacy Policy link to Support section
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mirrors the checkout.session.completed case which checks
payment_status === paid before acting. Now checks data.status
=== succeeded on the PaymentIntent object, consistent with how
Stripe structures the event and defensive against any future
edge case where the event fires in a non-final state.
- Email::send(): add curl_error() check so transport failures (timeout,
DNS, TLS) return a diagnosable error string instead of Unknown error
- Email::send(): strip metadata key from options before array_merge so
non-API fields are never sent to CyberMail endpoint
- Email::send() + sendEmail(): include from-name in From field using
RFC 5322 "Name <email>" format so fromName DB setting takes effect
- email-log.php: replace unbounded page-link loop with a windowed
paginator (first/last 2 pages + ±2 around current) with ellipsis
gaps — prevents hundreds of anchors rendering at scale