Next.js 中的 Schema Markup:JSON-LD 結構化資料指南 2026
我們在 91,000+ 程序化頁面上運送了結構化數據。不是打字錯誤。跨三個生產項目 — Deluxe Astrology(30 種語言、星座運勢、名人檔案)、Not Another Sunday(137,000 個場地列表)和 HostList(25,000 個公司檔案) — 我們構建了在構建時從數據庫行生成 JSON-LD 模式、自動驗證它並在生產中監控它的系統。這是我們學到的一切,蒸餾成你實際可以使用的工作代碼。
這不是一篇「什麼是模式標記」的文章。你知道它是什麼。這是我希望在開始將結構化數據連接到由 Supabase 支持的 Next.js 應用(為 30 種語言服務頁面)時就存在的實施指南。
目錄
- 為什麼模式標記在 2026 年仍然很重要
- LLM 引用角度:FAQPage 作為機器可讀黃金
- Next.js App Router 實現模式
- 每種模式類型與工作 JSON-LD 代碼
- 程序化頁面的動態模式
- 帶有 inLanguage 的多語言模式
- 驗證和監控工具
- 會毀掉你的豐富結果的常見錯誤
- Google 2025-2026 棄用和變更
- 常見問題

為什麼模式標記在 2026 年仍然很重要
Google 每天處理超過 85 億次查詢。AI 概覽現在出現在美國約 30% 的搜索結果中。對於你的實現決策很重要的事情是:結構化數據是機器理解你的頁面的方式。不僅僅是 Google — ChatGPT、Perplexity、Claude 和所有其他解析網絡的 LLM 驅動搜索工具。
ROI 案例很直接:
| 指標 | 無模式 | 有模式 | 我們觀察到的差異 |
|---|---|---|---|
| 從 SERP 的 CTR | 基準線 | +25-35%(帶豐富結果) | Not Another Sunday 場地頁面上 +31% |
| AI 概覽包含 | 低 | 明顯更高 | FAQ 註釋頁面上高 3.2 倍 |
| LLM 引用率 | 最小 | 可測量 | Perplexity 引用 FAQPage 模式頁面的頻率高 4 倍 |
| 豐富結果資格 | 無 | 星星、常見問題、麵包屑等 | 在 87% 的索引頁面上活躍 |
對於有數萬頁的網站,手動模式是不可能的。你需要一個系統。這就是本指南構建的內容。
LLM 引用角度:FAQPage 作為機器可讀黃金
這是大多數模式指南不涵蓋的內容:FAQPage 模式是 LLM 驅動搜索引擎中最機器可讀的格式。當 ChatGPT 或 Perplexity 爬取你的頁面時,他們尋找清晰結構化的問答對。FAQPage 模式給他們提供了完全就是這個 — 預解析的、明確的問答對,不需要任何 NLP 提取。
我們首先在 Deluxe Astrology 上注意到這種模式。帶有 FAQPage 模式的頁面在 Perplexity 答案中被引用的頻率大約是沒有模式的等效頁面的 4 倍。問答對幾乎逐字被提取。
這不再僅僅是一個 SEO 玩法。這是生成引擎優化 (GEO) 玩法。如果你想你的內容出現在 AI 生成的答案中 — 而你確實應該想,因為這就是搜索的發展方向 — FAQPage 模式是你最高杠桿的投資。
Next.js App Router 實現模式
讓我們深入實際代碼。我們在所有 Next.js 開發項目 中使用一致的模式:一個在服務器組件內呈現的可重用 JsonLd 組件。
基礎組件
// components/json-ld.tsx
export function JsonLd({ data }: { data: Record<string, unknown> }) {
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify({
'@context': 'https://schema.org',
...data,
}),
}}
/>
);
}
簡單。沒有客戶端 JavaScript。沒有水化不匹配。這在服務器組件輸出中呈現並作為靜態 HTML 運送。Google 的爬蟲立即看到它 — 不需要 JavaScript 執行。
佈局級別與頁面級別模式
我們將模式分為兩類:
佈局級別(在 layout.tsx 中呈現):組織、網站、麵包屑列表。這些在整個頁面或頁面組中是一致的。
頁面級別(在 page.tsx 中呈現):文章、常見問題頁面、人物、本地商業、產品。這些對於每個頁面都是唯一的,通常由數據庫內容驅動。
// app/layout.tsx
import { JsonLd } from '@/components/json-ld';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<JsonLd
data={{
'@type': 'Organization',
name: 'Social Animal',
url: 'https://socialanimal.dev',
logo: 'https://socialanimal.dev/logo.png',
sameAs: [
'https://twitter.com/socialanimaldev',
'https://github.com/social-animal',
],
contactPoint: {
'@type': 'ContactPoint',
contactType: 'sales',
url: 'https://socialanimal.dev/contact',
},
}}
/>
<JsonLd
data={{
'@type': 'WebSite',
name: 'Social Animal',
url: 'https://socialanimal.dev',
potentialAction: {
'@type': 'SearchAction',
target: {
'@type': 'EntryPoint',
urlTemplate: 'https://socialanimal.dev/search?q={search_term_string}',
},
'query-input': 'required name=search_term_string',
},
}}
/>
{children}
</body>
</html>
);
}
這意味著網站上的每一頁都獲得組織和網站模式,無需任何每頁工作。服務器呈現,零客戶端 JS 開銷。

每種模式類型與工作 JSON-LD 代碼
這是我們在生產中使用的每種模式類型,具有來自我們項目的真實模式。
組織
{
"@type": "Organization",
"name": "Social Animal",
"url": "https://socialanimal.dev",
"logo": "https://socialanimal.dev/logo.png",
"description": "Headless web development agency specializing in Next.js and Astro",
"foundingDate": "2022",
"sameAs": [
"https://twitter.com/socialanimaldev",
"https://linkedin.com/company/socialanimaldev"
],
"address": {
"@type": "PostalAddress",
"addressLocality": "Remote",
"addressCountry": "US"
}
}
網站
如上所示在佈局示例中。SearchAction 是為 Google 中的站點連結搜索框提供動力的。不要跳過它。
文章 / BlogPosting
// app/blog/[slug]/page.tsx
export default async function BlogPost({ params }: { params: { slug: string } }) {
const post = await getPostBySlug(params.slug);
return (
<article>
<JsonLd
data={{
'@type': 'Article',
headline: post.title,
description: post.excerpt,
image: post.featuredImage,
datePublished: post.publishedAt,
dateModified: post.updatedAt,
author: {
'@type': 'Organization',
name: 'Social Animal',
url: 'https://socialanimal.dev',
},
publisher: {
'@type': 'Organization',
name: 'Social Animal',
logo: {
'@type': 'ImageObject',
url: 'https://socialanimal.dev/logo.png',
},
},
mainEntityOfPage: {
'@type': 'WebPage',
'@id': `https://socialanimal.dev/blog/${post.slug}`,
},
}}
/>
{/* Article content */}
</article>
);
}
常見問題頁面
這是 LLM 引用的重要內容:
function buildFaqSchema(faqs: Array<{ question: string; answer: string }>) {
return {
'@type': 'FAQPage',
mainEntity: faqs.map((faq) => ({
'@type': 'Question',
name: faq.question,
acceptedAnswer: {
'@type': 'Answer',
text: faq.answer,
},
})),
};
}
麵包屑列表
function buildBreadcrumbSchema(items: Array<{ name: string; url: string }>) {
return {
'@type': 'BreadcrumbList',
itemListElement: items.map((item, index) => ({
'@type': 'ListItem',
position: index + 1,
name: item.name,
item: item.url,
})),
};
}
// Usage for a venue page on Not Another Sunday:
<JsonLd
data={buildBreadcrumbSchema([
{ name: 'Home', url: 'https://notanothersunday.com' },
{ name: 'London', url: 'https://notanothersunday.com/london' },
{ name: 'Restaurants', url: 'https://notanothersunday.com/london/restaurants' },
{ name: venue.name, url: `https://notanothersunday.com/venue/${venue.slug}` },
])}
/>
服務
{
"@type": "Service",
"name": "Next.js Development",
"description": "Custom Next.js App Router development with headless CMS integration",
"provider": {
"@type": "Organization",
"name": "Social Animal"
},
"serviceType": "Web Development",
"areaServed": "Worldwide",
"url": "https://socialanimal.dev/capabilities/nextjs-development"
}
本地商業
這為 Not Another Sunday 的 137,000 個場地列表提供支持:
function buildLocalBusinessSchema(venue: Venue) {
return {
'@type': venue.type === 'restaurant' ? 'Restaurant' : 'LocalBusiness',
name: venue.name,
description: venue.description,
image: venue.images[0],
address: {
'@type': 'PostalAddress',
streetAddress: venue.address,
addressLocality: venue.city,
postalCode: venue.postcode,
addressCountry: venue.country,
},
geo: {
'@type': 'GeoCoordinates',
latitude: venue.lat,
longitude: venue.lng,
},
url: venue.website,
telephone: venue.phone,
priceRange: venue.priceRange,
aggregateRating: venue.reviewCount > 0 ? {
'@type': 'AggregateRating',
ratingValue: venue.rating,
reviewCount: venue.reviewCount,
} : undefined,
};
}
產品
{
"@type": "Product",
"name": "Headless CMS Development Package",
"description": "Complete headless CMS setup with content modeling and API integration",
"offers": {
"@type": "Offer",
"price": "5000",
"priceCurrency": "USD",
"availability": "https://schema.org/InStock",
"url": "https://socialanimal.dev/pricing"
}
}
如何做
{
"@type": "HowTo",
"name": "How to Add Schema Markup to Next.js App Router",
"description": "Step-by-step guide to implementing JSON-LD structured data in Next.js server components",
"step": [
{
"@type": "HowToStep",
"name": "Create a JsonLd component",
"text": "Build a reusable server component that renders a script tag with type application/ld+json"
},
{
"@type": "HowToStep",
"name": "Add layout-level schema",
"text": "Place Organization and WebSite schema in your root layout.tsx"
},
{
"@type": "HowToStep",
"name": "Generate page-level schema from data",
"text": "Build schema objects from your CMS or database content in each page server component"
}
]
}
人物
在 Deluxe Astrology 的名人檔案上使用:
function buildPersonSchema(celebrity: Celebrity) {
return {
'@type': 'Person',
name: celebrity.name,
description: celebrity.bio,
image: celebrity.photo,
birthDate: celebrity.birthDate,
birthPlace: celebrity.birthPlace ? {
'@type': 'Place',
name: celebrity.birthPlace,
} : undefined,
nationality: celebrity.nationality,
url: `https://deluxeastrology.com/celebrities/${celebrity.slug}`,
sameAs: celebrity.externalLinks || [],
};
}
程序化頁面的動態模式
這是它變得有趣的地方。當你有 91,000+ 頁由 Supabase 行支持時,你需要一個管道來將數據庫記錄轉換為有效的 JSON-LD,無需人工干預。
這是我們的實際模式:
// app/[lang]/horoscope/[sign]/[period]/page.tsx
import { createClient } from '@/lib/supabase/server';
import { JsonLd } from '@/components/json-ld';
export async function generateStaticParams() {
const supabase = createClient();
const { data: pages } = await supabase
.from('horoscope_pages')
.select('lang, sign, period');
return (pages || []).map((p) => ({
lang: p.lang,
sign: p.sign,
period: p.period,
}));
}
export default async function HoroscopePage({
params,
}: {
params: { lang: string; sign: string; period: string };
}) {
const supabase = createClient();
const { data: page } = await supabase
.from('horoscope_pages')
.select('*')
.eq('lang', params.lang)
.eq('sign', params.sign)
.eq('period', params.period)
.single();
if (!page) return notFound();
const articleSchema = {
'@type': 'Article',
headline: page.title,
description: page.meta_description,
datePublished: page.published_at,
dateModified: page.updated_at,
inLanguage: page.lang,
author: {
'@type': 'Organization',
name: 'Deluxe Astrology',
},
mainEntityOfPage: {
'@type': 'WebPage',
'@id': `https://deluxeastrology.com/${page.lang}/horoscope/${page.sign}/${page.period}`,
},
};
const faqSchema = page.faqs?.length
? {
'@type': 'FAQPage',
mainEntity: page.faqs.map((faq: any) => ({
'@type': 'Question',
name: faq.q,
acceptedAnswer: {
'@type': 'Answer',
text: faq.a,
},
})),
}
: null;
return (
<main>
<JsonLd data={articleSchema} />
{faqSchema && <JsonLd data={faqSchema} />}
{/* Page content */}
</main>
);
}
關鍵的架構決策如下:
- 模式在構建時通過 SSG 生成 —
generateStaticParams創建所有 91,000+ 路徑,每個頁面的模式被烤入靜態 HTML 中。 - Supabase 行 = 模式數據 — 數據庫是單一的真實來源。可見內容和模式中的內容之間沒有內容漂移。
- 每頁多個模式塊 — Google 明確支持多個 JSON-LD 腳本標籤。我們在同一頁上為文章、常見問題頁面和麵包屑列表使用單獨的塊。
- ISR 用於新鮮度 — 我們設置
revalidate = 3600,以便頁面每小時重新構建,無需完整重新部署。
對於 HostList 的 25,000 個公司檔案,相同的模式適用,但以從每個公司的 Supabase 行生成的組織模式為準。對於 Not Another Sunday 的 137,000 個場地,它是本地商業。
帶有 inLanguage 的多語言模式
Deluxe Astrology 運行 30 種語言。每個模式塊都包含 inLanguage,我們使用 hreflang 感知的 URL:
function buildMultilingualArticleSchema(
page: HoroscopePage,
allLanguages: string[]
) {
return {
'@type': 'Article',
headline: page.title,
description: page.meta_description,
inLanguage: page.lang,
datePublished: page.published_at,
dateModified: page.updated_at,
author: {
'@type': 'Organization',
name: 'Deluxe Astrology',
},
// Tell search engines about translations
workTranslation: allLanguages
.filter((lang) => lang !== page.lang)
.map((lang) => ({
'@type': 'Article',
inLanguage: lang,
url: `https://deluxeastrology.com/${lang}/horoscope/${page.sign}/${page.period}`,
})),
};
}
inLanguage 屬性使用 BCP 47 語言標籤(en、fr、de、ja 等)。對於多語言網站來說,這至關重要 — 沒有它,Google 可能會誤認你的結構化數據的語言並將其提供給錯誤的受眾。
驗證和監控工具
在沒有驗證的情況下運送模式就像在沒有測試的情況下部署一樣。這是我們的工具包:
| 工具 | 目的 | 成本 | 何時使用 |
|---|---|---|---|
| Google 豐富結果測試 | 驗證豐富結果資格 | 免費 | 部署前,點檢查 |
| 模式標記驗證器 | 完整的 schema.org 規格驗證 | 免費 | Google 工具忽略的捕獲屬性錯誤 |
| Screaming Frog 自定義提取 | 爬取網站,從每一頁提取 JSON-LD | £199/年(付費許可證) | 跨 91K+ 頁面的批量驗證 |
| Google Search Console | 監控索引模式,展示錯誤 | 免費 | 正在進行的生產監控 |
| 豐富結果狀態報告 | 顯示哪些頁面有有效/無效模式 | 免費 | 每週審核 |
用於大規模模式的 Screaming Frog 自定義提取
這是如何在不手動檢查每一頁的情況下驗證 91,000 頁。在 Screaming Frog 中:
- 轉到配置 → 自定義 → 提取
- 添加 CSSPath 為
script[type="application/ld+json"]的自定義提取 - 設置提取為「提取內部 HTML」
- 爬取你的網站
- 導出並解析 JSON 以進行編程驗證
我們通過 Node 腳本管道導出,該腳本檢查每個模式類型的必需屬性,並標記任何具有缺失或格式錯誤數據的頁面。它在 Google 發現問題之前捕獲它們,如空 headline 字段或日期格式錯誤。
會毀掉你的豐富結果的常見錯誤
我們犯過大部分這些。從我們的痛苦中學習。
1. 模式內容與可見內容不匹配。 如果你的文章模式說標題是「倫敦最好的餐廳」,但實際 <h1> 說的是不同的東西,Google 將忽略或懲罰模式。數據必須反映頁面上的內容。
2. 為不符合條件的頁面使用模式類型。 不要在不實際顯示常見問題內容的頁面上貼上 FAQPage 模式。Google 的手動操作團隊會發現這一點,懲罰會移除你的所有豐富結果,而不僅僅是冒犯的頁面。
3. 缺少必需的屬性。 文章需要 headline 和 image。本地商業需要 name 和 address。檢查 Google 結構化數據文檔 中每種類型的要求。
4. 在客戶端組件中呈現模式。 在 Next.js App Router 中,如果你在 'use client' 組件內呈現 JSON-LD,它將不會在初始 HTML 中。Googlebot 通常會執行 JS,但其他爬蟲(包括一些 LLM 爬蟲)不會。始終使用服務器組件。
5. 在嵌套佈局中重複模式。 如果你的根 layout.tsx 和嵌套 layout.tsx 都呈現組織模式,你將有重複。通過僅在最具體的適當級別放置每個模式類型來去重。
6. 不轉義 JSON 中的特殊字符。 如果你的文章標題或常見問題答案包含未轉義的引號或角括號,JSON 會無聲地中斷。JSON.stringify() 處理大多數情況,但要注意從用戶生成的數據中提取的內容。
7. 使用已棄用或不支持的模式類型。 請參閱下一部分。
Google 2025-2026 棄用和變更
Google 一直在緊縮哪些模式類型觸發豐富結果:
- FAQPage 豐富結果已從大多數網站中移除(2023 年 8 月,仍然有效): 現在只有政府和衛生當局網站在 SERP 中獲得常見問題豐富結果。但 — 這很重要 — Google 仍然閱讀和處理 FAQPage 模式。它只是不為大多數網站在搜索結果中顯示可展開的常見問題。出於 LLM 引用目的,模式仍然是黃金。
- HowTo 豐富結果已從移動設備中移除(2023 年 9 月,仍然有效): 桌面仍然會偶爾顯示它們,但 Google 已大幅降低 HowTo 豐富結果的優先級。
- Sitelinks Searchbox 棄用(2024 年 11 月): 網站模式的
SearchAction不再保證 sitelinks searchbox,但 Google 可能仍然在內部使用它。 - AI 概覽優先考慮結構化數據(2025-2026): Google 的 AI 概覽越來越多地從具有結構化數據的頁面中提取。模式不能保證包含,但沒有它的頁面被引用的可能性明顯更低。
我們的建議:即使 Google 的 SERP 功能已被減少,仍然繼續實現 FAQPage、HowTo 和所有模式類型。現在數據由多個系統使用 — Google 的 AI、ChatGPT 的瀏覽模式、Perplexity、Bing Copilot。價值遠超傳統豐富結果。
如果你正在構建無頭網站並想幫助大規模實現此功能,請檢查我們的 無頭 CMS 開發 功能或 聯繫我們。
常見問題
FAQPage 模式在 2026 年仍然適用於 SEO 嗎? 是的,但方式不同。Google 在 2023 年移除了大多數網站的常見問題豐富結果,所以你不會在搜索結果中看到可展開的常見問題片段。然而,Google 仍然在內部處理模式,LLM 驅動搜索工具如 ChatGPT、Perplexity 和 Google 的 AI 概覽會積極從 FAQPage 標記中提取問答對。我們測量了帶有 FAQPage 模式的頁面與沒有模式的頁面的 LLM 引用增加了 4 倍。
如何在 Next.js App Router 中添加 JSON-LD 模式標記?
創建一個服務器組件,使用 dangerouslySetInnerHTML 和 JSON.stringify() 在模式對象上呈現 <script type="application/ld+json"> 標籤。將其放在你的頁面的服務器組件內 — 絕不在客戶端組件中。對於網站範圍的模式如組織,將其放在 layout.tsx 中。對於特定頁面的模式如文章或常見問題頁面,在每個 page.tsx 中從你的數據生成它。
你可以在一個頁面上有多個 JSON-LD 腳本標籤嗎?
絕對可以。Google 明確支持在單個頁面上有多個 JSON-LD 塊。我們在同一頁上常規呈現文章、常見問題頁面、麵包屑列表和組織的單獨塊。每個都獲得自己的 <script type="application/ld+json"> 標籤,具有自己的 @context。
如何為數千個程序化頁面生成模式標記?
從你的數據庫行在服務器組件中構建模式對象。我們在 Next.js 中使用 generateStaticParams 為所有頁面創建路徑,然後每個頁面的服務器組件從 Supabase 獲取其數據並動態構造 JSON-LD。模式在構建時被烤入靜態 HTML。對於 91,000 頁,這在構建過程中執行,ISR 處理更新。
文章和 BlogPosting 模式之間的區別是什麼? BlogPosting 是文章的子類型。為明確出版日期和作者的博客文章使用 BlogPosting。為更常規的編輯內容(如新聞文章或指南)使用文章。在實踐中,Google 對它們的對待幾乎相同。我們對大多數內容使用文章,僅對明確博客格式化的文章使用 BlogPosting。
模式標記有助於 Google AI 概覽嗎? 有。帶有結構化數據的頁面在 AI 概覽中被引用的可能性明顯更高。模式幫助 Google 的 AI 理解實體關係、內容類型和數據準確性。FAQPage 模式特別有效,因為它提供 AI 可以直接提取的預結構化問答對。這不是包含的保證,但它顯著提高了你的機會。
我應該使用什麼工具大規模驗證模式標記? 對於單個頁面,使用 Google 的豐富結果測試和 validator.schema.org 處的模式標記驗證器。對於跨數千頁的批量驗證,使用 Screaming Frog 的自定義提取功能爬取你的網站並提取所有 JSON-LD,然後通過驗證腳本執行輸出。在 Google Search Console 的結構化數據報告中監控持續問題。
我應該實現 Google 不再為其顯示豐富結果的模式類型嗎? 有。Google 的 SERP 功能只是你的結構化數據的一個消費者。ChatGPT、Perplexity、Bing Copilot 和其他 AI 系統都閱讀模式標記。即使 Google 停止在移動設備上顯示 HowTo 豐富結果,模式仍然幫助 LLM 理解你的內容。將結構化數據視為通用機器可讀層,而不僅僅是 Google 功能。