From 08df1ad4c1a47d63297800ba292cb2edb3c28268 Mon Sep 17 00:00:00 2001 From: Ryan Salazar Date: Fri, 8 May 2026 06:25:29 +0000 Subject: [PATCH] wire /news/[slug] and /articles/[slug] to read bb.wp_imported_posts via ISR - new src/lib/articles/legacy-source.ts: server-side Supabase reader (bb schema, anon key, RLS public_read policy) that maps imported rows to the existing Article shape, applies rewriteLegacyImageUrl for the featured image and rewriteLegacyImageUrlsInHtml across the body. - both [slug]/page.tsx routes now: try seed sampleArticles first; on miss fall back to getLegacyArticleBySlug. Related articles match via same-category recent posts when imported. - generateStaticParams pre-renders seed slugs + 50 most recent imported posts. dynamicParams=true means anything else server-renders on first request and ISR caches it for 1h (revalidate=3600). Avoids a 4577-page build. - Hardcoded builtwithrocket.new URLs in JSON-LD replaced with process.env.NEXT_PUBLIC_SITE_URL. --- src/app/articles/[slug]/page.tsx | 102 +++++++++++----------- src/app/news/[slug]/page.tsx | 86 +++++++++--------- src/lib/articles/legacy-source.ts | 139 ++++++++++++++++++++++++++++++ 3 files changed, 233 insertions(+), 94 deletions(-) create mode 100644 src/lib/articles/legacy-source.ts diff --git a/src/app/articles/[slug]/page.tsx b/src/app/articles/[slug]/page.tsx index fba3f06..46a80f4 100644 --- a/src/app/articles/[slug]/page.tsx +++ b/src/app/articles/[slug]/page.tsx @@ -1,91 +1,89 @@ -import type { Metadata } from 'next'; -import { notFound } from 'next/navigation'; -import ArticleDetailPage from './ArticleDetailClient'; -import { sampleArticles, getRelatedArticles } from '@/lib/articles/sampleArticles'; +import type { Metadata } from "next"; +import { notFound } from "next/navigation"; +import ArticleDetailPage from "./ArticleDetailClient"; +import { sampleArticles, getRelatedArticles, type Article } from "@/lib/articles/sampleArticles"; +import { + getLegacyArticleBySlug, + getLegacyRecentSlugs, + getLegacyRelatedArticles, +} from "@/lib/articles/legacy-source"; + +export const revalidate = 3600; +export const dynamicParams = true; -// DO NOT OVERRIDE — article slug generation and metadata interface PageProps { params: Promise<{ slug: string }>; } +const SITE_URL = + process.env.NEXT_PUBLIC_SITE_URL || "https://bb-staging.onsethost.com"; + +async function loadArticle(slug: string): Promise<{ + article: Article | null; + related: Article[]; +}> { + const seed = sampleArticles.find((a) => a.slug === slug); + if (seed) { + return { article: seed, related: getRelatedArticles(slug, 3) }; + } + const imported = await getLegacyArticleBySlug(slug); + if (!imported) return { article: null, related: [] }; + const related = await getLegacyRelatedArticles(slug, imported.category, 3); + return { article: imported, related }; +} + export async function generateMetadata({ params }: PageProps): Promise { const { slug } = await params; - const article = sampleArticles.find((a) => a.slug === slug); - + const { article } = await loadArticle(slug); if (!article) { - return { - title: 'Article Not Found', - description: 'The article you are looking for does not exist.', - }; + return { title: "Article Not Found", description: "The article you are looking for does not exist." }; } - return { title: article.title, description: article.excerpt, - alternates: { - canonical: `/articles/${article.slug}`, - }, + alternates: { canonical: `/articles/${article.slug}` }, openGraph: { - type: 'article', + type: "article", title: article.title, description: article.excerpt, url: `/articles/${article.slug}`, - images: [ - { - url: article.image, - width: 1200, - height: 630, - alt: article.alt, - type: 'image/jpeg', - }, - ], + images: [{ url: article.image, width: 1200, height: 630, alt: article.alt }], authors: [article.author], publishedTime: article.date, tags: article.tags, }, twitter: { - card: 'summary_large_image', + card: "summary_large_image", title: article.title, description: article.excerpt, images: [article.image], - creator: '@BroadcastBeat', + creator: "@BroadcastBeat", }, }; } export async function generateStaticParams() { - return sampleArticles.map((article) => ({ - slug: article.slug, - })); + const seedSlugs = sampleArticles.map((a) => a.slug); + const recent = await getLegacyRecentSlugs(50); + return Array.from(new Set([...seedSlugs, ...recent])).map((slug) => ({ slug })); } export default async function ArticlePage({ params }: PageProps) { const { slug } = await params; - const article = sampleArticles.find((a) => a.slug === slug); - - if (!article) { - notFound(); - } - - const related = getRelatedArticles(slug, 3); + const { article, related } = await loadArticle(slug); + if (!article) notFound(); const articleSchema = { - '@context': 'https://schema.org', - '@type': 'Article', + "@context": "https://schema.org", + "@type": "Article", headline: article.title, description: article.excerpt, image: article.image, - author: { - '@type': 'Person', - name: article.author, - }, + author: { "@type": "Person", name: article.author }, publisher: { - '@type': 'Organization', - name: 'BroadcastBeat', - logo: { - '@type': 'ImageObject', - url: 'https://broadcastb5322.builtwithrocket.new/assets/images/logo.png', - }, + "@type": "Organization", + name: "BroadcastBeat", + logo: { "@type": "ImageObject", url: `${SITE_URL}/legacy/site/broadcastbeat-logo.png` }, }, datePublished: article.date, dateModified: new Date().toISOString(), @@ -95,11 +93,9 @@ export default async function ArticlePage({ params }: PageProps) { <>