
Hướng dẫn Sanity CMS: Cách chúng tôi xuất bản nội dung bằng 10 ngôn ngữ
Chúng tôi đã xuất bản hơn 400 bài viết trên 4 website và 10 ngôn ngữ thông qua Sanity CMS. Dưới đây là những bài học chúng tôi rút ra, từ thiết kế schema đến quy trình xuất bản đa ngôn ngữ tự động.
Sanity CMS là một nền tảng nội dung headless (phi đầu cuối) được xây dựng xung quanh nội dung có cấu trúc, Content Lake thời gian thực và một trình soạn thảo tùy chỉnh dựa trên React gọi là Sanity Studio. Nó sử dụng GROQ để truy vấn, Portable Text cho nội dung phong phú và schema-as-code (schema dưới dạng mã) để mô hình hóa nội dung. Hướng dẫn này bao gồm cách thiết lập, thiết kế schema, GROQ, Portable Text, kiến trúc đa ngôn ngữ và bảng giá.
Sanity CMS là gì?
Sanity là một nền tảng nội dung có cấu trúc, hay như đội ngũ Sanity.io gọi là "hệ điều hành nội dung". Khác với các CMS truyền thống lưu trữ các khối HTML trong cơ sở dữ liệu, Sanity lưu trữ từng phần nội dung dưới dạng JSON có cấu trúc trong một backend được quản lý gọi là Content Lake. Bạn truy vấn nó bằng GROQ hoặc GraphQL, và hiển thị nội dung trên bất kỳ frontend nào bạn muốn: Next.js, React Native, Svelte, ứng dụng di động, công cụ CLI, hoặc bất cứ thứ gì khác.
Các công ty sử dụng nó trải dài trên mọi quy mô. Nike, Figma, Puma và Cloudflare vận hành Sanity ở quy mô doanh nghiệp. Các startup sử dụng nó vì gói miễn phí thực sự hữu ích (sẽ nói thêm về giá cả sau). Chúng tôi sử dụng nó vì không có giải pháp nào khác mang lại sự linh hoạt để xây dựng một quy trình xuất bản 10 ngôn ngữ hoàn toàn tự động.
Kiến trúc Content Lake
Content Lake là backend được quản lý của Sanity. Hãy nghĩ về nó như một kho lưu trữ tài liệu được host, đồng bộ hóa theo thời gian thực trên tất cả các client được kết nối. Khi một biên tập viên thay đổi một đoạn văn trong Sanity Studio, một biên tập viên khác sẽ thấy ngay lập tức, không cần nút lưu, không xung đột merge, không cần migration cơ sở dữ liệu.
Bên dưới, các tài liệu được lưu trữ dưới dạng JSON có cấu trúc với các trường được định kiểu. Mọi thay đổi đều được theo dõi thông qua nhật ký giao dịch, vì vậy bạn có đầy đủ lịch sử phiên bản theo mặc định. Tính năng đồng bộ hóa thời gian thực sử dụng kiến trúc dựa trên listener (được mô tả trong tài liệu kiến trúc GitHub của Sanity) đẩy các thay đổi đến tất cả người đăng ký thông qua RxJS observables.
Điều gì làm cho nó khác biệt so với, ví dụ, cơ sở dữ liệu PostgreSQL với API REST? Content Lake xử lý mô hình hóa nội dung, kiểm soát truy cập, bộ nhớ đệm CDN, biến đổi hình ảnh và cộng tác thời gian thực như một dịch vụ được quản lý duy nhất. Bạn không chạy migration. Bạn không quản lý các bản sao. Bạn chỉ cần định nghĩa schema và truy vấn nội dung.
Sanity Studio: Trình soạn thảo tùy chỉnh của bạn
Sanity Studio là một ứng dụng React mã nguồn mở đóng vai trò là giao diện chỉnh sửa của bạn. Nó không phải là một bảng quản trị được host sẵn, mà là một ứng dụng React nằm trong codebase của bạn. Bạn có thể tùy chỉnh mọi khía cạnh của nó: các component input tùy chỉnh, trường có điều kiện, hành động tài liệu, các mẫu structure builder và plugin.
Cộng tác thời gian thực được tích hợp sẵn. Nhiều biên tập viên có thể làm việc trên cùng một tài liệu cùng lúc với các chỉ báo hiện diện và cập nhật trực tiếp. Nếu bạn đã sử dụng Google Docs, trải nghiệm cũng tương tự, bạn thấy con trỏ và thay đổi của người khác trong thời gian thực.
Chúng tôi triển khai Studio của mình với npx sanity deploy, giúp host nó trên CDN của Sanity tại một subdomain tùy chỉnh. Bạn cũng có thể tự host vì nó chỉ là một ứng dụng React. Chúng tôi đánh giá cao Sanity trong bài so sánh headless CMS chủ yếu nhờ vào sự linh hoạt của Studio.
Cách thiết lập dự án Sanity
Để thiết lập Sanity CMS, hãy cài đặt CLI bằng npm create sanity@latest, chọn một mẫu dự án, cấu hình các file schema và chạy npx sanity dev để khởi chạy Studio cục bộ. Toàn bộ quá trình mất chưa đầy 5 phút.
Điều kiện tiên quyết và Cài đặt
Bạn cần Node.js 18+ và npm (hoặc pnpm). Chỉ vậy thôi. Chạy lệnh init:
npm create sanity@latest
# You'll be prompted for:
# - Login method (Google, GitHub, email)
# - Project name
# - Dataset name (default: "production")
# - Project template (blog, ecommerce, clean)
# - TypeScript? (recommended: yes)CLI sẽ tạo khung dự án với mọi thứ bạn cần. Đây là cấu trúc dự án trông như thế nào:
Giải thích cấu trúc dự án
my-sanity-project/
├── schemas/ # Your content schemas (this is where you'll spend time)
│ ├── index.ts # Schema registry -- imports and exports all types
│ ├── post.ts # Document type definitions
│ └── blockContent.ts # Rich text / Portable Text config
├── sanity.config.ts # Main config -- plugins, Studio structure, dataset
├── sanity.cli.ts # CLI config -- project ID, dataset
├── package.json
└── tsconfig.jsonFile sanity.config.ts là điểm entry point. Đây là một ví dụ tối giản:
// sanity.config.ts
import { defineConfig } from 'sanity'
import { structureTool } from 'sanity/structure'
import { visionTool } from '@sanity/vision'
import { schemaTypes } from './schemas'
export default defineConfig({
name: 'default',
title: 'My Blog',
projectId: 'your-project-id',
dataset: 'production',
plugins: [structureTool(), visionTool()],
schema: { types: schemaTypes },
})Plugin visionTool() cung cấp cho bạn một sân chơi GROQ ngay trong Studio, bạn sẽ sử dụng nó liên tục trong quá trình phát triển.
Triển khai Studio của bạn
Khởi chạy cục bộ với npx sanity dev (chạy trên localhost:3333). Khi bạn sẵn sàng chia sẻ với các biên tập viên, hãy triển khai lên CDN của Sanity:
npx sanity deploy
# Prompts for a hostname, e.g., "my-blog"
# Deploys to https://my-blog.sanity.studioMẹo chuyên nghiệp: chạy npx sanity@latest schema deploy sau bất kỳ thay đổi schema nào. Thao tác này tải schema của bạn lên API của Sanity, cho phép các tính năng như API GraphQL và các công cụ nhận biết schema (bao gồm cả máy chủ MCP mà chúng tôi sẽ đề cập sau).
Thiết kế Schema trong Sanity CMS
Các schema của Sanity được định nghĩa là các đối tượng JavaScript hoặc TypeScript trong codebase của bạn. Mỗi schema chỉ định một loại tài liệu với các trường, quy tắc xác thực và các component input tùy chỉnh. Các thay đổi đối với schema diễn ra tức thì, không cần migration cơ sở dữ liệu. Đây là cách tiếp cận "schema-as-code", và đó là điều đã thuyết phục chúng tôi chọn Sanity thay vì Contentful.
Các loại trường và Xác thực
Sanity đi kèm với một bộ loại trường phong phú. Dưới đây là những loại chúng tôi sử dụng nhiều nhất:
| Loại trường | Trường hợp sử dụng | Ví dụ |
|---|---|---|
string | Văn bản ngắn, tiêu đề, slug | Tiêu đề bài viết, tên tác giả |
text | Văn bản thuần túy nhiều dòng | Đoạn trích, mô tả |
number | Số nguyên, số thập phân | Thời gian đọc, thứ tự sắp xếp |
boolean | Bật/tắt | Cờ nổi bật, trạng thái nháp |
array | Danh sách, văn bản phong phú (Portable Text) | Nội dung chính, thẻ tag |
reference | Liên kết đến các tài liệu khác | Tác giả, danh mục |
image | Hình ảnh với metadata | Ảnh bìa với văn bản alt |
slug | Chuỗi thân thiện với URL | Tự động tạo từ tiêu đề |
object | Nhóm trường lồng nhau | Các trường SEO (metaTitle + metaDescription) |
date / datetime | Ngày tháng | Ngày xuất bản |
Mọi trường đều hỗ trợ xác thực thông qua callback validation. Bạn có thể bắt buộc các trường bắt buộc, giá trị min/max, mẫu regex và các quy tắc tùy chỉnh:
defineField({
name: 'seoDescription',
title: 'Meta Description',
type: 'string',
validation: (Rule) =>
Rule.required()
.min(145)
.max(160)
.warning('Meta description should be 145-160 characters'),
})Các loại Block tùy chỉnh (Ví dụ thực tế của chúng tôi)
Đây là nơi Sanity trở nên thú vị, và là nơi 0 trên 6 hướng dẫn cạnh tranh hiển thị bất kỳ mã nào. Trong schema production của chúng tôi, chúng tôi định nghĩa năm loại block tùy chỉnh bên trong mảng body: block (văn bản chuẩn), table, codeBlock, chartBlock và inlineImage.
Đây là định nghĩa codeBlock của chúng tôi:
// schemas/objects/codeBlock.ts
import { defineType } from 'sanity'
export const codeBlock = defineType({
name: 'codeBlock',
title: 'Code Block',
type: 'object',
fields: [
{
name: 'language',
title: 'Language',
type: 'string',
options: {
list: [
{ title: 'JavaScript', value: 'javascript' },
{ title: 'TypeScript', value: 'typescript' },
{ title: 'Python', value: 'python' },
{ title: 'Bash', value: 'bash' },
{ title: 'JSON', value: 'json' },
{ title: 'GROQ', value: 'groq' },
],
},
},
{
name: 'code',
title: 'Code',
type: 'text',
},
],
})Và đây là cách trường body tham chiếu đến tất cả các loại tùy chỉnh của chúng tôi cùng nhau:
// schemas/fields/body.ts
defineField({
name: 'body',
title: 'Body',
type: 'array',
of: [
{ type: 'block' }, // Standard Portable Text (paragraphs, headings, lists)
{ type: 'table' }, // @sanity/table plugin
{ type: 'codeBlock' }, // Our custom code block
{ type: 'chartBlock' }, // Data visualization (bar, line, pie)
{ type: 'inlineImage' }, // Images with alt text and captions
],
})Điều này cung cấp cho các biên tập viên của chúng tôi một bộ công cụ nội dung phong phú trong khi giữ cho mọi phần tử được định kiểu và có thể truy vấn. Một chartBlock không chỉ là một embed HTML mờ ám, mà là dữ liệu có cấu trúc với các trường chartType, title, dataPoints và dataLabels. Điều đó rất quan trọng khi bạn cố gắng hiển thị cùng một nội dung trên web, email và di động.
Các phương pháp hay nhất về tổ chức Schema
Giữ các schema модуль hóa. Chúng tôi chia nhỏ chúng theo loại qua các file: schemas/documents/post.ts, schemas/objects/codeBlock.ts, schemas/objects/chartBlock.ts. Nhập tất cả chúng trong schemas/index.ts:
// schemas/index.ts
import { post } from './documents/post'
import { codeBlock } from './objects/codeBlock'
import { chartBlock } from './objects/chartBlock'
import { inlineImage } from './objects/inlineImage'
export const schemaTypes = [post, codeBlock, chartBlock, inlineImage]Bài học quan trọng chúng tôi rút ra khi làm việc với nội dung có cấu trúc: schema CỦA BẠN CHÍNH LÀ mô hình nội dung. Nếu bạn coi nó như kỹ thuật ngữ cảnh cho đội ngũ nội dung của mình, bạn sẽ đưa ra các quyết định thiết kế tốt hơn. Mỗi trường bạn thêm vào nên phục vụ một mục đích, dù là cho biên tập viên, cho việc hiển thị hay cho việc truy vấn.
GROQ: Ngôn ngữ truy vấn của Sanity
GROQ (Graph-Relational Object Queries) là ngôn ngữ truy vấn mã nguồn mở của Sanity để lọc, join và chiếu các tài liệu JSON. Cú pháp cơ bản là *[filter]{projection}, chọn tất cả các tài liệu khớp với bộ lọc, sau đó định hình đầu ra. Nó ngắn gọn hơn GraphQL cho các truy vấn cụ thể của Sanity và, theo kinh nghiệm của chúng tôi, dễ học hơn.
Truy vấn cơ bản: Lọc và Chiếu
Truy vấn đơn giản nhất lấy tất cả các tài liệu của một loại:
// Fetch all posts -- just title and slug
*[_type == "post"]{
title,
"slug": slug.current
}
// Filter by language, expand author reference
*[_type == "post" && language == "en"]{
title,
"slug": slug.current,
"authorName": author->name,
"authorImage": author->image,
"categoryTitle": category->title,
publishedAt
}Toán tử -> đi theo các reference. author->name có nghĩa là "đi theo reference tác giả và trả về trường name." Không có truy vấn riêng biệt, không có vấn đề N+1, không có JOIN, tất cả đều là một biểu thức duy nhất.
Joins, Sắp xếp và Phân trang
Đối với các trang index blog của chúng tôi, chúng tôi cần các bài viết được sắp xếp, phân trang với các reference được mở rộng:
// Paginated posts with full metadata
*[_type == "post" && language == "en"] | order(publishedAt desc) [0...10] {
title,
"slug": slug.current,
excerpt,
publishedAt,
readTime,
"author": author->{name, image},
"category": category->{title, "slug": slug.current},
"coverImage": coverImage{
"src": asset->url,
alt
}
}[0...10] cung cấp cho bạn 10 kết quả đầu tiên (chỉ số 0, kết thúc độc quyền). | order(publishedAt desc) sắp xếp mới nhất trước. Projection định hình đầu ra để bao gồm chính xác những gì frontend của bạn cần, không hơn không kém.
Bạn có thể kiểm tra tất cả các truy vấn này một cách tương tác bằng cách sử dụng plugin Vision bên trong Sanity Studio. Nó vô giá trong quá trình phát triển. Để biết thêm các mẫu, hãy xem bảng cheatsheet GROQ.
GROQ so với GraphQL
Sanity hỗ trợ cả GROQ và GraphQL. Khi nào nên sử dụng cái nào?
GROQ là ngôn ngữ gốc của Sanity. Nó xử lý joins, projections và các trường tính toán trong một chuỗi truy vấn duy nhất. Đó là những gì Content Lake được tối ưu hóa cho.
GraphQL có sẵn sau khi bạn triển khai schema của mình (npx sanity@latest schema deploy). Sử dụng nó khi bạn cần các công cụ tiêu chuẩn hóa, ví dụ: nếu frontend của bạn đã sử dụng Apollo Client hoặc nếu nhóm của bạn biết GraphQL nhưng không biết GROQ.
Chúng tôi sử dụng độc quyền GROQ. Nó biểu cảm hơn cho dữ liệu Sanity và plugin Vision giúp việc gỡ lỗi truy vấn trở nên tầm thường.
Portable Text: Nội dung phong phú đúng cách
Portable Text là đặc tả của Sanity cho văn bản phong phú có cấu trúc. Thay vì lưu trữ nội dung dưới dạng chuỗi HTML, nó lưu trữ một mảng các block được định kiểu, đoạn văn, tiêu đề, hình ảnh, đoạn mã, bảng, mỗi cái như một đối tượng JSON. Điều này làm cho nội dung có thể hiển thị trong bất kỳ framework nào, bất kỳ nền tảng nào, bất kỳ định dạng nào.
Cấu trúc dữ liệu
Dưới đây là cách một đoạn văn và một block mã trông như thế nào dưới dạng JSON Portable Text:
[
{
"_type": "block",
"_key": "a1b2c3",
"style": "normal",
"markDefs": [],
"children": [
{
"_type": "span",
"_key": "d4e5f6",
"text": "Here's an example of our pipeline config:",
"marks": []
}
]
},
{
"_type": "codeBlock",
"_key": "g7h8i9",
"language": "typescript",
"code": "export default defineConfig({ ... })"
}
]Mỗi block có _type và _key. Các block văn bản chuẩn sử dụng "block" với các children spans (hỗ trợ các marks như đậm, nghiêng và liên kết). Các block tùy chỉnh, như codeBlock, chartBlock, table và inlineImage của chúng tôi, sử dụng _type riêng và mang các trường có cấu trúc.
Tại sao điều này lại quan trọng? Vì HTML là một định dạng hiển thị, không phải định dạng lưu trữ. Nếu bạn lưu trữ <h2>Title</h2><p>Some <strong>text</strong></p> trong cơ sở dữ liệu, bạn đã tự khóa mình vào việc hiển thị web. Bạn không thể trích xuất sạch sẽ điều đó cho ứng dụng di động, bản tin email, PDF hoặc cửa sổ ngữ cảnh của tác nhân AI. Portable Text tách biệt nội dung khỏi trình bày. Đặc tả Portable Text là mã nguồn mở, nó không phải là sự phụ thuộc vào Sanity.
Các Block tùy chỉnh trong Production
Quy trình của chúng tôi chuyển đổi Markdown sang Portable Text bằng một script Python (scripts/md_to_portable_text.py). Bộ chuyển đổi xử lý các block chuẩn, cộng với bốn loại tùy chỉnh của chúng tôi:
table, sử dụng schema plugin@sanity/table. Các hàng và ô được lưu trữ dưới dạng dữ liệu có cấu trúc.codeBlock, ngôn ngữ và mã là các trường riêng biệt, cho phép tô sáng cú pháp khi hiển thị.chartBlock, loại biểu đồ, tiêu đề, nhãn trục, tên series và các điểm dữ liệu dưới dạng JSON có cấu trúc. Frontend hiển thị những thứ này bằng Chart.js.inlineImage, văn bản alt, nguồn và chú thích tùy chọn là các trường riêng biệt.
Cấu trúc này có nghĩa là chúng tôi có thể truy vấn tất cả các ví dụ mã trong blog của mình (*[body[]._type == "codeBlock"]), tìm các bài viết có biểu đồ hoặc trích xuất tất cả các hình ảnh thiếu văn bản alt, tất cả thông qua GROQ.
Hiển thị Portable Text
Trên frontend, sử dụng @portabletext/react (hoặc các tương đương Svelte/Vue). Bạn đăng ký các component tùy chỉnh cho mỗi loại block:
import { PortableText } from '@portabletext/react'
const components = {
types: {
codeBlock: ({ value }) => (
<pre className={`language-${value.language}`}>
<code>{value.code}</code>
</pre>
),
chartBlock: ({ value }) => <Chart data={value} />,
inlineImage: ({ value }) => (
<figure>
<img src={value.src} alt={value.alt} />
{value.caption && <figcaption>{value.caption}</figcaption>}
</figure>
),
},
}
// In your component:
<PortableText value={post.body} components={components} />Đó là toàn bộ quy trình hiển thị. Component PortableText xử lý các block chuẩn (đoạn văn, tiêu đề, danh sách, marks) tự động. Bạn chỉ cần định nghĩa các component tùy chỉnh cho các loại tùy chỉnh của mình.
Nội dung đa ngôn ngữ với Sanity CMS
Sanity hỗ trợ nội dung đa ngôn ngữ thông qua bản địa hóa cấp tài liệu (các tài liệu riêng biệt cho mỗi ngôn ngữ được liên kết bằng một reference canonical) hoặc bản địa hóa cấp trường (các trường được dịch trong một tài liệu). Bản địa hóa cấp tài liệu hoạt động tốt hơn cho SEO và xuất bản quy mô lớn, đó là những gì chúng tôi sử dụng trên quy trình 10 ngôn ngữ của mình.
Bản địa hóa cấp Tài liệu so với cấp Trường
| Khía cạnh | Cấp Tài liệu | Cấp Trường |
|---|---|---|
| Cách tiếp cận | Tài liệu riêng cho mỗi ngôn ngữ | Tất cả bản dịch trong một tài liệu |
| SEO | Mỗi tài liệu có URL/slug riêng | URL duy nhất, khó phục vụ các trang theo ngôn ngữ |
| Độ phức tạp truy vấn | Bộ lọc đơn giản: language == "de" | Truy cập trường lồng nhau: title.de |
| Kích thước nội dung | Tài liệu nhỏ, tập trung | Một tài liệu lớn với tất cả ngôn ngữ |
| Phù hợp nhất cho | Bài đăng blog, trang, nội dung hướng SEO | Chuỗi UI nhỏ, nhãn, metadata |
| Kết luận của chúng tôi | Chúng tôi sử dụng cái này cho mọi thứ | Chỉ cho các chuỗi UI chia sẻ |
Chúng tôi chọn bản địa hóa cấp tài liệu vì mỗi bản dịch có slug riêng, URL riêng và metadata riêng. Phiên bản tiếng Thổ Nhĩ Kỳ của một bài viết về Supabase so với Firebase có slug supabase-firebase-karsilastirma, tiếng Thổ Nhĩ Kỳ chuẩn, không phải một hack tham số URL.
Kiến trúc Quy trình 10 Ngôn ngữ của chúng tôi
Đây là cách quy trình tự động của chúng tôi hoạt động: chúng tôi viết một bài đăng bằng tiếng Anh, sau đó dịch nó sang 9 ngôn ngữ bổ sung (Tiếng Đức, Pháp, Hà Lan, Tây Ban Nha, Thổ Nhĩ Kỳ, Ý, Thụy Điển, Na Uy, Ả Rập). Mỗi bản dịch đi qua chuyển đổi Markdown, tạo Portable Text và xuất bản API Sanity.
Kiến trúc trông như thế này:
- Viết, Markdown tiếng Anh với frontmatter YAML
- Dịch, dịch AI sang 9 ngôn ngữ (đã xác minh tính đầy đủ và dấu phụ)
- Chuyển đổi, script Python chuyển đổi mỗi file
.mdsang JSON Portable Text - Xuất bản, gọi API đến Sanity: tạo tài liệu, tải lên hình ảnh, patch các reference
Mỗi tài liệu có một trường language và một reference canonicalPost trỏ đến bản gốc tiếng Anh. Đây là truy vấn GROQ để lấy một bài đăng và tất cả các bản dịch của nó:
// Fetch a post and all its translations
*[_type == "post" && slug.current == "sanity-cms-guide" && language == "en"][0]{
title,
language,
"translations": *[
_type == "post" &&
canonicalPost._ref == ^._id
]{
title,
language,
"slug": slug.current
}
}Phía schema khá đơn giản, một trường language với enum các ngôn ngữ được hỗ trợ:
defineField({
name: 'language',
title: 'Language',
type: 'string',
options: {
list: [
{ title: 'English', value: 'en' },
{ title: 'German', value: 'de' },
{ title: 'French', value: 'fr' },
{ title: 'Dutch', value: 'nl' },
{ title: 'Spanish', value: 'es' },
{ title: 'Turkish', value: 'tr' },
{ title: 'Italian', value: 'it' },
{ title: 'Swedish', value: 'sv' },
{ title: 'Norwegian', value: 'no' },
{ title: 'Arabic', value: 'ar' },
],
},
validation: (Rule) => Rule.required(),
})Một vấn đề chúng tôi đã học được một cách khó khăn: hãy xuất bản tài liệu tiếng Anh trước, sau đó patch các reference canonicalPost trên các bản dịch bằng ID tài liệu đã xuất bản, không phải tiền tố drafts.. Sanity coi các tài liệu nháp và đã xuất bản là các thực thể riêng biệt bên trong.
Để biết thêm chi tiết về cách quy trình này kết nối với Model Context Protocol, hãy xem phần tiếp theo.
Các tính năng AI của Sanity: MCP, Canvas và Agent Context
Sanity định vị mình là hệ điều hành nội dung cho kỷ nguyên AI. Các tính năng AI chính bao gồm máy chủ MCP để các tác nhân AI đọc và ghi nội dung, Canvas để chỉnh sửa hỗ trợ bởi AI bên trong Studio và Agent Context để các tác nhân AI production truy vấn nội dung có cấu trúc với nhận thức về schema.
Tích hợp Máy chủ MCP
Máy chủ Sanity MCP cho phép các tác nhân AI, Claude Code, Cursor, Windsurf và những tác nhân khác, tương tác với không gian làm việc Sanity của bạn một cách lập trình. Các tác nhân có thể đọc schema, thực thi truy vấn GROQ, tạo tài liệu và quản lý nội dung mà không cần các wrapper API tùy chỉnh.
Chúng tôi sử dụng máy chủ Sanity MCP hàng ngày trong quy trình nội dung của mình. Các tác nhân AI của chúng tôi truy vấn schema để hiểu cấu trúc tài liệu, tìm nạp các bài đăng hiện có để tìm cơ hội liên kết nội bộ và xuất bản các tài liệu mới. Giao thức MCP cung cấp cho các tác nhân nhận thức về schema, họ biết những trường nào tồn tại, những loại nào họ mong đợi và những quy tắc xác thực nào áp dụng. Nếu bạn đang xây dựng các quy trình làm việc tác nhân AI cho doanh nghiệp, đây là một mẫu mạnh mẽ.
Agent Context cho AI Production
Agent Context là một tính năng riêng biệt cho các tích hợp AI cấp production. Không giống như máy chủ MCP (được thiết kế cho các công cụ dành cho nhà phát triển), Agent Context cung cấp quyền truy cập chỉ đọc, được giới hạn phạm vi cho các tác nhân AI cần truy vấn nội dung của bạn trong thời gian chạy, hãy nghĩ đến chatbot, công cụ đề xuất hoặc hệ thống cá nhân hóa nội dung.
Sự khác biệt là quan trọng: MCP dành cho các quy trình làm việc build-time và biên tập (công cụ phát triển nhận biết schema), trong khi Agent Context dành cho truy cập nội dung runtime với xác thực và giới hạn tốc độ phù hợp.
Nội dung có cấu trúc của Sanity mang lại lợi thế thực sự ở đây. Một trang WordPress lưu trữ nội dung dưới dạng các khối HTML, một tác nhân AI phải phân tích cú pháp HTML để hiểu nội dung. Sanity lưu trữ các tài liệu JSON được định kiểu với các schema được định nghĩa. Một tác nhân có thể truy vấn *[_type == "product" && category == "electronics"]{name, price, features} và nhận lại dữ liệu sạch, có cấu trúc. Không cào quét, không phân tích cú pháp, không đoán mò.
Cách chúng tôi sử dụng Sanity tại Techsy
Đây không phải là phần giả định. Chúng tôi vận hành Sanity CMS trên 4 website production, xuất bản bằng 10 ngôn ngữ với một quy trình tự động mà chúng tôi đã xây dựng trong năm qua. Đây là kiến trúc.
Kiến trúc Quy trình Nội dung của chúng tôi
Quy trình đi từ nghiên cứu đến bài đăng đã xuất bản trên tất cả 10 ngôn ngữ:
- Nghiên cứu, phân tích từ khóa, xác định khoảng trống đối thủ, mẫu SERP
- Brief, đặc tả viết có cấu trúc với hướng dẫn phần, số lượng từ, liên kết nội bộ
- Viết, tạo Markdown tiếng Anh với frontmatter YAML
- Chuyển đổi, script Python biến đổi Markdown sang JSON Portable Text với 5 loại block tùy chỉnh của chúng tôi
- Xuất bản, gọi API đến Sanity: tài liệu
createOrReplace, tải lên hình ảnh lên Sanity CDN, patch các reference tác giả/danh mục - Dịch, dịch AI sang 9 ngôn ngữ, đã xác minh tính đầy đủ
- Xuất bản bản dịch, cùng quy trình chuyển đổi/xuất bản cho mỗi ngôn ngữ, với reference
canonicalPostđược patch đến bản gốc tiếng Anh
Schema tùy chỉnh hỗ trợ các loại block, table, codeBlock, chartBlock và inlineImage, tất cả được định nghĩa là các đối tượng schema Sanity production với các quy tắc xác thực. Trong số các công cụ AI cho startup mà chúng tôi đã thử nghiệm, quy trình dựa trên Sanity này là đáng tin cậy nhất cho nội dung có cấu trúc ở quy mô lớn.
Bài học từ hơn 400 bài viết đã xuất bản
Một vài điều chúng tôi ước ai đó đã nói với chúng tôi:
Thứ tự patch reference là quan trọng. Các reference của Sanity không thể trỏ đến các tài liệu chưa tồn tại. Hãy xuất bản bài đăng tiếng Anh trước, sau đó tạo các bản dịch với canonicalPost trỏ đến ID đã xuất bản của tài liệu tiếng Anh. Chúng tôi đã phá vỡ điều này nhiều lần trong giai đoạn đầu.
Triển khai schema là theo workspace. Nếu bạn chạy nhiều dự án Sanity (chúng tôi chạy 4), bạn cần triển khai schema cho từng dự án riêng biệt: npx sanity@latest schema deploy cho mỗi cấu hình dự án.
Gói miễn phí là có thật. Chúng tôi đã chạy hai trong số bốn trang web của mình trên gói miễn phí trong nhiều tháng. 20 người dùng, 500K yêu cầu API/tháng, 100K yêu cầu CDN, đủ cho một trang web production thực sự, không chỉ là một dự án đồ chơi.
Chuyển đổi Portable Text là nút cổ chai. Chuyển đổi Markdown sang Portable Text không hề tầm thường. Danh sách lồng nhau, bảng bên trong blockquote, block mã với các ký tự đặc biệt, các trường hợp edge ở khắp mọi nơi. Chúng tôi đã lặp lại script chuyển đổi của mình trong nhiều tháng.
Cần giúp đỡ thiết lập Sanity cho dự án của bạn? Chúng tôi đã xây dựng các quy trình nội dung đa ngôn ngữ cho 4 trang web production. Nhận tư vấn miễn phí
Phân tích Giá cả Sanity CMS
Sanity cung cấp ba gói: Free (20 người dùng, 500K yêu cầu API/tháng), Growth ($15/người dùng/tháng với các vai trò nâng cao và bản nháp lên lịch) và Enterprise (giá tùy chỉnh với SLA và các tính năng tuân thủ). Gói miễn phí là hào phóng nhất trên thị trường headless CMS.
| Tính năng | Free | Growth ($15/người dùng/tháng) | Enterprise |
|---|---|---|---|
| Người dùng | 20 | 50 | Không giới hạn |
| Yêu cầu API | 500K/tháng | 2.5M/tháng | Tùy chỉnh |
| Yêu cầu CDN | 100K/tháng | 500K/tháng | Tùy chỉnh |
| Vai trò | Chỉ Admin | Admin, Developer, Editor, Contributor | Vai trò tùy chỉnh |
| Cộng tác | Chỉnh sửa thời gian thực | + Xuất bản theo lịch, bản nháp | + Quy trình làm việc |
| Hỗ trợ | Cộng đồng | Dedicated + SLA | |
| Tuân thủ | , | , | SOC 2, HIPAA |
Trên gói miễn phí, chúng tôi chạy hai trang web của mình mà không chạm đến giới hạn. Gói Growth ở mức $15/người dùng/tháng đã thêm quyền truy cập dựa trên vai trò (quan trọng khi chúng tôi có các biên tập viên không kỹ thuật) và xuất bản theo lịch. Người xem miễn phí trên gói Growth, đó là một điểm cộng nice, bạn không bị phạt vì cung cấp quyền đọc cho các bên liên quan.
So sánh với đối thủ như thế nào?
| Tính năng | Sanity Free | Contentful Free | Strapi Cloud Free | Payload Cloud |
|---|---|---|---|---|
| Người dùng | 20 | 1 | 1 | 1 |
| Loại nội dung | Không giới hạn | 48 | Không giới hạn | Không giới hạn |
| Gọi API | 500K/tháng | Bao gồm | Bao gồm | Bao gồm |
| Loại tùy chỉnh | Có | Giới hạn | Có | Có |
| Giá để mở rộng | $15/người dùng/tháng | $300/tháng | $29/tháng | $50/tháng |
Gói miễn phí 20 người dùng của Sanity là ngoại lệ. Contentful giới hạn bạn ở 1 người dùng trên gói miễn phí và nhảy vọt lên $300/tháng cho gói Team của họ. Nếu bạn là một startup hoặc nhóm nhỏ, gói miễn phí của Sanity cho phép bạn chạy các khối lượng công việc production thực sự mà không tốn xu nào.
Sanity cũng cung cấp một chương trình startup tặng các startup đủ điều kiện một năm truy cập Growth miễn phí. Đáng để nộp đơn nếu bạn đủ điều kiện.
Câu hỏi Thường gặp
Sanity CMS là gì và nó hoạt động như thế nào?
Sanity CMS là một nền tảng nội dung headless lưu trữ các tài liệu JSON có cấu trúc trong một backend được quản lý gọi là Content Lake. Bạn chỉnh sửa nội dung thông qua Sanity Studio (một ứng dụng React tùy chỉnh), truy vấn nó bằng GROQ hoặc GraphQL và hiển thị nó trong bất kỳ framework frontend nào. Nội dung đồng bộ hóa theo thời gian thực trên tất cả các client được kết nối.
Sanity CMS có miễn phí không?
Có. Gói miễn phí của Sanity bao gồm 20 người dùng, 500K yêu cầu API mỗi tháng và 100K yêu cầu CDN, là gói miễn phí hào phóng nhất trong số các nền tảng headless CMS. Gói Growth có giá $15 mỗi người dùng mỗi tháng và thêm quyền truy cập dựa trên vai trò, xuất bản theo lịch và các giới hạn cao hơn. Giá Enterprise là tùy chỉnh.
Sự khác biệt giữa Sanity và Contentful là gì?
Sanity sử dụng schema-as-code (schema nằm trong codebase của bạn), GROQ để truy vấn và một Studio mã nguồn mở hoàn toàn tùy chỉnh. Contentful sử dụng mô hình hóa nội dung dựa trên GUI, GraphQL và một trình soạn thảo được host với ít tùy chỉnh hơn. Gói miễn phí của Sanity bao gồm 20 người dùng so với 1 của Contentful. Contentful có thị trường plugin lớn hơn.
Sanity CMS có tốt cho người mới bắt đầu không?
Sanity Studio trực quan cho các biên tập viên nội dung, trải nghiệm chỉnh sửa không yêu cầu kiến thức kỹ thuật. Tuy nhiên, thiết lập schema đòi hỏi thành thạo JavaScript hoặc TypeScript. Sanity cung cấp tài liệu tuyệt vời, các mẫu dự án và một Slack cộng đồng với hỗ trợ tích cực. Hãy bắt đầu với npm create sanity@latest và một mẫu blog.
Tôi có thể tự host Sanity không?
Sanity Studio hoàn toàn có thể tự host vì nó là một ứng dụng React mã nguồn mở. Bạn có thể triển khai nó lên Vercel, Netlify hoặc bất kỳ nhà cung cấp hosting tĩnh nào. Backend Content Lake là một dịch vụ được quản lý, không có tùy chọn tự host cho lớp dữ liệu. Đây là sự đánh đổi: bạn có được quản lý hạ tầng bằng không nhưng không có quyền kiểm soát dữ liệu on-premises.
Sanity sử dụng loại cơ sở dữ liệu nào?
Content Lake của Sanity không phải là cơ sở dữ liệu SQL hoặc NoSQL truyền thống. Nó là một kho lưu trữ tài liệu được quản lý lưu trữ nội dung dưới dạng JSON có cấu trúc với một lớp truy vấn GROQ ở trên. Bạn không tương tác trực tiếp với cơ sở dữ liệu bên dưới, bạn tương tác thông qua các API của Sanity. Các tài liệu có đầy đủ lịch sử phiên bản và đồng bộ hóa thời gian thực được tích hợp sẵn.
Sanity CMS có mã nguồn mở không?
Sanity Studio là mã nguồn mở theo giấy phép MIT, bạn có thể fork, tùy chỉnh và tự host nó. Backend Content Lake là SaaS độc quyền. Đặc tả ngôn ngữ truy vấn GROQ cũng là mã nguồn mở, được công bố trên GitHub. Đặc tả Portable Text cũng là mã nguồn mở, được duy trì tại portabletext.org.
Portable Text trong Sanity là gì?
Portable Text là đặc tả của Sanity cho văn bản phong phú có cấu trúc. Thay vì lưu trữ nội dung dưới dạng chuỗi HTML, nó đại diện cho các đoạn văn, tiêu đề, hình ảnh và các block tùy chỉnh dưới dạng các đối tượng JSON được định kiểu trong một mảng. Điều này làm cho nội dung có thể di chuyển giữa các framework và nền tảng. Bạn có thể định nghĩa các loại block tùy chỉnh như đoạn mã, biểu đồ và bảng với các trường có cấu trúc riêng của chúng.
GROQ là gì và nó khác với GraphQL như thế nào?
GROQ (Graph-Relational Object Queries) là ngôn ngữ truy vấn gốc của Sanity. Cú pháp của nó, *[filter]{projection}, ngắn gọn hơn GraphQL cho dữ liệu Sanity, với hỗ trợ tích hợp cho các joins thông qua toán tử -> và các trường tính toán. GraphQL cũng có sẵn cho các nhóm thích các công cụ tiêu chuẩn hóa hoặc đã sử dụng Apollo Client.
Sanity xử lý nội dung đa ngôn ngữ như thế nào?
Sanity hỗ trợ bản địa hóa cấp tài liệu (các tài liệu riêng biệt cho mỗi ngôn ngữ được liên kết bằng các reference canonical) và bản địa hóa cấp trường (các trường được dịch trong một tài liệu). Cấp tài liệu tốt hơn cho SEO vì mỗi bản dịch có URL và metadata riêng. Chúng tôi sử dụng bản địa hóa cấp tài liệu để xuất bản trên 10 ngôn ngữ với các quy trình dịch và xuất bản tự động.