diff --git a/app/[filename]/page.tsx b/app/[filename]/page.tsx index c114d2347..1df3a03b4 100644 --- a/app/[filename]/page.tsx +++ b/app/[filename]/page.tsx @@ -2,7 +2,7 @@ import React from "react"; import categoryTitleIndex from "@/category-uri-title-map.json"; import { Section } from "@/components/layout/section"; import { extractBodyPreview } from "@/lib/bodyUtils"; -import { siteUrl } from "@/site-config"; +import { siteDescription, siteUrl } from "@/site-config"; import client from "@/tina/__generated__/client"; import { CategoryWithRulesQueryDocument } from "@/tina/__generated__/types"; import ClientFallbackPage from "./ClientFallbackPage"; @@ -338,31 +338,57 @@ export async function generateMetadata({ params }: { params: Promise<{ filename: const category = await getCategoryData(filename); if (category?.data?.category && category.data.category.__typename === "CategoryCategory") { const categoryData = category.data.category as any; + const title = `${categoryData.title} | SSW.Rules`; + const description = categoryData.seoDescription || siteDescription; + const url = `${siteUrl}/${filename}`; const metadata: any = { - title: `${categoryData.title} | SSW.Rules`, + title, + description, alternates: { - canonical: `${siteUrl}/${filename}`, + canonical: url, + }, + openGraph: { + title, + description, + url, + type: "website", + images: [`${siteUrl}/og-image.jpg`], + }, + twitter: { + card: "summary_large_image", + title, + description, }, }; - if (categoryData.seoDescription) { - metadata.description = categoryData.seoDescription; - } - return metadata; } const rule = await getRuleData(filename); if (rule?.data?.rule?.title) { + const title = `${rule.data.rule.title} | SSW.Rules`; + const description = rule.data.rule.seoDescription || extractBodyPreview(rule.data.rule.body) || siteDescription; + const url = `${siteUrl}/${filename}`; const metadata: any = { - title: `${rule.data.rule.title} | SSW.Rules`, + title, + description, alternates: { - canonical: `${siteUrl}/${filename}`, + canonical: url, + }, + openGraph: { + title, + description, + url, + type: "article", + images: [`${siteUrl}/og-image.jpg`], + }, + twitter: { + card: "summary_large_image", + title, + description, }, }; - metadata.description = rule.data.rule.seoDescription || extractBodyPreview(rule.data.rule.body) || undefined; - if (rule.data.rule.isArchived) { metadata.robots = { index: false, follow: true }; } diff --git a/app/layout.tsx b/app/layout.tsx index caa097c9a..fc5aba528 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -8,6 +8,7 @@ import "@/styles.css"; import UserClientProvider from "@/components/auth/UserClientProvider"; import AppInsightsProvider from "@/components/providers/AppInsightsProvider"; import { TailwindIndicator } from "@/components/ui/breakpoint-indicator"; +import { siteDescription, siteTitle, siteUrl, social } from "@/site-config"; const fontSans = FontSans({ subsets: ["latin"], @@ -26,9 +27,29 @@ const lato = Lato({ }); export const metadata: Metadata = { - title: "SSW.Rules | Secret Ingredients to Quality Software (Open Source on GitHub)", - description: - "Secret Ingredients to Quality Software | SSW Rules provides best practices for developing secure, reliable, and efficient .NET, Azure, CRM, Angular, React, Dynamics, and AI applications. Learn more today!", + metadataBase: new URL(siteUrl), + title: `${siteTitle} | Secret Ingredients to Quality Software (Open Source on GitHub)`, + description: siteDescription, + openGraph: { + title: `${siteTitle} | Secret Ingredients to Quality Software (Open Source on GitHub)`, + description: siteDescription, + url: siteUrl, + siteName: siteTitle, + type: "website", + images: [ + { + url: `${siteUrl}/og-image.jpg`, + width: 1200, + height: 630, + alt: "SSW Rules - Secret Ingredients to Quality Software", + }, + ], + }, + twitter: { + card: "summary_large_image", + site: `@${social.twitter}`, + creator: `@${social.twitter}`, + }, }; const jsonLd = [