Trường tùy chỉnh và loại nội dung
Nhân sự có thể tạo loại nội dung (ví dụ «Sự kiện», «Linh mục quản xứ») và trường tùy chỉnh (ví dụ «Ngày diễn ra», «Địa điểm») trong trang quản trị. Mỗi entry trả về hai trường liên quan:
| Trường | Kiểu | Ý nghĩa |
|---|---|---|
contentType | string | null | Slug của loại nội dung; null với bài thường và với trang tĩnh. |
meta | object | Các giá trị trường tùy chỉnh, khóa là khóa của trường. |
Có ở cả mục danh sách lẫn chi tiết.
Thống nhất khóa với nhân sự trước
API công khai không trả về định nghĩa trường (tên hiển thị, kiểu, bắt buộc hay không). meta chỉ là các cặp khóa và giá trị. Vì vậy:
- Thống nhất với nhân sự danh sách loại nội dung và khóa trường mà giao diện của bạn dựa vào, ví dụ loại
su-kiencóngay-dien-ra(ngày) vàdia-diem(văn bản). - Viết giao diện theo
contentTypevà các khóa đó. - Luôn coi mọi khóa là có thể vắng mặt: trường không bắt buộc, trường mới thêm sau khi bài được viết, giá trị theo ngôn ngữ chưa dịch, hoặc nhân sự đổi cấu trúc sau này.
Khóa trường là slug (chữ thường, số, -), tối đa 40 ký tự, duy nhất trong một trang web.
Giá trị theo từng kiểu trường
| Kiểu trường | Giá trị JSON trong meta | Hiển thị an toàn |
|---|---|---|
| Văn bản ngắn | string, tối đa 300 ký tự, một dòng | In ra như văn bản. |
| Văn bản dài | string, tối đa 5000 ký tự, có thể có xuống dòng | In ra như văn bản, đổi xuống dòng thành <br> hoặc dùng CSS white-space: pre-line. Không chèn như HTML. |
| Liên kết | string, luôn bắt đầu bằng https:// | Dùng làm href; nên thêm rel="noopener noreferrer". |
| Số | number | Định dạng theo ngôn ngữ (Intl.NumberFormat). |
| Ngày | string dạng YYYY-MM-DD (chỉ ngày, không giờ) | Phân tích như một ngày lịch, không qua new Date(…) theo giờ địa phương, kẻo lệch một ngày. |
| Có/không | boolean | |
| Lựa chọn | string: giá trị (slug) của lựa chọn, không phải nhãn | Tự ánh xạ giá trị sang nhãn hiển thị. |
| Hình ảnh | object có url (địa chỉ https:// đầy đủ) | Dùng url làm src. Object còn một khóa định danh nội bộ: hãy bỏ qua nó. |
Một số trường dùng chung cho mọi ngôn ngữ (ví dụ ngày, ảnh), số khác theo từng ngôn ngữ (ví dụ địa điểm viết bằng tiếng Việt và tiếng Anh). meta bạn nhận được đã gộp sẵn cả hai loại cho locale bạn hỏi. Giá trị theo ngôn ngữ chưa được dịch thì vắng mặt, không dự phòng về ngôn ngữ chính.
Ví dụ: hiển thị một «Sự kiện»
type Meta = Record<string, unknown>
const text = (v: unknown): string | null => (typeof v === 'string' && v.trim() !== '' ? v : null)
function calendarDate(v: unknown, locale: string): string | null {
if (typeof v !== 'string' || !/^\d{4}-\d{2}-\d{2}$/.test(v)) return null
const [y, m, d] = v.split('-').map(Number)
// Format in UTC so the calendar day never shifts with the visitor's time zone.
return new Intl.DateTimeFormat(locale, { dateStyle: 'long', timeZone: 'UTC' }).format(new Date(Date.UTC(y, m - 1, d)))
}
function imageUrl(v: unknown): string | null {
if (typeof v !== 'object' || v === null) return null
const url = (v as { url?: unknown }).url
return typeof url === 'string' && url.startsWith('https://') ? url : null
}
function eventDetails(entry: { contentType: string | null; meta: Meta }, locale: string) {
if (entry.contentType !== 'su-kien') return null
return {
date: calendarDate(entry.meta['ngay-dien-ra'], locale),
place: text(entry.meta['dia-diem']),
poster: imageUrl(entry.meta['anh-poster']),
}
}
Các khóa su-kien, ngay-dien-ra, dia-diem, anh-poster ở trên chỉ là ví dụ; dùng khóa mà bạn đã thống nhất với nhân sự.
Loại nội dung «không liệt kê»
Nhân sự có thể đặt một loại nội dung là không liệt kê. Bài của loại đó không có trong danh sách chung, trong tìm kiếm và trong «Đọc nhiều», nhưng vẫn có trong danh sách theo danh mục hoặc thẻ và vẫn mở được theo slug. Dùng cách này cho những mục có trang riêng (ví dụ một danh mục «Sự kiện» hiển thị dạng lịch) mà không muốn chen vào dòng tin chung.