seo-2025-patterns
3
总安装量
3
周安装量
#54997
全站排名
安装命令
npx skills add https://github.com/vanman2024/ai-dev-marketplace --skill seo-2025-patterns
Agent 安装分布
opencode
3
gemini-cli
3
claude-code
3
github-copilot
3
codex
3
amp
3
Skill 文档
SEO 2025 Patterns
Purpose: Implement 2025 SEO best practices for Next.js applications to maximize search visibility and organic traffic.
Activation Triggers:
- Optimizing pages for search engines
- Implementing metadata and Open Graph
- Adding Schema.org structured data
- Improving Core Web Vitals
- E-E-A-T signal implementation
- Sitemap and robots.txt setup
- Meta description optimization
Key Resources:
scripts/seo-audit.sh– Comprehensive SEO audit scriptscripts/validate-schema.sh– Validate JSON-LD structured datatemplates/metadata-patterns.tsx– Next.js Metadata API patternstemplates/schema-components.tsx– JSON-LD schema componentsexamples/complete-seo-setup.md– Full SEO implementation example
2025 SEO Landscape
Key Changes from 2024
- INP Replaces FID – Interaction to Next Paint is now a Core Web Vital
- AI Content Guidelines – Google rewards helpful AI content with human oversight
- E-E-A-T Enhanced – “Experience” added as first factor
- Passage Ranking – Google indexes specific passages
- Video SEO – Video snippets dominate SERPs
- Zero-Click Optimization – Featured snippets and AI Overviews
Core Web Vitals Targets (2025)
| Metric | Target | What It Measures |
|---|---|---|
| LCP | < 2.5s | Largest Contentful Paint |
| INP | < 200ms | Interaction to Next Paint |
| CLS | < 0.1 | Cumulative Layout Shift |
Next.js Metadata API
Basic Metadata Configuration
// app/layout.tsx
import type { Metadata } from 'next'
export const metadata: Metadata = {
metadataBase: new URL('https://example.com'),
title: {
default: 'Site Name - Main Tagline',
template: '%s | Site Name',
},
description: 'Your site description for search engines (150-160 characters)',
keywords: ['keyword1', 'keyword2', 'keyword3'],
authors: [{ name: 'Author Name', url: 'https://author.com' }],
creator: 'Creator Name',
publisher: 'Publisher Name',
formatDetection: {
email: false,
address: false,
telephone: false,
},
}
Open Graph Configuration
export const metadata: Metadata = {
openGraph: {
type: 'website',
locale: 'en_US',
url: 'https://example.com',
siteName: 'Site Name',
title: 'Page Title for Social Sharing',
description: 'Description for social media (150-200 chars)',
images: [
{
url: '/og-image.png',
width: 1200,
height: 630,
alt: 'OG Image Alt Text',
},
],
},
}
Twitter Card Configuration
export const metadata: Metadata = {
twitter: {
card: 'summary_large_image',
site: '@sitehandle',
creator: '@creatorhandle',
title: 'Title for Twitter',
description: 'Description for Twitter (150-200 chars)',
images: ['/twitter-image.png'],
},
}
Robots Configuration
export const metadata: Metadata = {
robots: {
index: true,
follow: true,
nocache: false,
googleBot: {
index: true,
follow: true,
'max-video-preview': -1,
'max-image-preview': 'large',
'max-snippet': -1,
},
},
}
Dynamic Metadata
// app/blog/[slug]/page.tsx
import type { Metadata, ResolvingMetadata } from 'next'
type Props = {
params: { slug: string }
}
export async function generateMetadata(
{ params }: Props,
parent: ResolvingMetadata
): Promise<Metadata> {
const post = await getPost(params.slug)
return {
title: post.title,
description: post.excerpt,
openGraph: {
title: post.title,
description: post.excerpt,
type: 'article',
publishedTime: post.publishedAt,
modifiedTime: post.updatedAt,
authors: [post.author.name],
images: [
{
url: post.coverImage,
width: 1200,
height: 630,
alt: post.title,
},
],
},
}
}
Dynamic Sitemap
// app/sitemap.ts
import { MetadataRoute } from 'next'
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const baseUrl = 'https://example.com'
// Static pages
const staticPages: MetadataRoute.Sitemap = [
{
url: baseUrl,
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 1,
},
{
url: `${baseUrl}/about`,
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.8,
},
{
url: `${baseUrl}/pricing`,
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.9,
},
]
// Dynamic pages from database
const posts = await getAllPosts()
const postPages: MetadataRoute.Sitemap = posts.map((post) => ({
url: `${baseUrl}/blog/${post.slug}`,
lastModified: new Date(post.updatedAt),
changeFrequency: 'weekly' as const,
priority: 0.6,
}))
return [...staticPages, ...postPages]
}
Robots.txt
// app/robots.ts
import { MetadataRoute } from 'next'
export default function robots(): MetadataRoute.Robots {
const baseUrl = 'https://example.com'
return {
rules: [
{
userAgent: '*',
allow: '/',
disallow: ['/api/', '/admin/', '/_next/', '/private/'],
},
{
userAgent: 'GPTBot',
disallow: '/', // Block AI training crawlers if desired
},
],
sitemap: `${baseUrl}/sitemap.xml`,
}
}
Schema.org Structured Data
Organization Schema
// components/seo/OrganizationSchema.tsx
export function OrganizationSchema() {
const schema = {
'@context': 'https://schema.org',
'@type': 'Organization',
name: 'Company Name',
url: 'https://example.com',
logo: 'https://example.com/logo.png',
sameAs: [
'https://twitter.com/company',
'https://linkedin.com/company/company',
'https://github.com/company',
],
contactPoint: {
'@type': 'ContactPoint',
telephone: '+1-555-555-5555',
contactType: 'customer service',
availableLanguage: ['English'],
},
}
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
)
}
Article Schema
// components/seo/ArticleSchema.tsx
interface ArticleSchemaProps {
title: string
description: string
image: string
author: { name: string; url: string }
publishedAt: string
updatedAt: string
url: string
}
export function ArticleSchema(props: ArticleSchemaProps) {
const schema = {
'@context': 'https://schema.org',
'@type': 'Article',
headline: props.title,
description: props.description,
image: props.image,
author: {
'@type': 'Person',
name: props.author.name,
url: props.author.url,
},
publisher: {
'@type': 'Organization',
name: 'Company Name',
logo: {
'@type': 'ImageObject',
url: 'https://example.com/logo.png',
},
},
datePublished: props.publishedAt,
dateModified: props.updatedAt,
mainEntityOfPage: {
'@type': 'WebPage',
'@id': props.url,
},
}
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
)
}
FAQ Schema
// components/seo/FAQSchema.tsx
interface FAQItem {
question: string
answer: string
}
export function FAQSchema({ items }: { items: FAQItem[] }) {
const schema = {
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: items.map((item) => ({
'@type': 'Question',
name: item.question,
acceptedAnswer: {
'@type': 'Answer',
text: item.answer,
},
})),
}
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
)
}
Breadcrumb Schema
// components/seo/BreadcrumbSchema.tsx
interface BreadcrumbItem {
name: string
url: string
}
export function BreadcrumbSchema({ items }: { items: BreadcrumbItem[] }) {
const schema = {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: items.map((item, index) => ({
'@type': 'ListItem',
position: index + 1,
name: item.name,
item: item.url,
})),
}
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
)
}
Core Web Vitals Optimization
LCP Optimization
// Prioritize above-fold images
import Image from 'next/image'
// Hero image with priority
<Image
src="/hero.jpg"
alt="Hero description"
width={1200}
height={600}
priority // Preloads image for LCP
sizes="(max-width: 768px) 100vw, 1200px"
/>
Font Optimization
// app/layout.tsx
import { Inter } from 'next/font/google'
const inter = Inter({
subsets: ['latin'],
display: 'swap', // Prevents CLS
preload: true,
variable: '--font-inter',
})
export default function RootLayout({ children }) {
return (
<html lang="en" className={inter.variable}>
<body>{children}</body>
</html>
)
}
Script Optimization
import Script from 'next/script'
// Defer non-critical scripts
<Script
src="https://analytics.example.com/script.js"
strategy="lazyOnload" // Load after page is interactive
/>
// Load immediately for critical scripts
<Script
src="https://critical.example.com/script.js"
strategy="afterInteractive"
/>
E-E-A-T Signals
Author Information
// components/AuthorBio.tsx
export function AuthorBio({ author }) {
return (
<div className="flex items-center gap-4 p-4 bg-muted rounded-lg">
<Image
src={author.avatar}
alt={author.name}
width={64}
height={64}
className="rounded-full"
/>
<div>
<h3 className="font-semibold">{author.name}</h3>
<p className="text-sm text-muted-foreground">{author.title}</p>
<p className="text-sm">{author.bio}</p>
<div className="flex gap-2 mt-2">
<a href={author.twitter}>Twitter</a>
<a href={author.linkedin}>LinkedIn</a>
</div>
</div>
</div>
)
}
Trust Signals
- Clear contact information
- Privacy policy and terms of service
- About page with company information
- Author pages with credentials
- Published and updated dates
- HTTPS everywhere
SEO Audit Checklist
# Run comprehensive SEO audit
./scripts/seo-audit.sh
# Checks:
# â All pages have unique titles
# â All pages have meta descriptions
# â Open Graph tags present
# â Twitter cards configured
# â Sitemap.xml exists and valid
# â Robots.txt configured
# â Schema markup valid
# â Images have alt text
# â Heading hierarchy correct
# â Internal linking structure
Testing Tools
- Google Search Console – Monitor indexing and search performance
- PageSpeed Insights – Core Web Vitals measurement
- Rich Results Test – Validate structured data
- Mobile-Friendly Test – Mobile compatibility
- Schema.org Validator – Validate JSON-LD