json
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { notFound } from 'next/navigation';
|
import { notFound } from 'next/navigation';
|
||||||
import Script from 'next/script';
|
import Script from 'next/script';
|
||||||
import JsonLd from '@/components/JsonLd';
|
import JsonLd from '@/components/JsonLd';
|
||||||
|
import { getBreadcrumbSchema, SITE_URL, LOGO_URL } from '@/lib/schema';
|
||||||
import { MDXRemote } from 'next-mdx-remote/rsc';
|
import { MDXRemote } from 'next-mdx-remote/rsc';
|
||||||
import { getPostBySlug, getAdjacentPosts, getReadingTime, getHeadings } from '@/lib/blog';
|
import { getPostBySlug, getAdjacentPosts, getReadingTime, getHeadings } from '@/lib/blog';
|
||||||
import { Metadata } from 'next';
|
import { Metadata } from 'next';
|
||||||
@@ -322,31 +323,58 @@ export default async function BlogPost({ params: { locale, slug } }: BlogPostPro
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Structured Data */}
|
{/* Structured Data */}
|
||||||
<Script
|
<JsonLd
|
||||||
id={`jsonld-${slug}`}
|
id={`jsonld-${slug}`}
|
||||||
type="application/ld+json"
|
data={{
|
||||||
dangerouslySetInnerHTML={{
|
'@context': 'https://schema.org',
|
||||||
__html: JSON.stringify({
|
'@type': 'BlogPosting',
|
||||||
'@context': 'https://schema.org',
|
headline: post.frontmatter.title,
|
||||||
'@type': 'BlogPosting',
|
datePublished: post.frontmatter.date,
|
||||||
headline: post.frontmatter.title,
|
dateModified: post.frontmatter.date,
|
||||||
datePublished: post.frontmatter.date,
|
image: post.frontmatter.featuredImage ? `https://klz-cables.com${post.frontmatter.featuredImage}` : undefined,
|
||||||
image: post.frontmatter.featuredImage ? `https://klz-cables.com${post.frontmatter.featuredImage}` : undefined,
|
author: {
|
||||||
author: {
|
'@type': 'Organization',
|
||||||
'@type': 'Organization',
|
name: 'KLZ Cables',
|
||||||
name: 'KLZ Cables',
|
url: 'https://klz-cables.com',
|
||||||
url: 'https://klz-cables.com',
|
logo: 'https://klz-cables.com/logo.png'
|
||||||
|
},
|
||||||
|
publisher: {
|
||||||
|
'@type': 'Organization',
|
||||||
|
name: 'KLZ Cables',
|
||||||
|
logo: {
|
||||||
|
'@type': 'ImageObject',
|
||||||
|
url: 'https://klz-cables.com/logo.png',
|
||||||
},
|
},
|
||||||
publisher: {
|
},
|
||||||
'@type': 'Organization',
|
description: post.frontmatter.excerpt,
|
||||||
name: 'KLZ Cables',
|
mainEntityOfPage: {
|
||||||
logo: {
|
'@type': 'WebPage',
|
||||||
'@type': 'ImageObject',
|
'@id': `https://klz-cables.com/${locale}/blog/${slug}`,
|
||||||
url: 'https://klz-cables.com/logo.png',
|
},
|
||||||
},
|
articleSection: post.frontmatter.category,
|
||||||
|
wordCount: post.content.split(/\s+/).length,
|
||||||
|
timeRequired: `PT${getReadingTime(post.content)}M`
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<JsonLd
|
||||||
|
id={`breadcrumb-${slug}`}
|
||||||
|
data={{
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'BreadcrumbList',
|
||||||
|
itemListElement: [
|
||||||
|
{
|
||||||
|
'@type': 'ListItem',
|
||||||
|
position: 1,
|
||||||
|
name: 'Blog',
|
||||||
|
item: `https://klz-cables.com/${locale}/blog`,
|
||||||
},
|
},
|
||||||
description: post.frontmatter.excerpt,
|
{
|
||||||
}),
|
'@type': 'ListItem',
|
||||||
|
position: 2,
|
||||||
|
name: post.frontmatter.title,
|
||||||
|
item: `https://klz-cables.com/${locale}/blog/${slug}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</article>
|
</article>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useTranslations } from 'next-intl';
|
|||||||
import { getTranslations } from 'next-intl/server';
|
import { getTranslations } from 'next-intl/server';
|
||||||
import { Metadata } from 'next';
|
import { Metadata } from 'next';
|
||||||
import JsonLd from '@/components/JsonLd';
|
import JsonLd from '@/components/JsonLd';
|
||||||
|
import { getBreadcrumbSchema, SITE_URL, LOGO_URL } from '@/lib/schema';
|
||||||
import { Section, Container, Button, Heading, Card, Input, Textarea, Label } from '@/components/ui';
|
import { Section, Container, Button, Heading, Card, Input, Textarea, Label } from '@/components/ui';
|
||||||
|
|
||||||
interface ContactPageProps {
|
interface ContactPageProps {
|
||||||
@@ -57,6 +58,47 @@ export default function ContactPage() {
|
|||||||
],
|
],
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<JsonLd
|
||||||
|
id="local-business-contact"
|
||||||
|
data={{
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'LocalBusiness',
|
||||||
|
name: 'KLZ Cables',
|
||||||
|
image: 'https://klz-cables.com/logo.png',
|
||||||
|
'@id': 'https://klz-cables.com',
|
||||||
|
url: 'https://klz-cables.com',
|
||||||
|
telephone: '+49 881 92537298',
|
||||||
|
address: {
|
||||||
|
'@type': 'PostalAddress',
|
||||||
|
streetAddress: 'Trifthofstraße 57',
|
||||||
|
addressLocality: 'Weilheim i. OB',
|
||||||
|
postalCode: '82362',
|
||||||
|
addressCountry: 'DE',
|
||||||
|
},
|
||||||
|
geo: {
|
||||||
|
'@type': 'GeoCoordinates',
|
||||||
|
latitude: 47.8407,
|
||||||
|
longitude: 11.1421,
|
||||||
|
},
|
||||||
|
openingHoursSpecification: [
|
||||||
|
{
|
||||||
|
'@type': 'OpeningHoursSpecification',
|
||||||
|
dayOfWeek: [
|
||||||
|
'Monday',
|
||||||
|
'Tuesday',
|
||||||
|
'Wednesday',
|
||||||
|
'Thursday',
|
||||||
|
'Friday'
|
||||||
|
],
|
||||||
|
opens: '08:00',
|
||||||
|
closes: '17:00'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
sameAs: [
|
||||||
|
'https://www.linkedin.com/company/klz-cables'
|
||||||
|
]
|
||||||
|
}}
|
||||||
|
/>
|
||||||
{/* Hero Section */}
|
{/* Hero Section */}
|
||||||
<section className="bg-primary-dark text-white py-20 md:py-32 relative overflow-hidden">
|
<section className="bg-primary-dark text-white py-20 md:py-32 relative overflow-hidden">
|
||||||
<div className="absolute inset-0 opacity-20">
|
<div className="absolute inset-0 opacity-20">
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import UmamiScript from '@/components/analytics/UmamiScript';
|
|||||||
import AnalyticsProvider from '@/components/analytics/AnalyticsProvider';
|
import AnalyticsProvider from '@/components/analytics/AnalyticsProvider';
|
||||||
import { Metadata, Viewport } from 'next';
|
import { Metadata, Viewport } from 'next';
|
||||||
import JsonLd from '@/components/JsonLd';
|
import JsonLd from '@/components/JsonLd';
|
||||||
|
import { getOrganizationSchema, SITE_URL } from '@/lib/schema';
|
||||||
|
|
||||||
export async function generateMetadata({params: {locale}}: {params: {locale: string}}): Promise<Metadata> {
|
export async function generateMetadata({params: {locale}}: {params: {locale: string}}): Promise<Metadata> {
|
||||||
const t = await getTranslations({locale, namespace: 'Index.meta'});
|
const t = await getTranslations({locale, namespace: 'Index.meta'});
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import Hero from '@/components/home/Hero';
|
import Hero from '@/components/home/Hero';
|
||||||
import JsonLd from '@/components/JsonLd';
|
import JsonLd from '@/components/JsonLd';
|
||||||
|
import { getBreadcrumbSchema } from '@/lib/schema';
|
||||||
import ProductCategories from '@/components/home/ProductCategories';
|
import ProductCategories from '@/components/home/ProductCategories';
|
||||||
import WhatWeDo from '@/components/home/WhatWeDo';
|
import WhatWeDo from '@/components/home/WhatWeDo';
|
||||||
import RecentPosts from '@/components/home/RecentPosts';
|
import RecentPosts from '@/components/home/RecentPosts';
|
||||||
@@ -16,18 +17,9 @@ export default function HomePage({ params: { locale } }: { params: { locale: str
|
|||||||
<div className="flex flex-col min-h-screen">
|
<div className="flex flex-col min-h-screen">
|
||||||
<JsonLd
|
<JsonLd
|
||||||
id="breadcrumb-home"
|
id="breadcrumb-home"
|
||||||
data={{
|
data={getBreadcrumbSchema([
|
||||||
'@context': 'https://schema.org',
|
{ name: 'Home', item: `/${locale}` },
|
||||||
'@type': 'BreadcrumbList',
|
])}
|
||||||
itemListElement: [
|
|
||||||
{
|
|
||||||
'@type': 'ListItem',
|
|
||||||
position: 1,
|
|
||||||
name: 'Home',
|
|
||||||
item: `https://klz-cables.com/${locale}`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<Hero />
|
<Hero />
|
||||||
<Reveal><ProductCategories /></Reveal>
|
<Reveal><ProductCategories /></Reveal>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import Script from 'next/script';
|
import Script from 'next/script';
|
||||||
import JsonLd from '@/components/JsonLd';
|
import JsonLd from '@/components/JsonLd';
|
||||||
|
import { getBreadcrumbSchema, SITE_URL } from '@/lib/schema';
|
||||||
import ProductSidebar from '@/components/ProductSidebar';
|
import ProductSidebar from '@/components/ProductSidebar';
|
||||||
import ProductTabs from '@/components/ProductTabs';
|
import ProductTabs from '@/components/ProductTabs';
|
||||||
import ProductTechnicalData from '@/components/ProductTechnicalData';
|
import ProductTechnicalData from '@/components/ProductTechnicalData';
|
||||||
@@ -229,6 +230,18 @@ export default async function ProductPage({ params }: ProductPageProps) {
|
|||||||
notFound();
|
notFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extract technical data for schema
|
||||||
|
const technicalDataMatch = product.content.match(/technicalData=\{<ProductTechnicalData data=\{(.*?)\}\s*\/>\}/s);
|
||||||
|
let technicalItems = [];
|
||||||
|
if (technicalDataMatch) {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(technicalDataMatch[1]);
|
||||||
|
technicalItems = data.technicalItems || [];
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to parse technical data for schema', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const datasheetPath = getDatasheetPath(productSlug, locale);
|
const datasheetPath = getDatasheetPath(productSlug, locale);
|
||||||
const isFallback = (product.frontmatter as any).isFallback;
|
const isFallback = (product.frontmatter as any).isFallback;
|
||||||
const categorySlug = slug[0];
|
const categorySlug = slug[0];
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useTranslations } from 'next-intl';
|
|||||||
import { getTranslations } from 'next-intl/server';
|
import { getTranslations } from 'next-intl/server';
|
||||||
import { Metadata } from 'next';
|
import { Metadata } from 'next';
|
||||||
import JsonLd from '@/components/JsonLd';
|
import JsonLd from '@/components/JsonLd';
|
||||||
|
import { getBreadcrumbSchema, SITE_URL } from '@/lib/schema';
|
||||||
import { Section, Container, Heading, Badge, Button } from '@/components/ui';
|
import { Section, Container, Heading, Badge, Button } from '@/components/ui';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import Reveal from '@/components/Reveal';
|
import Reveal from '@/components/Reveal';
|
||||||
@@ -43,6 +44,46 @@ export default function TeamPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col min-h-screen bg-neutral-light">
|
<div className="flex flex-col min-h-screen bg-neutral-light">
|
||||||
|
<JsonLd
|
||||||
|
id="breadcrumb-team"
|
||||||
|
data={getBreadcrumbSchema([
|
||||||
|
{ name: t('hero.subtitle'), item: `/team` },
|
||||||
|
])}
|
||||||
|
/>
|
||||||
|
<JsonLd
|
||||||
|
id="person-michael"
|
||||||
|
data={{
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'Person',
|
||||||
|
name: t('michael.name'),
|
||||||
|
jobTitle: t('michael.role'),
|
||||||
|
worksFor: {
|
||||||
|
'@type': 'Organization',
|
||||||
|
name: 'KLZ Cables',
|
||||||
|
},
|
||||||
|
sameAs: [
|
||||||
|
'https://www.linkedin.com/in/michael-bodemer-33b493122/'
|
||||||
|
],
|
||||||
|
image: `${SITE_URL}/uploads/2024/12/DSC07768-Large.webp`
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<JsonLd
|
||||||
|
id="person-klaus"
|
||||||
|
data={{
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'Person',
|
||||||
|
name: t('klaus.name'),
|
||||||
|
jobTitle: t('klaus.role'),
|
||||||
|
worksFor: {
|
||||||
|
'@type': 'Organization',
|
||||||
|
name: 'KLZ Cables',
|
||||||
|
},
|
||||||
|
sameAs: [
|
||||||
|
'https://www.linkedin.com/in/klaus-mintel-b80a8b193/'
|
||||||
|
],
|
||||||
|
image: `${SITE_URL}/uploads/2024/12/DSC07963-Large.webp`
|
||||||
|
}}
|
||||||
|
/>
|
||||||
{/* Hero Section */}
|
{/* Hero Section */}
|
||||||
<section className="relative flex items-center justify-center overflow-hidden bg-primary-dark pt-32 pb-24 md:pt-[14%] md:pb-[12%]">
|
<section className="relative flex items-center justify-center overflow-hidden bg-primary-dark pt-32 pb-24 md:pt-[14%] md:pb-[12%]">
|
||||||
<div className="absolute inset-0 z-0">
|
<div className="absolute inset-0 z-0">
|
||||||
|
|||||||
16
components/JsonLd.tsx
Normal file
16
components/JsonLd.tsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import Script from 'next/script';
|
||||||
|
|
||||||
|
interface JsonLdProps {
|
||||||
|
id?: string;
|
||||||
|
data: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function JsonLd({ id, data }: JsonLdProps) {
|
||||||
|
return (
|
||||||
|
<Script
|
||||||
|
id={id || `jsonld-${Math.random().toString(36).substr(2, 9)}`}
|
||||||
|
type="application/ld+json"
|
||||||
|
dangerouslySetInnerHTML={{ __html: JSON.stringify(data) }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
33
lib/schema.ts
Normal file
33
lib/schema.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { getTranslations } from 'next-intl/server';
|
||||||
|
|
||||||
|
export const SITE_URL = 'https://klz-cables.com';
|
||||||
|
export const LOGO_URL = `${SITE_URL}/logo.png`;
|
||||||
|
|
||||||
|
export const getOrganizationSchema = () => ({
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'Organization',
|
||||||
|
name: 'KLZ Cables',
|
||||||
|
url: SITE_URL,
|
||||||
|
logo: LOGO_URL,
|
||||||
|
sameAs: [
|
||||||
|
'https://www.linkedin.com/company/klz-cables',
|
||||||
|
],
|
||||||
|
contactPoint: {
|
||||||
|
'@type': 'ContactPoint',
|
||||||
|
telephone: '+49-881-92537298',
|
||||||
|
contactType: 'customer service',
|
||||||
|
email: 'info@klz-vertriebs-gmbh.com',
|
||||||
|
availableLanguage: ['German', 'English']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getBreadcrumbSchema = (items: { name: string; item: string }[]) => ({
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'BreadcrumbList',
|
||||||
|
itemListElement: items.map((item, index) => ({
|
||||||
|
'@type': 'ListItem',
|
||||||
|
position: index + 1,
|
||||||
|
name: item.name,
|
||||||
|
item: item.item.startsWith('http') ? item.item : `${SITE_URL}${item.item}`,
|
||||||
|
})),
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user