Bỏ qua tới nội dung
Theme

Giải thích theme.json trong WordPress: settings, styles và thứ tự ưu tiên

Hiểu vì sao settings và styles trong theme.json làm hai việc khác nhau, và sửa những chỉnh sửa block theme không hiện gì bằng cách đi từng lớp trong cascade của WordPress.

Đã đăng

theme.json là một file cấu hình duy nhất nằm ở gốc block theme và làm hai việc tách bạch: settings quyết định block editor mở ra những gì cho người dùng, còn styles quyết định site trông ra sao theo mặc định. WordPress phân tích file này, trộn với mặc định của chính nó và với mọi thứ đã lưu trong Site Editor, rồi xuất kết quả ra dưới dạng biến CSS cộng một stylesheet inline trên mọi trang.

Nhầm lẫn giữa hai việc đó chính là lý do phần lớn chỉnh sửa theme.json trông như chẳng có tác dụng gì. Khai báo một màu trong settings không áp màu đó lên bất cứ đâu. Nó chỉ tạo ra một biến và một ô màu trong sidebar của editor.

Các khoá cấp cao nhất

Một file tối giản trông như sau:

{
  "$schema": "https://schemas.wp.org/trunk/theme.json",
  "version": 3,
  "settings": {},
  "styles": {},
  "templateParts": [],
  "customTemplates": []
}
KhoáNhiệm vụ
$schemaChỉ để code editor gợi ý và kiểm tra cú pháp. WordPress bỏ qua nó.
versionCho WordPress biết phân tích theo cấu trúc schema nào. Không phải version của theme.
settingsSinh ra biến CSS và quyết định editor mở ra những gì.
stylesÁp style mặc định thật sự.
templatePartsKhai báo các part trong parts/ và chúng thuộc khu vực nào.
customTemplatesĐăng ký page template trong templates/ cho post editor.

version hay làm người ta hiểu nhầm vì nó trông giống số phiên bản của theme. Không phải. Nó chọn chế độ phân tích, và các bản WordPress cũ sẽ lặng lẽ bỏ qua những khoá thuộc cấu trúc schema chúng không biết. Nếu bạn hỗ trợ các bản cài cũ, hãy nhắm đúng version mà chúng hiểu, thay vì tin rằng khoá mới sẽ tự thoái lui êm đẹp. Version 3 là bản hiện hành ở thời điểm viết bài; version 2 vẫn còn chạy rộng rãi và vẫn được phân tích.

$schema trỏ tới một URL schema do WordPress lưu trữ. Ghim nó vào trunk cho bạn gợi ý mới nhất trong code editor; còn URL gắn version cụ thể thì an toàn hơn nếu bạn cố tình ở lại schema cũ.

settings: editor mở ra những gì

Mọi thứ nằm dưới settings đều sinh ra một biến CSS và, trong đa số trường hợp, một control trong editor. Không có gì dưới settings tạo style cả.

{
  "settings": {
    "color": {
      "palette": [
        { "slug": "brand", "color": "#1f4ed8", "name": "Brand" },
        { "slug": "ink", "color": "#111827", "name": "Ink" }
      ],
      "custom": false
    },
    "typography": {
      "fontSizes": [
        { "slug": "small", "size": "0.875rem", "name": "Small" },
        { "slug": "large", "size": "1.5rem", "name": "Large" }
      ]
    },
    "layout": {
      "contentSize": "680px",
      "wideSize": "1200px"
    }
  }
}

Đoạn trên sinh ra các biến được đặt tên theo đường dẫn preset và slug:

--wp--preset--color--brand
--wp--preset--color--ink
--wp--preset--font-size--small
--wp--preset--font-size--large

Nó cũng sinh ra các class tiện ích như .has-brand-color.has-brand-background-color — đây chính là cách editor áp ô màu người dùng chọn lên một block.

Dòng "custom": false là nửa còn lại của settings: tắt bớt tuỳ chọn. Đặt nó thì bộ chọn màu tự do biến mất, người dùng chỉ còn bảng màu của bạn và không gì khác. Cùng một kiểu đó áp dụng cho mọi thứ — settings.typography.customFontSize, settings.spacing.customSpacingSize, settings.border, v.v. Không có khoá nào dưới settings chỉ để trang trí; mỗi khoá hoặc thêm một biến, hoặc thêm một control, hoặc bỏ một control.

settings.custom là một cái giỏ tự do cho biến của riêng bạn:

{
  "settings": {
    "custom": {
      "lineHeight": { "body": 1.6 },
      "shadow": { "card": "0 1px 3px rgba(0,0,0,0.12)" }
    }
  }
}

Chúng trở thành --wp--custom--line-height--body--wp--custom--shadow--card. Để ý cách biến đổi tên: khoá camelCase bị tách thành kebab-case, còn các cấp lồng nhau được nối bằng hai dấu gạch ngang. Gõ sai tên biến là một lý do rất hay gặp khiến giá trị lặng lẽ rơi về mặc định.

Bạn có thể giới hạn settings theo từng block, và đây là cách cho phép bộ chọn màu trên nút bấm nhưng không cho trên đoạn văn:

{
  "settings": {
    "blocks": {
      "core/paragraph": {
        "color": { "custom": false, "customGradient": false }
      }
    }
  }
}

styles: cái thật sự hiển thị

styles là nơi giá trị được áp dụng. Nó phản chiếu cấu trúc của editor: cấp gốc, rồi elements, rồi blocks.

{
  "styles": {
    "color": {
      "background": "var(--wp--preset--color--base)",
      "text": "var(--wp--preset--color--ink)"
    },
    "typography": {
      "lineHeight": "var(--wp--custom--line-height--body)"
    },
    "elements": {
      "link": {
        "color": { "text": "var(--wp--preset--color--brand)" },
        ":hover": { "typography": { "textDecoration": "none" } }
      }
    },
    "blocks": {
      "core/quote": {
        "typography": { "fontStyle": "italic" },
        "spacing": { "padding": { "left": "var(--wp--preset--spacing--40)" } }
      }
    }
  }
}

styles ở cấp gốc rơi xuống thẻ body. elements lo các phần tử HTML nguyên thuỷ vốn không phải block — link, button, heading, caption. blocks nhắm vào một loại block cụ thể theo tên.

Giới hạn cần nói thẳng: styles không diễn đạt được mọi thứ mà CSS làm được. Không có cách nào tự viết media query, không có selector phức tạp, không có animation, và chỉ hỗ trợ một tập nhỏ trạng thái pseudo-class. Fluid typography và cách chỉnh kích thước dựa trên layout thay được kha khá thứ mà trước đây người ta dùng breakpoint, nhưng không phải tất cả. Phần lớn block theme phát hành thật đều mang theo theme.json cộng một stylesheet nhỏ, và đó là kết quả bình thường chứ không phải thất bại.

Cái bẫy settings và styles

Câu hỏi hỗ trợ hay gặp nhất luôn là một biến thể của “tôi thêm màu thương hiệu rồi mà chẳng thấy đổi gì”.

Đúng vậy. Thêm nó vào settings.color.palette chỉ tạo ra --wp--preset--color--brand và một ô màu. Nó không áp gì cả. Muốn biến nó thành màu link mặc định, bạn phải viết thêm trong styles:

{
  "settings": {
    "color": {
      "palette": [{ "slug": "brand", "color": "#1f4ed8", "name": "Brand" }]
    }
  },
  "styles": {
    "elements": {
      "link": { "color": { "text": "var(--wp--preset--color--brand)" } }
    }
  }
}

Hiểu thế này: settings là hộp sơn bạn đưa cho người dùng, còn styles là lớp sơn bạn quét trước khi họ đến.

Cascade, từ thấp lên cao

Đây là phần giải thích vì sao một site trông như “phớt lờ” file theme. WordPress trộn nhiều lớp trước khi xuất CSS:

  1. Mặc định của WordPress core — core đi kèm theme.json riêng với bảng màu, cỡ chữ và thang spacing nền.
  2. theme.json của theme cha
  3. theme.json của child theme — trộn đè lên theme cha theo từng khoá, chứ không thay cả file.
  4. Global Styles lưu trong database — thứ mà panel Styles của Site Editor ghi ra.
  5. Style riêng trên từng block — các thuộc tính lưu trong nội dung bài viết, render thành style inline hoặc class.

Lớp 4 chính là lớp làm hỏng site. Ngay khi có người mở panel Styles và bấm lưu, WordPress lưu một bản ghi Global Styles, và bản ghi đó thắng file của bạn ở mọi thuộc tính nó chứa. Sửa theme.json sau đó không thay đổi gì nhìn thấy được với những thuộc tính này — site trông y hệt sau khi deploy trong khi file trên đĩa rõ ràng đã khác.

Cách sửa là xoá bản ghi đã lưu, chứ không phải leo thang bằng !important. Mở Site Editor, vào Styles, mở panel revisions, rồi reset về mặc định của theme. Hỏi khách hàng hoặc chủ site trước — việc reset sẽ xoá sạch tuỳ biến của họ, đó là một cái giá thật, không phải thao tác miễn phí.

Nghi phạm thứ hai là cache. WordPress cache lại dữ liệu theme.json đã phân tích thay vì đọc lại file ở mỗi request — đúng thứ bạn muốn trên production và đúng thứ bạn không muốn khi đang phát triển. Bật WP_DEBUG, hoặc bật chế độ theme development mode ở các bản mới hơn, sẽ khiến WordPress đọc lại file mỗi lần. Nếu chỉnh sửa của bạn chỉ hiện ra sau khi deploy hoặc xả cache, thì đây chính là thứ bạn đang gặp.

templateParts và customTemplates

Cả hai đều là mảng mô tả những file vốn đã nằm sẵn trong theme của bạn.

{
  "templateParts": [
    { "name": "header", "title": "Header", "area": "header" },
    { "name": "footer", "title": "Footer", "area": "footer" }
  ],
  "customTemplates": [
    { "name": "page-wide", "title": "Wide Page", "postTypes": ["page"] }
  ]
}

name khớp với tên file bỏ phần đuôi mở rộng — parts/header.html, templates/page-wide.html. Giá trị area rất quan trọng: nó quyết định part có được bọc trong phần tử landmark header hay footer không, và editor xếp part đó vào nhóm nào. Bỏ trống thì part bị coi là không phân loại.

customTemplates là thứ khiến một template xuất hiện trong dropdown chọn template ở post editor. Không có mục này, file vẫn tồn tại nhưng không ai chọn được.

Thứ tự chẩn đoán nhanh

Khi một block theme không lên style đúng như file khai báo, hãy đi qua các bước sau trước khi đụng vào bất cứ thứ gì:

  1. Xem source và tìm khối global styles được sinh ra. Nếu biến của bạn không có ở đó, vấn đề nằm ở settings hoặc gõ sai slug.
  2. Nếu biến có mà không được dùng, vấn đề là thiếu mục trong styles.
  3. Nếu cả hai đều có mà vẫn bị thứ gì đó đè, hãy kiểm tra xem có bản ghi Global Styles đã lưu không.
  4. Chỉ sau đó mới ngó tới stylesheet của bạn, các plugin, hoặc một page builder chèn CSS vào sau trong cascade.

FAQ

Câu hỏi

theme.json trong WordPress là gì?

Đó là một file cấu hình JSON duy nhất nằm ở thư mục gốc của block theme, kiểm soát hai thứ: block editor mở ra những tuỳ chọn thiết kế nào cho người dùng, và style mặc định là gì. WordPress đọc file này, sinh ra các biến CSS cùng một stylesheet từ nó, rồi trộn với mặc định của core và mọi Global Styles mà người dùng đã lưu.

settings và styles trong theme.json khác nhau ở chỗ nào?

settings khai báo cái gì có sẵn, sinh ra biến CSS và các control trong editor, nhưng tự nó không áp dụng gì cả. styles mới là nơi gán giá trị thật, dùng chính các biến đó. Thêm một màu vào bảng màu sẽ không đổi bất kỳ phần tử nào cho tới khi bạn tham chiếu nó trong styles hoặc người dùng tự chọn nó trong editor.

Vì sao chỉnh theme.json mà ngoài front end không thấy đổi gì?

Gần như luôn là do Global Styles đã lưu trong database đè lên theme.json. Chỉ cần một người mở panel Styles trong Site Editor và bấm lưu, bản ghi đó thắng file của bạn với mọi thuộc tính nó chứa. Vào Styles, dùng panel revisions để reset về mặc định của theme, rồi tải lại trang. Nghi phạm thứ hai là cache của dữ liệu theme.json đã được phân tích.

Có theme.json rồi thì còn cần file style.css nữa không?

Có. WordPress bắt buộc phải có style.css để đọc khối comment header chứa tên theme, phiên bản và các metadata khác, nếu không theme sẽ không được nhận diện. Bạn có thể để file đó trống và đưa toàn bộ quyết định thiết kế vào theme.json, hoặc giữ lại một ít CSS cho những thứ theme.json không diễn đạt được.

Nên đặt số version nào cho theme.json?

Dùng version cao nhất mà bản WordPress thấp nhất bạn hỗ trợ hiểu được. Khoá version cho WordPress biết cần phân tích theo cấu trúc schema nào, và các bản WordPress cũ sẽ bỏ qua những khoá chúng không nhận ra. Nếu bạn nhắm tới các bản cài cũ, hãy giữ đúng version chúng hỗ trợ thay vì tin rằng khoá mới sẽ tự động thoái lui êm đẹp.

theme.json có thay thế hoàn toàn CSS không?

Không. Nó lo tốt phần preset, mặc định cho block, style cho element, chiều rộng layout và spacing, nhưng nó không có khái niệm media query do bạn tự viết, không có selector phức tạp, không có animation và chỉ hỗ trợ một nhúm trạng thái pseudo-class. Phần lớn block theme chạy thật ngoài đời đều đi kèm theme.json cộng thêm một stylesheet nhỏ cho phần còn lại.