Le Duy Khuong

Chuỗi: seo-json-ld · Phần 3

Năng suất & công cụ dev

Multi-Schema Strategy

WebSite, Person, BreadcrumbList

2026-03-206 phút đọcVI

Định dạng Case Study

This post follows the Problem → Approach → Result → Lessons structure.

Multi-Schema Strategy

Mở đầu

Một page trên web không chỉ chứa một loại entity. Blog post page của leduykhuong.com vừa là BlogPosting (bài viết), vừa có BreadcrumbList (navigation path). Homepage vừa là WebSite, vừa có thông tin về Person (tác giả). Mỗi page cần một chiến lược kết hợp nhiều schemas để Google hiểu đầy đủ context.

Mục tiêu: Hiểu cách leduykhuong.com dùng nhiều schema types trên từng loại page, cách tổ chức schema per-page, và khi nào nên thêm schema mới.


Schema Map — Toàn bộ site

leduykhuong.com có 4 schema types, phân bổ theo page:

PageSchemasHelper functions
HomepageWebSite + SearchActiongetWebSiteJsonLd()
AboutPersongetPersonJsonLd()
Blog postBlogPosting + BreadcrumbListgetBlogPostJsonLd() + getBreadcrumbJsonLd()
Blog landing(chưa có)
Topic/Pillar(chưa có)

Tổng cộng: 4 helper functions trong lib/seo.ts, mỗi function return một JSON-LD object.

Loading diagram...

Schema Types

4

WebSite, Person, BlogPosting, BreadcrumbList

Helper Functions

4

In lib/seo.ts

Page Types

5

Homepage, About, Blog Post, Landing, Topic


WebSite Schema — Homepage

// lib/seo.ts
export function getWebSiteJsonLd() {
  return {
    "@context": "https://schema.org",
    "@type": "WebSite",
    name: SITE_CONFIG.siteName,
    url: SITE_CONFIG.baseUrl,
    description: SITE_CONFIG.description,
    potentialAction: {
      "@type": "SearchAction",
      target: {
        "@type": "EntryPoint",
        urlTemplate: `${SITE_CONFIG.baseUrl}/blog/search?q={search_term_string}`,
      },
      "query-input": "required name=search_term_string",
    },
  };
}

Phân tích:

  • @type: "WebSite" — Nói Google: "Đây là trang chủ của website."
  • name + url — Thông tin cơ bản, Google dùng cho Knowledge Panel.
  • potentialAction: SearchAction — Tính năng đặc biệt: nói Google rằng site có search. Google CÓ THỂ hiển thị Sitelinks Searchbox — ô tìm kiếm trực tiếp trên search results.

Khi Google hiển thị Sitelinks Searchbox:

Le Duy Khuong — leduykhuong.com
Engineering Leader × AI/Agentic Systems Builder
┌─────────────────────────────────┐
│ Search leduykhuong.com          │
└─────────────────────────────────┘

User có thể search trực tiếp từ Google results mà không cần vào site trước. urlTemplate chỉ định URL pattern: khi user search "agentic", Google redirect tới leduykhuong.com/blog/search?q=agentic.

Yêu cầu: Site phải có search functionality thực sự tại URL pattern khai báo. leduykhuong.com có Pagefind search tại /blog/search.


Person Schema — About Page

// lib/seo.ts
export function getPersonJsonLd() {
  return {
    "@context": "https://schema.org",
    "@type": "Person",
    name: SITE_CONFIG.author.name,
    jobTitle: SITE_CONFIG.author.jobTitle,
    url: SITE_CONFIG.author.url,
    sameAs: [SITE_CONFIG.author.linkedin, SITE_CONFIG.author.github],
  };
}

Phân tích:

  • jobTitle — "Head of Digital & AI Transformation". Google dùng cho Knowledge Panel.
  • sameAs — Array URLs profile trên các platform khác (LinkedIn, GitHub). Google dùng để connect entities: "Le Duy Khuong trên leduykhuong.com = Le Duy Khuong trên LinkedIn." Điều này strengthen author authority.

sameAs best practices:

  • Chỉ khai báo profiles anh thực sự sở hữu
  • LinkedIn profile nên public
  • Thứ tự không quan trọng
  • Có thể thêm: Twitter/X, Google Scholar, Orcid, Medium...

// lib/seo.ts
export function getBreadcrumbJsonLd(
  items: { name: string; url: string }[]
) {
  return {
    "@context": "https://schema.org",
    "@type": "BreadcrumbList",
    itemListElement: items.map((item, i) => ({
      "@type": "ListItem",
      position: i + 1,
      name: item.name,
      item: item.url,
    })),
  };
}

Sử dụng trong blog post:

<JsonLd data={getBreadcrumbJsonLd([
  { name: "Home", url: SITE_CONFIG.baseUrl },
  { name: "Blog", url: `${SITE_CONFIG.baseUrl}/blog` },
  { name: post.title, url: `${SITE_CONFIG.baseUrl}/blog/${post.slug}` },
])} />

Google rich result:

leduykhuong.com > Blog > Learning in Public

Thay vì URL dài leduykhuong.com/vi/blog/learning-in-public, Google hiển thị breadcrumb trail readable.

Key rules:

  • position bắt đầu từ 1 (không phải 0)
  • Item cuối cùng = page hiện tại
  • Mỗi item phải có nameitem (URL)
  • URL phải absolute

Tại sao mỗi page cần strategy khác?

Mỗi loại page có primary purpose khác nhau:

PagePrimary entitySecondary entitiesLý do
HomepageWebSite(SearchAction embedded)Google cần biết đây là entry point
AboutPersonFocus vào author identity
Blog postBlogPostingBreadcrumbListContent + navigation context
Blog landing(none yet)Listing page, ít structured data cần

Principle: Schema nên phản ánh purpose của page, không phải liệt kê mọi entity có mặt. Homepage KHÔNG cần BlogPosting schema dù nó hiển thị recent posts — vì purpose của homepage là giới thiệu website, không phải display blog content.

Loading diagram...

Multiple <script> Tags — Cách Google xử lý

Mỗi JsonLd component render một <script> riêng:

<!-- Blog post page -->
<script type="application/ld+json">{"@type":"BlogPosting",...}</script>
<script type="application/ld+json">{"@type":"BreadcrumbList",...}</script>

Cách Google đọc:

  1. Parse TẤT CẢ <script type="application/ld+json"> blocks trên page
  2. Extract entities từ mỗi block
  3. Combine entities → hiểu toàn bộ page context
  4. Quyết định hiển thị rich results nào
Loading diagram...

Alternative: @graph array — Có thể gộp nhiều entities vào 1 script:

{
  "@context": "https://schema.org",
  "@graph": [
    { "@type": "BlogPosting", "headline": "..." },
    { "@type": "BreadcrumbList", "itemListElement": [...] }
  ]
}

Cả hai approaches đều valid. leduykhuong.com chọn multiple scripts vì:

  • Dễ maintain (mỗi component độc lập)
  • Dễ debug (grep từng type)
  • Dễ add/remove per page

Schemas chưa implement — Cơ hội mở rộng

Một số schema types có thể thêm trong tương lai:

CollectionPage — Blog landing

{
  "@type": "CollectionPage",
  "name": "Blog",
  "description": "Tất cả bài viết từ Le Duy Khuong",
  "url": "https://leduykhuong.com/blog",
  "mainEntity": {
    "@type": "ItemList",
    "numberOfItems": 125,
    "itemListElement": [...]
  }
}

Giúp Google hiểu: "Trang này là tập hợp bài viết, không phải một bài riêng."

FAQPage — Nếu có Q&A content

{
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "Agentic AI là gì?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Agentic AI là hệ thống AI..."
      }
    }
  ]
}

Google hiển thị FAQ expandable trực tiếp trên search results — tăng real estate đáng kể.

HowTo — Tutorial posts

Nếu blog post là tutorial/hướng dẫn, HowTo schema cho Google hiển thị steps:

Step 1: Install dependencies
Step 2: Configure environment
Step 3: Deploy

Design Principle — Schema per Page Type

Khi quyết định thêm schema, follow pattern:

1. Xác định page type (homepage, about, blog post, listing...)
2. Chọn primary schema (1 type chính)
3. Thêm supplementary schemas (breadcrumb, etc.) nếu cần
4. Tạo helper function trong lib/seo.ts
5. Inject qua <JsonLd> trong page component

Anti-patterns:

  • Thêm schema không liên quan tới page content
  • Khai báo required fields sai (Google ignore hoặc penalize)
  • Duplicate schemas trên cùng page (2 BlogPosting trên 1 page)

Thực hành

Bài tập 1: Map schema usage

cd ACE-component/ACE-leduykhuong-site
 
# Tìm tất cả nơi dùng JsonLd
grep -rn "JsonLd" app/ --include="*.tsx"
 
# Tìm tất cả schema helpers
grep -n "export function get.*JsonLd" lib/seo.ts

Câu hỏi: Có bao nhiêu page types dùng JsonLd? Có page nào dùng 2+ schemas?

Bài tập 2: Check homepage schema

npm run build
grep 'application/ld+json' out/index.html

Câu hỏi: Homepage có schema WebSite không? SearchAction urlTemplate trỏ đúng URL không?

Bài tập 3: Thiết kế schema cho Topic page

Topic page (ví dụ: /topics/agentic-ai) hiển thị danh sách posts theo topic. Schema type nào phù hợp nhất? Thử sketch JSON-LD object cho page này.


Tóm tắt

  • Multi-schema — Mỗi page có thể chứa nhiều schema types (BlogPosting + BreadcrumbList)
  • WebSite + SearchAction — Homepage schema, có thể trigger Sitelinks Searchbox
  • Person + sameAs — About page, connect author identity across platforms
  • BreadcrumbList — Navigation context, Google hiển thị readable path
  • Multiple <script> tags — Google parse tất cả blocks, dễ maintain hơn @graph
  • Schema per page type — Chọn primary schema theo page purpose, thêm supplementary khi cần

Bài tiếp theo

Bài 8: Debugging & Extending Structured Data — Cách dùng Rich Results Test, Schema Markup Validator, và Chrome DevTools để validate JSON-LD. Plus: quy trình thêm schema type mới cho leduykhuong.com.

LDK

Le Duy Khuong

AI Transformation & Digital Strategy. Writing about agentic systems, engineering leadership, and building in public.