WordPress 中常说的“自定义分类”实际包含两个概念:自定义文章类型(Custom Post Type)和自定义分类法(Custom Taxonomy)。文章类型定义内容实体,分类法定义内容如何分组,两者应分别注册。
下面以“产品”和“产品分类”为例。代码更适合放在站点专用插件中,而不是主题的 functions.php;切换主题不应该让业务内容类型消失。
注册文章类型
<?php
add_action(
'init',
function (): void {
register_post_type(
'acme_product',
array(
'labels' => array(
'name' => '产品',
'singular_name' => '产品',
'add_new_item' => '添加产品',
'edit_item' => '编辑产品',
),
'public' => true,
'has_archive' => true,
'rewrite' => array(
'slug' => 'products',
'with_front' => false,
),
'show_in_rest' => true,
'menu_icon' => 'dashicons-products',
'supports' => array(
'title',
'editor',
'excerpt',
'thumbnail',
'revisions',
),
)
);
}
);
文章类型 key 最长 20 个字符,并应使用项目或组织前缀,避免与主题、插件冲突。
注册分层分类法
<?php
add_action(
'init',
function (): void {
register_taxonomy(
'acme_product_category',
array( 'acme_product' ),
array(
'labels' => array(
'name' => '产品分类',
'singular_name' => '产品分类',
'add_new_item' => '添加产品分类',
'edit_item' => '编辑产品分类',
),
'public' => true,
'hierarchical' => true,
'show_admin_column' => true,
'show_in_rest' => true,
'rewrite' => array(
'slug' => 'product-category',
'with_front' => false,
'hierarchical' => true,
),
)
);
}
);
hierarchical => true 表示像分类目录一样支持父子层级;设为 false 时更接近标签。
固定链接只刷新一次
注册或修改 rewrite 规则后需要刷新固定链接,但不能在每次请求调用 flush_rewrite_rules()。插件应只在激活和停用时处理:
<?php
function acme_register_content_types(): void {
// 把上面的 register_post_type 和
// register_taxonomy 调用提取到此函数。
}
register_activation_hook(
__FILE__,
function (): void {
acme_register_content_types();
flush_rewrite_rules();
}
);
register_deactivation_hook(
__FILE__,
'flush_rewrite_rules'
);
挂到 init 的回调也调用同一个注册函数。不要复制两份注册参数,否则以后会出现激活逻辑和运行逻辑不一致。
权限、REST 与归档
public、publicly_queryable、show_ui和show_in_menu含义不同,内部数据不应只靠隐藏菜单保护。- 使用区块编辑器或 REST API 时通常需要
show_in_rest => true。 - 自定义权限模型要配置
capability_type、capabilities和map_meta_cap,并在业务操作中再次调用current_user_can()。 has_archive决定文章类型归档;taxonomy 则有自己的 term 归档链接。- slug 变更会影响已收录 URL,应配置 301 重定向并检查 canonical、站点地图和内链。