seo-metadata
4
总安装量
2
周安装量
#49559
全站排名
安装命令
npx skills add https://github.com/canatufkansu/claude-skills --skill seo-metadata
Agent 安装分布
claude-code
2
mcpjam
1
kilo
1
junie
1
windsurf
1
zencoder
1
Skill 文档
SEO Metadata
Base Metadata Configuration
// app/layout.tsx
import type { Metadata } from 'next';
export const metadata: Metadata = {
metadataBase: new URL(process.env.NEXT_PUBLIC_SITE_URL!),
title: {
template: '%s | Studio Name',
default: 'Studio Name - Pilates & Yoga',
},
description: 'Professional Pilates and Yoga coaching for strength and calm.',
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
'max-video-preview': -1,
'max-image-preview': 'large',
'max-snippet': -1,
},
},
};
Per-Page Dynamic Metadata
// app/[locale]/services/page.tsx
import type { Metadata } from 'next';
import { getTranslations } from 'next-intl/server';
import { locales } from '@/i18n.config';
type Props = {
params: Promise<{ locale: string }>;
};
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { locale } = await params;
const t = await getTranslations({ locale, namespace: 'meta.services' });
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL;
return {
title: t('title'),
description: t('description'),
alternates: {
canonical: `${siteUrl}/${locale}/services`,
languages: Object.fromEntries(
locales.map((loc) => [loc, `${siteUrl}/${loc}/services`])
),
},
openGraph: {
title: t('title'),
description: t('description'),
url: `${siteUrl}/${locale}/services`,
siteName: 'Studio Name',
locale: locale.replace('-', '_'),
type: 'website',
images: [
{
url: `${siteUrl}/og/services.jpg`,
width: 1200,
height: 630,
alt: t('title'),
},
],
},
twitter: {
card: 'summary_large_image',
title: t('title'),
description: t('description'),
images: [`${siteUrl}/og/services.jpg`],
},
};
}
Metadata Helper Function
// lib/metadata.ts
import type { Metadata } from 'next';
import { locales, type Locale } from '@/i18n.config';
interface GenerateMetadataOptions {
locale: Locale;
path: string;
title: string;
description: string;
image?: string;
noIndex?: boolean;
}
export function generatePageMetadata({
locale,
path,
title,
description,
image = '/og/default.jpg',
noIndex = false,
}: GenerateMetadataOptions): Metadata {
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL!;
const fullUrl = `${siteUrl}/${locale}${path}`;
const imageUrl = image.startsWith('http') ? image : `${siteUrl}${image}`;
return {
title,
description,
robots: noIndex ? { index: false, follow: false } : undefined,
alternates: {
canonical: fullUrl,
languages: Object.fromEntries(
locales.map((loc) => [loc, `${siteUrl}/${loc}${path}`])
),
},
openGraph: {
title,
description,
url: fullUrl,
siteName: 'Studio Name',
locale: locale.replace('-', '_'),
type: 'website',
images: [{ url: imageUrl, width: 1200, height: 630, alt: title }],
},
twitter: {
card: 'summary_large_image',
title,
description,
images: [imageUrl],
},
};
}
Usage with Helper
// app/[locale]/about/page.tsx
import { generatePageMetadata } from '@/lib/metadata';
import { getTranslations } from 'next-intl/server';
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { locale } = await params;
const t = await getTranslations({ locale, namespace: 'meta.about' });
return generatePageMetadata({
locale: locale as Locale,
path: '/about',
title: t('title'),
description: t('description'),
image: '/og/about.jpg',
});
}
Dynamic Route Metadata
// app/[locale]/programmes/[slug]/page.tsx
import { getProgrammeBySlug } from '@/lib/data';
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { locale, slug } = await params;
const programme = await getProgrammeBySlug(locale as Locale, slug);
if (!programme) {
return { title: 'Not Found' };
}
return generatePageMetadata({
locale: locale as Locale,
path: `/programmes/${slug}`,
title: programme.title,
description: programme.outcomes.slice(0, 2).join('. '),
});
}
Hreflang in HTML Head
The metadata API handles hreflang automatically via alternates.languages. The rendered HTML will include:
<link rel="canonical" href="https://example.com/en/services" />
<link rel="alternate" hreflang="pt-PT" href="https://example.com/pt-PT/services" />
<link rel="alternate" hreflang="en" href="https://example.com/en/services" />
<link rel="alternate" hreflang="tr" href="https://example.com/tr/services" />
<link rel="alternate" hreflang="es" href="https://example.com/es/services" />
<link rel="alternate" hreflang="fr" href="https://example.com/fr/services" />
<link rel="alternate" hreflang="de" href="https://example.com/de/services" />
<link rel="alternate" hreflang="x-default" href="https://example.com/pt-PT/services" />
Translation Keys Structure
// messages/en.json
{
"meta": {
"home": {
"title": "Pilates & Yoga Coaching",
"description": "Transform your body with personalized training"
},
"services": {
"title": "Our Services",
"description": "1:1 sessions, group classes, and online coaching"
},
"about": {
"title": "About Us",
"description": "Meet your instructor and learn our approach"
}
}
}