register_taxonomy()
云策文档标注
概述
register_taxonomy() 函数用于在 WordPress 中创建或修改分类法对象,需在 'init' 钩子后调用。它接受分类法键名、关联的对象类型和参数数组,返回 WP_Taxonomy 对象或 WP_Error。
关键要点
- 分类法键名($taxonomy)必须不超过 32 字符,仅包含小写字母、数字、破折号和下划线,避免与保留词冲突。
- 对象类型($object_type)可以是内置或自定义文章类型,设为 null 时不自动关联,需手动注册。
- 参数($args)控制分类法的行为,如标签、公开性、层级结构、REST API 集成和重写规则。
- 重要参数包括:hierarchical(默认 false)、public(默认 true)、show_in_rest(用于 Gutenberg 编辑器)、rewrite(控制 URL 重写)和 capabilities(权限设置)。
- 注册后需注意:避免在 'init' 钩子前调用,修改现有分类法会覆盖 $object_type,注册顺序可能影响重写规则。
代码示例
function wpdocs_create_book_taxonomies() {
// 注册分层分类法(如分类)
$labels = array(
'name' => _x( 'Genres', 'taxonomy general name', 'textdomain' ),
'singular_name' => _x( 'Genre', 'taxonomy singular name', 'textdomain' ),
// 其他标签...
);
$args = array(
'hierarchical' => true,
'labels' => $labels,
'show_ui' => true,
'show_admin_column' => true,
'query_var' => true,
'rewrite' => array( 'slug' => 'genre' ),
'show_in_rest' => true, // 支持 Gutenberg
);
register_taxonomy( 'genre', 'book', $args );
// 注册非分层分类法(如标签)
$labels2 = array(
'name' => _x( 'Writers', 'taxonomy general name', 'textdomain' ),
'singular_name' => _x( 'Writer', 'taxonomy singular name', 'textdomain' ),
// 其他标签...
);
$args2 = array(
'hierarchical' => false,
'labels' => $labels2,
'show_ui' => true,
'show_admin_column' => true,
'query_var' => true,
'rewrite' => array( 'slug' => 'writer' ),
);
register_taxonomy( 'writer', 'book', $args2 );
}
add_action( 'init', 'wpdocs_create_book_taxonomies', 0 );注意事项
- 使用 Gutenberg 编辑器时,设置 show_in_rest 为 true 以在侧边栏显示分类法面板,但 meta_box_cb 参数不受支持。
- 为附件注册分类法时,可能需要设置 update_count_callback 为 '_update_generic_term_count' 以确保计数正确。
- 避免使用保留词作为分类法键名或 query_var,否则可能导致前端查询问题或 404 错误。
- 注册顺序:若需在 URL 中包含自定义文章类型 slug,应先注册分类法再注册文章类型。
- 分类法名称应仅使用小写字母和下划线,大写字母或连字符可能导致意外行为。
原文内容
Creates or modifies a taxonomy object.
Description
Note: Do not use before the ‘init’ hook.
A simple function for creating or modifying a taxonomy object based on the parameters given. If modifying an existing taxonomy object, note that the $object_type value from the original registration will be overwritten.
Parameters
$taxonomystringrequired-
Taxonomy key. Must not exceed 32 characters and may only contain lowercase alphanumeric characters, dashes, and underscores. See sanitize_key() .
$object_typearray|stringrequired-
Object type or array of object types with which the taxonomy should be associated.
$argsarray|stringoptional-
Array or query string of arguments for registering a taxonomy.
labelsstring[]An array of labels for this taxonomy. By default, Tag labels are used for non-hierarchical taxonomies, and Category labels are used for hierarchical taxonomies. See accepted values in get_taxonomy_labels() .descriptionstringA short descriptive summary of what the taxonomy is for.publicboolWhether a taxonomy is intended for use publicly either via the admin interface or by front-end users. The default settings of$publicly_queryable,$show_ui, and$show_in_nav_menusare inherited from$public.publicly_queryableboolWhether the taxonomy is publicly queryable.
If not set, the default is inherited from$publichierarchicalboolWhether the taxonomy is hierarchical. Default false.show_uiboolWhether to generate and allow a UI for managing terms in this taxonomy in the admin. If not set, the default is inherited from$public(default true).show_in_menuboolWhether to show the taxonomy in the admin menu. If true, the taxonomy is shown as a submenu of the object type menu. If false, no menu is shown.
$show_uimust be true. If not set, default is inherited from$show_ui(default true).show_in_nav_menusboolMakes this taxonomy available for selection in navigation menus. If not set, the default is inherited from$public(default true).show_in_restboolWhether to include the taxonomy in the REST API. Set this to true for the taxonomy to be available in the block editor.rest_basestringTo change the base url of REST API route. Default is $taxonomy.rest_namespacestringTo change the namespace URL of REST API route. Default is wp/v2.rest_controller_classstringREST API Controller class name. Default is ‘WP_REST_Terms_Controller‘.show_tagcloudboolWhether to list the taxonomy in the Tag Cloud Widget controls. If not set, the default is inherited from$show_ui(default true).show_in_quick_editboolWhether to show the taxonomy in the quick/bulk edit panel. It not set, the default is inherited from$show_ui(default true).show_admin_columnboolWhether to display a column for the taxonomy on its post type listing screens. Default false.meta_box_cbbool|callableProvide a callback function for the meta box display. If not set, post_categories_meta_box() is used for hierarchical taxonomies, and post_tags_meta_box() is used for non-hierarchical. If false, no meta box is shown.meta_box_sanitize_cbcallableCallback function for sanitizing taxonomy data saved from a meta box. If no callback is defined, an appropriate one is determined based on the value of$meta_box_cb.capabilitiesstring[]Array of capabilities for this taxonomy.manage_termsstringDefault'manage_categories'.edit_termsstringDefault'manage_categories'.delete_termsstringDefault'manage_categories'.assign_termsstringDefault'edit_posts'.rewritebool|arrayTriggers the handling of rewrites for this taxonomy. Default true, using $taxonomy as slug. To prevent rewrite, set to false. To specify rewrite rules, an array can be passed with any of these keys:slugstringCustomize the permastruct slug. Default$taxonomykey.with_frontboolShould the permastruct be prepended with WP_Rewrite::$front. Default true.hierarchicalboolEither hierarchical rewrite tag or not. Default false.ep_maskintAssign an endpoint mask. DefaultEP_NONE.query_varstring|boolSets the query var key for this taxonomy. Default$taxonomykey. If false, a taxonomy cannot be loaded at?{query_var}={term_slug}. If a string, the query?{query_var}={term_slug}will be valid.update_count_callbackcallableWorks much like a hook, in that it will be called when the count is updated. Default _update_post_term_count() for taxonomies attached to post types, which confirms that the objects are published before counting them. Default _update_generic_term_count() for taxonomies attached to other object types, such as users.default_termstring|arrayDefault term to be used for the taxonomy.namestringName of default term.slugstringSlug for default term.descriptionstringDescription for default term.sortboolWhether terms in this taxonomy should be sorted in the order they are provided towp_set_object_terms(). Default null which equates to false.argsarrayArray of arguments to automatically use insidewp_get_object_terms()for this taxonomy._builtinboolThis taxonomy is a “built-in” taxonomy. INTERNAL USE ONLY! Default false.
Default:
array()Source
function register_taxonomy( $taxonomy, $object_type, $args = array() ) { global $wp_taxonomies; if ( ! is_array( $wp_taxonomies ) ) { $wp_taxonomies = array(); } $args = wp_parse_args( $args ); if ( empty( $taxonomy ) || strlen( $taxonomy ) > 32 ) { _doing_it_wrong( __FUNCTION__, __( 'Taxonomy names must be between 1 and 32 characters in length.' ), '4.2.0' ); return new WP_Error( 'taxonomy_length_invalid', __( 'Taxonomy names must be between 1 and 32 characters in length.' ) ); } $taxonomy_object = new WP_Taxonomy( $taxonomy, $object_type, $args ); $taxonomy_object->add_rewrite_rules(); $wp_taxonomies[ $taxonomy ] = $taxonomy_object; $taxonomy_object->add_hooks(); // Add default term. if ( ! empty( $taxonomy_object->default_term ) ) { $term = term_exists( $taxonomy_object->default_term['name'], $taxonomy ); if ( $term ) { update_option( 'default_term_' . $taxonomy_object->name, $term['term_id'] ); } else { $term = wp_insert_term( $taxonomy_object->default_term['name'], $taxonomy, array( 'slug' => sanitize_title( $taxonomy_object->default_term['slug'] ), 'description' => $taxonomy_object->default_term['description'], ) ); // Update `term_id` in options. if ( ! is_wp_error( $term ) ) { update_option( 'default_term_' . $taxonomy_object->name, $term['term_id'] ); } } } /** * Fires after a taxonomy is registered. * * @since 3.3.0 * * @param string $taxonomy Taxonomy slug. * @param array|string $object_type Object type or array of object types. * @param array $args Array of taxonomy registration arguments. */ do_action( 'registered_taxonomy', $taxonomy, $object_type, (array) $taxonomy_object ); /** * Fires after a specific taxonomy is registered. * * The dynamic portion of the filter name, `$taxonomy`, refers to the taxonomy key. * * Possible hook names include: * * - `registered_taxonomy_category` * - `registered_taxonomy_post_tag` * * @since 6.0.0 * * @param string $taxonomy Taxonomy slug. * @param array|string $object_type Object type or array of object types. * @param array $args Array of taxonomy registration arguments. */ do_action( "registered_taxonomy_{$taxonomy}", $taxonomy, $object_type, (array) $taxonomy_object ); return $taxonomy_object; }Hooks
- do_action( ‘registered_taxonomy’, string $taxonomy, array|string $object_type, array $args )
-
Fires after a taxonomy is registered.
- do_action( “registered_taxonomy_{$taxonomy}”, string $taxonomy, array|string $object_type, array $args )
-
Fires after a specific taxonomy is registered.
Changelog
Version Description 5.9.0 Introduced rest_namespaceargument.5.5.0 Introduced default_termargument.5.4.0 Added the registered taxonomy object as a return value. 5.1.0 Introduced meta_box_sanitize_cbargument.4.7.0 Introduced show_in_rest,'rest_base'and'rest_controller_class'arguments to register the taxonomy in REST API.4.5.0 Introduced publicly_queryableargument.4.4.0 The publicargument now controls whether the taxonomy can be queried on the front end.4.2.0 Introduced show_in_quick_editargument.2.3.0 Introduced. User Contributed Notes
You must log in before being able to contribute a note or feedback.
Skip to note 17 content
Amir Arabnezhad
If you want your taxonomy panel to be visible at the sidebar of the block editor, you should set
show_in_resttotrue.Skip to note 18 content
Matt Radford
In order to have a taxonomy appear in the URL hierarchy of the relevant CPT, you can rewrite the taxonomy slug to contain the CPT’s slug. But you must register the CPT after registering the taxonomy, otherwise the rewrite will not work, i.e. in this case, book CPT must be registered after genre taxonomy.
HT: https://cnpagency.com/blog/the-right-way-to-do-wordpress-custom-taxonomy-rewrites/
/** * Register a 'genre' taxonomy for post type 'book', with a rewrite to match book CPT slug. * * @see register_post_type for registering post types. */ function wpdocs_create_book_tax_rewrite() { register_taxonomy( 'genre', 'book', array( 'rewrite' => array( 'slug' => 'books/genre' ) ) ); } add_action( 'init', 'wpdocs_create_book_tax_rewrite', 0 );Skip to note 19 content
Timo Tijhof
Be careful not to use a reserved word for
slug,query_varor$taxonomy name. See WP_Query for a list of them.This includes words like “author”. If you attempt to use “author” as a taxonomy and/or override the default
slugorquery_varof a custom taxonomy to match these words, they will not work correctly.The administration will be fine (a menu is shown, terms can be created and associated etc.). But the front-end will not work correctly. For example a url `https://example.org/author/name`, should probably display no results (if it is looking for post authors, instead of your taxonomy). But instead, it seems to first try both during the rewrite matching, but then the actual query filters neither. End result the query is empty and matches all results, and WordPress displays your home page (not even `archive.php`).
As of WordPress 4.9.5, there is no warning for this when you accidentally use one of these words.
Skip to note 20 content
Boone Gorges
Note that the taxonomy name – the
$taxonomyparam above – should include only the charactersa-z0-9_. It may appear to work when you register a taxonomy that has, say, a capital letter. But there are various places in WP where the taxonomy slug is run throughsanitize_key()– such as during AJAX tag searches – which will lead to subtle sorts of breakage.Skip to note 21 content
Codex
Registering two taxonomies for a post type
This example registers two taxonomies, genres and writers, for the post type called “book”.
Note: You can define custom taxonomies in a theme’s
functions.phptemplate file:/** * Create two taxonomies, genres and writers for the post type "book". * * @see register_post_type() for registering custom post types. */ function wpdocs_create_book_taxonomies() { // Add new taxonomy, make it hierarchical (like categories) $labels = array( 'name' => _x( 'Genres', 'taxonomy general name', 'textdomain' ), 'singular_name' => _x( 'Genre', 'taxonomy singular name', 'textdomain' ), 'search_items' => __( 'Search Genres', 'textdomain' ), 'all_items' => __( 'All Genres', 'textdomain' ), 'parent_item' => __( 'Parent Genre', 'textdomain' ), 'parent_item_colon' => __( 'Parent Genre:', 'textdomain' ), 'edit_item' => __( 'Edit Genre', 'textdomain' ), 'update_item' => __( 'Update Genre', 'textdomain' ), 'add_new_item' => __( 'Add New Genre', 'textdomain' ), 'new_item_name' => __( 'New Genre Name', 'textdomain' ), 'menu_name' => __( 'Genre', 'textdomain' ), ); $args = array( 'hierarchical' => true, 'labels' => $labels, 'show_ui' => true, 'show_admin_column' => true, 'query_var' => true, 'rewrite' => array( 'slug' => 'genre' ), ); register_taxonomy( 'genre', array( 'book' ), $args ); unset( $args ); unset( $labels ); // Add new taxonomy, NOT hierarchical (like tags) $labels = array( 'name' => _x( 'Writers', 'taxonomy general name', 'textdomain' ), 'singular_name' => _x( 'Writer', 'taxonomy singular name', 'textdomain' ), 'search_items' => __( 'Search Writers', 'textdomain' ), 'popular_items' => __( 'Popular Writers', 'textdomain' ), 'all_items' => __( 'All Writers', 'textdomain' ), 'parent_item' => null, 'parent_item_colon' => null, 'edit_item' => __( 'Edit Writer', 'textdomain' ), 'update_item' => __( 'Update Writer', 'textdomain' ), 'add_new_item' => __( 'Add New Writer', 'textdomain' ), 'new_item_name' => __( 'New Writer Name', 'textdomain' ), 'separate_items_with_commas' => __( 'Separate writers with commas', 'textdomain' ), 'add_or_remove_items' => __( 'Add or remove writers', 'textdomain' ), 'choose_from_most_used' => __( 'Choose from the most used writers', 'textdomain' ), 'not_found' => __( 'No writers found.', 'textdomain' ), 'menu_name' => __( 'Writers', 'textdomain' ), ); $args = array( 'hierarchical' => false, 'labels' => $labels, 'show_ui' => true, 'show_admin_column' => true, 'update_count_callback' => '_update_post_term_count', 'query_var' => true, 'rewrite' => array( 'slug' => 'writer' ), ); register_taxonomy( 'writer', 'book', $args ); } // hook into the init action and call create_book_taxonomies when it fires add_action( 'init', 'wpdocs_create_book_taxonomies', 0 );Skip to note 22 content
Codex
Example Private Taxonomy
If you do not want your taxonomy to be exposed publicly, you can use the
publicandrewriteparameters to suppress it. It will be available to use internally by your plugin or theme, but will not generate a url of it’s own./** * Register a private 'Genre' taxonomy for post type 'book'. * * @see register_post_type() for registering post types. */ function wpdocs_register_private_taxonomy() { $args = array( 'label' => __( 'Genre', 'textdomain' ), 'public' => false, 'rewrite' => false, 'hierarchical' => true ); register_taxonomy( 'genre', 'book', $args ); } add_action( 'init', 'wpdocs_register_private_taxonomy', 0 );Skip to note 23 content
dominicmarcelino
NOTE: The ‘meta_box_cb’ argument is not supported with Gutenberg editor
Skip to note 24 content
Anastis Sourgoutsidis
The statement: If you want to ensure that your custom taxonomy behaves like a tag, you must add the option
'update_count_callback' => '_update_post_term_count'is no longer true, at least as of version 4.6.1, perhaps even earlier.Simply declaring a taxonomy as non-hierarchical, behaves exactly like a tag.
Skip to note 25 content
Sean Leavey
Note two undocumented configuration arguments of `register_taxonomy` (the `$args` array keys): `sort` and `args`. Setting `sort` to `true` will have WordPress retain the order in which terms are added to objects. Setting `args` lets you specify an array of configuration parameters that, when present, override corresponding parameters in the `$args` array passed to `wp_get_object_terms` when using that function to query for terms in the specified taxonomy. This allows the order of terms to be displayed in the order they were defined in the editor.
The bug presented in ticket #40496 (https://core.trac.wordpress.org/ticket/40496) introduced these undocumented features to me.
Skip to note 26 content
Christopher Norman
For registering a custom taxonomy (with hierarchical set to true), and wanting all the labels options set – and Gutenberg editor ready (show_in_rest => true). Here is the code.
function register_custom_taxonomy() { $labels = array( 'name' => _x( 'Genres', 'taxonomy general name', 'textdomain' ), 'singular_name' => _x( 'Genre', 'taxonomy singular name', 'textdomain' ), 'search_items' => __( 'Search Genres', 'textdomain' ), 'all_items' => __( 'All Genres', 'textdomain' ), 'view_item' => __( 'View Genre', 'textdomain' ), 'parent_item' => __( 'Parent Genre', 'textdomain' ), 'parent_item_colon' => __( 'Parent Genre:', 'textdomain' ), 'edit_item' => __( 'Edit Genre', 'textdomain' ), 'update_item' => __( 'Update Genre', 'textdomain' ), 'add_new_item' => __( 'Add New Genre', 'textdomain' ), 'new_item_name' => __( 'New Genre Name', 'textdomain' ), 'not_found' => __( 'No Genres Found', 'textdomain' ), 'back_to_items' => __( 'Back to Genres', 'textdomain' ), 'menu_name' => __( 'Genre', 'textdomain' ), ); $args = array( 'labels' => $labels, 'hierarchical' => true, 'public' => true, 'show_ui' => true, 'show_admin_column' => true, 'query_var' => true, 'rewrite' => array( 'slug' => 'genre' ), 'show_in_rest' => true, ); register_taxonomy( 'genre', 'book', $args ); }Skip to note 27 content
Dilip Gupta
If you want to use the dynamic capabilities for taxonomy to be displayed and managed from frontend then append the ‘capabilities’ key with the array like below.
/** * Register a 'genre' taxonomy for post type 'book'. * * Register custom capabilities for taxonomies. * * @see register_post_type for registering post types. */ function wpdocs_create_book_tax() { register_taxonomy( 'genre', 'book', array( 'label' => __( 'Genre', 'textdomain' ), 'rewrite' => array( 'slug' => 'genre' ), 'hierarchical' => true, 'capabilities' => array( // $taxonomy['slug'] = genre; 'manage_terms' => 'manage_'.$taxonomy['slug'], 'edit_terms' => 'edit_'.$taxonomy['slug'], 'delete_terms' => 'delete'.$taxonomy['slug'], 'assign_terms' => 'assign_'.$taxonomy['slug'], ), ) ); } add_action( 'init', 'wpdocs_create_book_tax', 0 );Skip to note 28 content
leemon
Since Gutenberg 13.3 (and WP 6.1), a post term block variation is generated for each registered custom taxonomy. For example, if you register a “Product category” taxonomy, you should able to add a “Product categories” block that lists all the product category terms assigned to the current post.
But, currently, for the post term block variation automatic generation to work you need to register the custom taxonomies earlier in the process (a priority lower than 10).
Example:
add_action( 'init', 'wpdocs_register_taxonomies', 9 );Skip to note 29 content
Oberon Lai
Registering multiple taxonomies in array for specific post type.
function add_post_taxonomy() { $taxArray = array( array( "taxName" => 'tax中文名1', "taxNameEn" =>'taxSlu1' ), array( "taxName" => 'tax中文名2', "taxNameEn" =>'taxSlu2' ), ); foreach ($taxArray as $tax) { $labels = array( "name" => __( "", "" ), "singular_name" => __( $tax['taxName'], "" ), "menu_name" => __( $tax['taxName'], "" ), "all_items" => __( "所有", "" ), "edit_item" => __( "編輯", "" ), "view_item" => __( "檢視", "" ), "update_item" => __( "更新", "" ), "add_new_item" => __( "新增", "" ), "new_item_name" => __( "新增", "" ), "search_items" => __( "搜尋", "" ), ); $args = array( "label" => __( $tax['taxName'], "" ), "labels" => $labels, "public" => true, "hierarchical" => true, "label" => $tax['taxName'], "show_ui" => true, "show_in_menu" => true, "show_in_nav_menus" => true, "show_admin_column" => true, "query_var" => true, "rewrite" => array( 'slug' => $tax['taxNameEn'], 'with_front' => true, ), "show_admin_column" => true, "show_in_rest" => false, "rest_base" => $tax['taxNameEn'], "show_in_quick_edit" => true, ); register_taxonomy( $tax['taxNameEn'], 'post', $args ); } } add_action( 'init', 'add_post_taxonomy' );Skip to note 30 content
Florian
To hide a taxonomy metabox when using Gutenberg you must enqueue a script in admin that does this:
wp.data.dispatch( 'core/edit-post').removeEditorPanel( 'taxonomy-panel-[taxonomy_key]' );Replace
[taxonomy_key]with your taxonomy key.Skip to note 31 content
ramon fincken
As per https://core.trac.wordpress.org/ticket/41813 if you use this to add a custom taxonomy to media/attachments. You may find that all works well except the count of the terms when using get_terms ( which returns nothing ).
To fix this you may need to use this call in register_taxonomy
'update_count_callback' => '_update_generic_term_count',( https://core.trac.wordpress.org/ticket/41813#comment:8 )
Skip to note 32 content
Codex
Basic Example
/** * Register a 'genre' taxonomy for post type 'book'. * * @see register_post_type for registering post types. */ function wpdocs_create_book_tax() { register_taxonomy( 'genre', 'book', array( 'label' => __( 'Genre', 'textdomain' ), 'rewrite' => array( 'slug' => 'genre' ), 'hierarchical' => true, ) ); } add_action( 'init', 'wpdocs_create_book_tax', 0 );Note: If you want to ensure that your custom taxonomy behaves like a tag, you must add the option
'update_count_callback' => '_update_post_term_count'. Not doing so will result in multiple comma-separated items added at once being saved as a single value, not as separate values. This can cause undue stress when using<a href="https://developer.wordpress.org/reference/functions/get_the_term_list/" rel="nofollow">get_the_term_list()</a>and other term display functions.