Khi một website có nhiều nội dung cùng loại, bạn cần một trục để gom nhóm và lọc chúng. Danh mục bài viết mặc định nhanh chóng trở nên chật chội. Taxonomy tuỳ biến giải quyết đúng việc đó: tạo ra một hệ thống phân loại riêng, tách bạch với category sẵn có, và gắn thẳng vào kiểu nội dung của bạn.
Taxonomy là gì và khác custom post type ra sao
Trong WordPress, taxonomy (hệ phân loại — cách nhóm nội dung) là cơ chế để gom các bản ghi lại với nhau. Bản thân WordPress đã có hai taxonomy mặc định: category (danh mục, phân cấp) và post_tag (thẻ, phẳng).
Cần phân biệt rạch ròi hai khái niệm hay bị nhầm:
- Custom post type (CPT — kiểu nội dung tuỳ biến) là bản thân nội dung: một sản phẩm, một dự án, một sự kiện. Mỗi bản ghi là một trang riêng.
- Custom taxonomy là nhãn để phân loại những nội dung đó: “thương hiệu”, “ngành nghề”, “khu vực”. Mỗi nhãn (gọi là term — thuật ngữ phân loại) gom nhiều bản ghi lại.
Ví dụ dễ hình dung: nếu “Sản phẩm” là một CPT, thì “Thương hiệu” và “Màu sắc” là các taxonomy gắn vào nó. Bạn không tạo một CPT cho từng thương hiệu — bạn tạo các term trong taxonomy “Thương hiệu”.

Đăng ký taxonomy cơ bản với register_taxonomy
Hàm chuẩn để tạo taxonomy là register_taxonomy(), gọi trong hook init. Theo tài liệu chính thức của WordPress, tuyệt đối không gọi hàm này trước hook init, nếu không taxonomy có thể không đăng ký đúng. Đặt code trong một plugin nhỏ là cách bền nhất, để khi đổi giao diện thì dữ liệu phân loại không biến mất.
function w22_register_thuong_hieu_taxonomy() {
$labels = array(
'name' => _x( 'Thương hiệu', 'taxonomy general name', 'w22' ),
'singular_name' => _x( 'Thương hiệu', 'taxonomy singular name', 'w22' ),
'menu_name' => __( 'Thương hiệu', 'w22' ),
'all_items' => __( 'Tất cả thương hiệu', 'w22' ),
'add_new_item' => __( 'Thêm thương hiệu', 'w22' ),
);
$args = array(
'labels' => $labels,
'hierarchical' => true,
'public' => true,
'show_admin_column' => true,
'show_in_rest' => true,
'rewrite' => array( 'slug' => 'thuong-hieu' ),
);
register_taxonomy( 'w22_thuong_hieu', array( 'product' ), $args );
}
add_action( 'init', 'w22_register_thuong_hieu_taxonomy' );Vài điểm quan trọng trong đoạn trên:
- Tham số đầu là tên taxonomy (tối đa 32 ký tự, chỉ chữ thường, gạch dưới). Nên thêm tiền tố riêng (ở đây là
w22_) để tránh đụng tên với plugin khác. - Tham số thứ hai là object_type — kiểu nội dung mà taxonomy gắn vào. Truyền mảng nếu muốn gắn nhiều kiểu cùng lúc.
show_admin_column => truehiện thêm một cột phân loại ngay trên màn hình danh sách bản ghi, rất tiện khi quản trị.
Hierarchical hay flat — chọn đúng kiểu
Quyết định lớn nhất nằm ở tham số hierarchical. Mặc định của nó là false.
| Đặc điểm | hierarchical = true (như category) | hierarchical = false (như tag) |
|---|---|---|
| Quan hệ cha–con | Có, term lồng nhiều cấp | Không, danh sách phẳng |
| Giao diện nhập liệu | Ô tick (checkbox) | Ô gõ tự do, ngăn cách dấu phẩy |
| Hợp với | Ngành nghề, khu vực, danh mục sản phẩm | Từ khoá, đặc điểm, tag mô tả |
Để tạo một taxonomy phẳng kiểu thẻ, chỉ cần đổi đúng một dòng:
$args = array(
'labels' => $labels,
'hierarchical' => false,
'public' => true,
'show_in_rest' => true,
'rewrite' => array( 'slug' => 'tinh-nang' ),
);
register_taxonomy( 'w22_tinh_nang', array( 'product' ), $args );Nguyên tắc thực tế: nếu các nhãn cần lồng vào nhau (Miền Bắc > Hà Nội), chọn phân cấp. Nếu chỉ là một rổ từ khoá ngang hàng, chọn phẳng.
show_in_rest — điều kiện để chạy trong block editor
Đây là điểm dễ vấp nhất. Nếu thiếu show_in_rest => true, taxonomy sẽ không hiện trong block editor (trình soạn thảo khối — Gutenberg). Người dùng mở bài ra mà không thấy ô chọn thương hiệu đâu cả, dù taxonomy đã đăng ký đúng. Tài liệu WordPress nêu rõ: bật cờ này để taxonomy có mặt trong REST API và sẵn sàng cho block editor.
Đây cũng là một khác biệt so với việc gắn taxonomy vào một custom post type tạo bằng code: ở CPT bạn lo cờ show_in_rest cho cả màn hình soạn thảo, còn ở taxonomy nó quyết định riêng panel phân loại bên thanh bên phải. Cả hai phải cùng bật thì luồng nhập liệu mới mượt.
Gắn taxonomy vào CPT một cách tách rời
Bạn có thể khai báo taxonomies ngay khi đăng ký post type, nhưng cách linh hoạt hơn là gắn riêng bằng register_taxonomy_for_object_type(). Cách này cho phép gắn taxonomy vào một kiểu nội dung do plugin khác tạo ra, mà không phải sửa code của plugin đó:
add_action( 'init', function () {
register_taxonomy_for_object_type( 'w22_thuong_hieu', 'product' );
}, 20 );Đặt độ ưu tiên 20 để chắc chắn cả post type lẫn taxonomy đã đăng ký xong trước khi nối chúng lại.
Thêm term meta cho mỗi nhãn phân loại
Term meta (dữ liệu phụ của term — trường thông tin gắn vào từng nhãn) cho phép mỗi term mang thêm dữ liệu riêng: một mã màu, một logo, một đường dẫn. Đăng ký bằng register_term_meta(), cũng trong hook init:
add_action( 'init', function () {
register_term_meta( 'w22_thuong_hieu', 'w22_website', array(
'type' => 'string',
'single' => true,
'show_in_rest' => true,
'sanitize_callback' => 'esc_url_raw',
) );
} );Khai báo này cho WordPress biết kiểu dữ liệu, hàm làm sạch (sanitize_callback — lọc giá trị trước khi lưu), và việc có lộ ra REST API hay không. Để người quản trị nhập được giá trị, thêm một ô vào màn hình sửa term qua hook {$taxonomy}_edit_form_fields và lưu lại bằng edited_{$taxonomy}:
add_action( 'w22_thuong_hieu_edit_form_fields', function ( $term ) {
$value = get_term_meta( $term->term_id, 'w22_website', true );
?>
<tr class="form-field">
<th><label for="w22_website">Website</label></th>
<td><input name="w22_website" id="w22_website" type="url"
value="<?php echo esc_attr( $value ); ?>" /></td>
</tr>
<?php
} );
add_action( 'edited_w22_thuong_hieu', function ( $term_id ) {
if ( isset( $_POST['w22_website'] ) ) {
update_term_meta( $term_id, 'w22_website',
esc_url_raw( wp_unslash( $_POST['w22_website'] ) ) );
}
} );Trong thực tế tự code plugin web22-core, Web22 thường gắn term meta để mỗi nhãn mang theo logo hoặc đường dẫn, rồi gọi get_term_meta() ra ngoài giao diện. Nhờ show_in_rest => true, giá trị này cũng hiện trong dữ liệu API của term.

Lưu ý sau khi đăng ký
Sau khi thêm taxonomy mới, đường dẫn đẹp (permalink) chưa hoạt động ngay. Vào Cài đặt > Đường dẫn tĩnh và lưu lại một lần để WordPress nạp lại quy tắc rewrite. Nếu trang lưu trữ term báo lỗi 404, gần như chắc chắn là do bước này bị bỏ qua.
Câu hỏi thường gặp
Một taxonomy có gắn được vào nhiều post type không?
Được. Truyền một mảng các post type vào tham số thứ hai của register_taxonomy, hoặc dùng register_taxonomy_for_object_type để gắn thêm sau.
Đổi từ hierarchical sang flat sau này có mất dữ liệu không?
Các term đã tạo vẫn còn, nhưng quan hệ cha–con sẽ không còn ý nghĩa ở chế độ phẳng. Nên chốt kiểu phân loại từ đầu để tránh phải dọn dẹp về sau.
Vì sao taxonomy không hiện trong trình soạn thảo?
Khả năng cao là thiếu show_in_rest => true. Block editor đọc taxonomy qua REST API, nên cờ này là bắt buộc.
Nếu bạn cần một hệ phân loại phức tạp gắn vào dữ liệu riêng và muốn nó bền vững qua các lần đổi giao diện, dịch vụ lập trình WordPress theo yêu cầu của Web22 có thể dựng phần khung dữ liệu này gọn gàng trong một plugin riêng.
