Fertig
This commit is contained in:
166
lib/seo.ts
Normal file
166
lib/seo.ts
Normal file
@@ -0,0 +1,166 @@
|
||||
import type { Metadata } from "next";
|
||||
import { siteConfig } from "@/data/site-content";
|
||||
|
||||
type PageMetadataInput = {
|
||||
title: string;
|
||||
description: string;
|
||||
path: string;
|
||||
image?: string;
|
||||
};
|
||||
|
||||
type FaqEntry = {
|
||||
question: string;
|
||||
answer: string;
|
||||
};
|
||||
|
||||
type ItemListEntry = {
|
||||
name: string;
|
||||
path?: string;
|
||||
};
|
||||
|
||||
export function buildMetadataBase() {
|
||||
const rawUrl = process.env.NEXT_PUBLIC_SITE_URL || siteConfig.siteUrl;
|
||||
|
||||
return new URL(rawUrl.endsWith("/") ? rawUrl : `${rawUrl}/`);
|
||||
}
|
||||
|
||||
export function buildAbsoluteUrl(path: string) {
|
||||
return new URL(path, buildMetadataBase()).toString();
|
||||
}
|
||||
|
||||
export function buildPageMetadata({
|
||||
title,
|
||||
description,
|
||||
path,
|
||||
image = siteConfig.defaultOgImage,
|
||||
}: PageMetadataInput): Metadata {
|
||||
return {
|
||||
title,
|
||||
description,
|
||||
alternates: {
|
||||
canonical: path,
|
||||
},
|
||||
openGraph: {
|
||||
title,
|
||||
description,
|
||||
url: path,
|
||||
images: [
|
||||
{
|
||||
url: image,
|
||||
alt: title,
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
title,
|
||||
description,
|
||||
images: [image],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function websiteSchema() {
|
||||
return {
|
||||
"@type": "WebSite",
|
||||
name: siteConfig.name,
|
||||
url: buildAbsoluteUrl("/"),
|
||||
};
|
||||
}
|
||||
|
||||
export function businessSchema() {
|
||||
return {
|
||||
"@type": "LocalBusiness",
|
||||
name: siteConfig.name,
|
||||
url: buildAbsoluteUrl("/"),
|
||||
description: siteConfig.description,
|
||||
logo: buildAbsoluteUrl(siteConfig.brand.primaryLogo),
|
||||
image: buildAbsoluteUrl(siteConfig.defaultOgImage),
|
||||
telephone: siteConfig.phoneDisplay,
|
||||
address: {
|
||||
"@type": "PostalAddress",
|
||||
streetAddress: siteConfig.address.street,
|
||||
addressLocality: "Corpus Christi",
|
||||
addressRegion: "TX",
|
||||
postalCode: "78405",
|
||||
addressCountry: "US",
|
||||
},
|
||||
sameAs: siteConfig.socials.map((social) => social.href),
|
||||
contactPoint: [
|
||||
{
|
||||
"@type": "ContactPoint",
|
||||
telephone: siteConfig.phoneDisplay,
|
||||
contactType: "customer service",
|
||||
areaServed: "Corpus Christi, TX",
|
||||
},
|
||||
],
|
||||
openingHoursSpecification: [
|
||||
{
|
||||
"@type": "OpeningHoursSpecification",
|
||||
dayOfWeek: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
|
||||
opens: "08:00",
|
||||
closes: "17:00",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
export function localBusinessSchema() {
|
||||
return {
|
||||
"@context": "https://schema.org",
|
||||
...businessSchema(),
|
||||
};
|
||||
}
|
||||
|
||||
export function breadcrumbSchema(items: { name: string; path: string }[]) {
|
||||
return {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
itemListElement: items.map((item, index) => ({
|
||||
"@type": "ListItem",
|
||||
position: index + 1,
|
||||
name: item.name,
|
||||
item: buildAbsoluteUrl(item.path),
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
export function faqPageSchema(items: FaqEntry[]) {
|
||||
return {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "FAQPage",
|
||||
mainEntity: items.map((item) => ({
|
||||
"@type": "Question",
|
||||
name: item.question,
|
||||
acceptedAnswer: {
|
||||
"@type": "Answer",
|
||||
text: item.answer,
|
||||
},
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
export function itemListSchema({
|
||||
name,
|
||||
path,
|
||||
items,
|
||||
}: {
|
||||
name: string;
|
||||
path: string;
|
||||
items: ItemListEntry[];
|
||||
}) {
|
||||
return {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "ItemList",
|
||||
name,
|
||||
url: buildAbsoluteUrl(path),
|
||||
numberOfItems: items.length,
|
||||
itemListOrder: "https://schema.org/ItemListOrderAscending",
|
||||
itemListElement: items.map((item, index) => ({
|
||||
"@type": "ListItem",
|
||||
position: index + 1,
|
||||
name: item.name,
|
||||
url: item.path ? buildAbsoluteUrl(item.path) : undefined,
|
||||
})),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user