From 1c1c01069c99e022a84889c03c0a89db3dec253e Mon Sep 17 00:00:00 2001 From: DMleadgen Date: Thu, 2 Apr 2026 16:28:15 -0600 Subject: [PATCH] deploy: ship 2026 local SEO overhaul --- app/[...slug]/page.tsx | 834 ++++++------------ app/about-us/page.tsx | 72 +- app/about/page.tsx | 39 +- app/blog/abandoned-vending-machines/page.tsx | 85 +- .../page.tsx | 87 +- app/blog/page.tsx | 83 +- app/contact-us/page.tsx | 70 +- app/layout.tsx | 75 +- app/page.tsx | 16 + app/reviews/page.tsx | 27 +- app/robots.ts | 5 +- app/seaga-hy900-support/layout.tsx | 16 + app/service-areas/page.tsx | 194 ++-- app/services/moving/page.tsx | 248 ++++-- app/services/page.tsx | 88 +- app/services/parts/page.tsx | 697 ++++++++++----- app/services/repairs/page.tsx | 563 ++++++++---- app/services/service-areas/page.tsx | 144 ++- app/sitemap.ts | 85 +- app/style-guide/layout.tsx | 19 + app/test-page/page.tsx | 22 +- app/vending-machines-[location]/page.tsx | 434 +-------- app/vending-machines/page.tsx | 27 +- components/breadcrumbs.tsx | 3 - components/contact-section.tsx | 51 +- components/features-section.tsx | 41 +- components/footer.tsx | 120 ++- components/header.tsx | 170 ++-- components/hero-section.tsx | 52 +- components/location-landing-page.tsx | 413 +++++++++ components/organization-schema.tsx | 32 +- components/reviews-page.tsx | 154 ++-- components/reviews-section.tsx | 59 +- components/services-section.tsx | 47 +- components/stats-section.tsx | 12 +- components/structured-data.tsx | 87 +- components/vending-machines-page.tsx | 140 ++- components/website-schema.tsx | 19 + components/who-we-serve-page.tsx | 71 +- lib/seo-registry.ts | 346 ++++++++ lib/seo.ts | 187 ++-- 41 files changed, 3530 insertions(+), 2404 deletions(-) create mode 100644 app/seaga-hy900-support/layout.tsx create mode 100644 app/style-guide/layout.tsx create mode 100644 components/location-landing-page.tsx create mode 100644 components/website-schema.tsx create mode 100644 lib/seo-registry.ts diff --git a/app/[...slug]/page.tsx b/app/[...slug]/page.tsx index b5c86ee0..9909b9b6 100644 --- a/app/[...slug]/page.tsx +++ b/app/[...slug]/page.tsx @@ -1,100 +1,98 @@ -import { notFound } from 'next/navigation'; -import { loadImageMapping } from '@/lib/wordpress-content'; -import { generateSEOMetadata, generateStructuredData } from '@/lib/seo'; -import { getPageBySlug, getAllPageSlugs } from '@/lib/wordpress-data-loader'; -import { cleanWordPressContent } from '@/lib/clean-wordPress-content'; -import { getLocationBySlug, getAllLocationSlugs } from '@/lib/location-data'; -import { businessConfig, socialProfiles } from '@/lib/seo-config'; -import { Phone, Mail, Globe, Clock, CreditCard, MapPin } from 'lucide-react'; -import { Card, CardContent } from '@/components/ui/card'; -import { ReviewsSection } from '@/components/reviews-section'; -import { Button } from '@/components/ui/button'; -import Link from 'next/link'; -import type { Metadata } from 'next'; -import React from 'react'; -import { FAQSchema } from '@/components/faq-schema'; -import { FAQSection } from '@/components/faq-section'; -import { ContactPage } from '@/components/contact-page'; -import { AboutPage } from '@/components/about-page'; -import { WhoWeServePage } from '@/components/who-we-serve-page'; -import { PublicPageHeader, PublicSurface } from '@/components/public-surface'; -import { GetFreeMachineCta } from '@/components/get-free-machine-cta'; +import { notFound } from "next/navigation" +import { loadImageMapping } from "@/lib/wordpress-content" +import { generateSEOMetadata, generateStructuredData } from "@/lib/seo" +import { getPageBySlug, getAllPageSlugs } from "@/lib/wordpress-data-loader" +import { cleanWordPressContent } from "@/lib/clean-wordPress-content" +import { getLocationBySlug, getAllLocationSlugs } from "@/lib/location-data" +import type { Metadata } from "next" +import { FAQSchema } from "@/components/faq-schema" +import { FAQSection } from "@/components/faq-section" +import { ContactPage } from "@/components/contact-page" +import { AboutPage } from "@/components/about-page" +import { WhoWeServePage } from "@/components/who-we-serve-page" +import { + generateLocationPageMetadata, + LocationLandingPage, +} from "@/components/location-landing-page" // Required for static export - ensures this route is statically generated -export const dynamic = 'force-static'; -export const dynamicParams = false; +export const dynamic = "force-static" +export const dynamicParams = false interface PageProps { - params: Promise<{ slug: string[] }>; + params: Promise<{ slug: string[] }> } // Route mapping: navigation URLs -> WordPress page slugs const routeMapping: Record = { // Services - 'services/repairs': 'vending-machine-repairs', - 'services/moving': 'vending-machine-repairs', // Placeholder - no moving page exists - 'services/parts': 'parts-and-support', - 'services': 'vending-machine-repairs', // Default to repairs page - + "services/repairs": "vending-machine-repairs", + "services/moving": "vending-machine-repairs", // Placeholder - no moving page exists + "services/parts": "parts-and-support", + services: "vending-machine-repairs", // Default to repairs page + // Vending Machines - 'vending-machines': 'vending-machines', // Main vending machines page - 'vending-machines/machines-we-use': 'vending-machines', // Use main page - 'vending-machines/machines-for-sale': 'vending-machines-for-sale-in-utah', - + "vending-machines": "vending-machines", // Main vending machines page + "vending-machines/machines-we-use": "vending-machines", // Use main page + "vending-machines/machines-for-sale": "vending-machines-for-sale-in-utah", + // Who We Serve - 'warehouses': 'streamlining-snack-and-beverage-access-in-warehouse-environments', - 'auto-repair': 'enhancing-auto-repair-facilities-with-convenient-vending-solutions', - 'gyms': 'vending-machine-for-your-gym', - 'community-centers': 'vending-for-your-community-centers', - 'dance-studios': 'vending-machine-for-your-dance-studio', - 'car-washes': 'vending-machines-for-your-car-wash', - + warehouses: + "streamlining-snack-and-beverage-access-in-warehouse-environments", + "auto-repair": + "enhancing-auto-repair-facilities-with-convenient-vending-solutions", + gyms: "vending-machine-for-your-gym", + "community-centers": "vending-for-your-community-centers", + "dance-studios": "vending-machine-for-your-dance-studio", + "car-washes": "vending-machines-for-your-car-wash", + // Food & Beverage - 'food-and-beverage/healthy-options': 'healthy-vending', - 'food-and-beverage/traditional-options': 'traditional-vending', - 'food-and-beverage/suppliers': 'diverse-vending-options-with-rocky-mountain-vendings-exclusive-wholesale-accounts', - + "food-and-beverage/healthy-options": "healthy-vending", + "food-and-beverage/traditional-options": "traditional-vending", + "food-and-beverage/suppliers": + "diverse-vending-options-with-rocky-mountain-vendings-exclusive-wholesale-accounts", + // About - 'about-us': 'about-us', - 'about/faqs': 'faqs', - 'contact-us': 'contact-us', -}; + "about-us": "about-us", + "about/faqs": "faqs", + "contact-us": "contact-us", +} // Helper function to resolve route to WordPress slug function resolveRouteToSlug(slugArray: string[]): string | null { - const route = slugArray.join('/'); - + const route = slugArray.join("/") + // Check if this is a location page - if so, return null to let Next.js handle it // (location pages are handled by vending-machines-[location] route) if (isLocationRoute(slugArray)) { - return null; // Let the location route handle it + return null // Let the location route handle it } - + // Check direct mapping first if (routeMapping[route]) { - return routeMapping[route]; + return routeMapping[route] } - + // Check if it's a direct WordPress slug - const directSlug = slugArray.join('-'); + const directSlug = slugArray.join("-") if (getPageBySlug(directSlug)) { - return directSlug; + return directSlug } - + // Check last segment as fallback (for nested routes) if (slugArray.length > 1) { - const lastSegment = slugArray[slugArray.length - 1]; + const lastSegment = slugArray[slugArray.length - 1] if (getPageBySlug(lastSegment)) { - return lastSegment; + return lastSegment } } - + // Try the full route as-is if (getPageBySlug(route)) { - return route; + return route } - - return null; + + return null } // Helper function to check if a route is a location page @@ -102,497 +100,166 @@ function isLocationRoute(slugArray: string[]): boolean { // Location pages follow pattern: vending-machines-{location} // e.g., ["vending-machines-salt-lake-city-utah"] or ["vending-machines", "salt-lake-city-utah"] if (slugArray.length === 1) { - const slug = slugArray[0]; + const slug = slugArray[0] // Check if it starts with "vending-machines-" and the rest is a valid location slug - if (slug.startsWith('vending-machines-')) { - const locationSlug = slug.replace('vending-machines-', ''); - return !!getLocationBySlug(locationSlug); + if (slug.startsWith("vending-machines-")) { + const locationSlug = slug.replace("vending-machines-", "") + return !!getLocationBySlug(locationSlug) } - } else if (slugArray.length === 2 && slugArray[0] === 'vending-machines') { - return !!getLocationBySlug(slugArray[1]); + } else if (slugArray.length === 2 && slugArray[0] === "vending-machines") { + return !!getLocationBySlug(slugArray[1]) } - return false; -} - -// Render location page component -function renderLocationPage(locationData: any, locationSlug: string) { - const structuredData = { - "@context": "https://schema.org", - "@type": "LocalBusiness", - name: businessConfig.name, - description: `Rocky Mountain Vending provides high-quality vending machines, vending machine sales, and vending machine repair services to businesses and schools across ${locationData.city}, ${locationData.state}.`, - url: `${businessConfig.website}/vending-machines-${locationSlug}`, - telephone: businessConfig.phoneFormatted, - priceRange: "$$", - foundingDate: businessConfig.openingDate, - areaServed: { - "@type": "City", - name: locationData.city, - address: { - "@type": "PostalAddress", - addressLocality: locationData.city, - addressRegion: locationData.stateAbbr, - postalCode: locationData.zipCode, - addressCountry: "US", - }, - }, - geo: { - "@type": "GeoCoordinates", - latitude: locationData.latitude, - longitude: locationData.longitude, - }, - openingHoursSpecification: [ - { - "@type": "OpeningHoursSpecification", - dayOfWeek: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"], - opens: "08:00", - closes: "17:00", - }, - ], - paymentAccepted: "Credit Card, Debit Card, American Express, Discover, MasterCard, Visa", - availableLanguage: ["English"], - sameAs: [ - socialProfiles.linkedin, - socialProfiles.facebook, - socialProfiles.youtube, - socialProfiles.twitter, - locationData.chamberUrl, - locationData.cityWebsite, - ...locationData.localLinks.map((link: any) => link.url), - ], - }; - - return ( - <> -