register_taxonomy( string $taxonomy, array|string $object_type, array|string $args = array() ): WP_Taxonomy|WP_Error

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.
  • labels string[]
    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() .
  • description string
    A short descriptive summary of what the taxonomy is for.
  • public bool
    Whether 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_menus are inherited from $public.
  • publicly_queryable bool
    Whether the taxonomy is publicly queryable.
    If not set, the default is inherited from $public
  • hierarchical bool
    Whether the taxonomy is hierarchical. Default false.
  • show_ui bool
    Whether 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_menu bool
    Whether 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_ui must be true. If not set, default is inherited from $show_ui (default true).
  • show_in_nav_menus bool
    Makes this taxonomy available for selection in navigation menus. If not set, the default is inherited from $public (default true).
  • show_in_rest bool
    Whether to include the taxonomy in the REST API. Set this to true for the taxonomy to be available in the block editor.
  • rest_base string
    To change the base url of REST API route. Default is $taxonomy.
  • rest_namespace string
    To change the namespace URL of REST API route. Default is wp/v2.
  • rest_controller_class string
    REST API Controller class name. Default is ‘WP_REST_Terms_Controller‘.
  • show_tagcloud bool
    Whether 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_edit bool
    Whether to show the taxonomy in the quick/bulk edit panel. It not set, the default is inherited from $show_ui (default true).
  • show_admin_column bool
    Whether to display a column for the taxonomy on its post type listing screens. Default false.
  • meta_box_cb bool|callable
    Provide 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_cb callable
    Callback 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.
  • capabilities string[]
    Array of capabilities for this taxonomy.
    • manage_terms string
      Default 'manage_categories'.
    • edit_terms string
      Default 'manage_categories'.
    • delete_terms string
      Default 'manage_categories'.
    • assign_terms string
      Default 'edit_posts'.
  • rewrite bool|array
    Triggers 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:
    • slug string
      Customize the permastruct slug. Default $taxonomy key.
    • with_front bool
      Should the permastruct be prepended with WP_Rewrite::$front. Default true.
    • hierarchical bool
      Either hierarchical rewrite tag or not. Default false.
    • ep_mask int
      Assign an endpoint mask. Default EP_NONE.
  • query_var string|bool
    Sets the query var key for this taxonomy. Default $taxonomy key. 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_callback callable
    Works 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_term string|array
    Default term to be used for the taxonomy.
    • name string
      Name of default term.
    • slug string
      Slug for default term.
    • description string
      Description for default term.
  • sort bool
    Whether terms in this taxonomy should be sorted in the order they are provided to wp_set_object_terms(). Default null which equates to false.
  • args array
    Array of arguments to automatically use inside wp_get_object_terms() for this taxonomy.
  • _builtin bool
    This taxonomy is a "built-in" taxonomy. INTERNAL USE ONLY! Default false.

Default:array()

Return

WP_Taxonomy|WP_Error The registered taxonomy object on success, WP_Error object on failure.

More Information

This function adds or overwrites a taxonomy. It takes in a name, an object name that it affects, and an array of parameters. It does not return anything.

Care should be used in selecting a taxonomy name so that it does not conflict with other taxonomies, post types, and reserved WordPress public and private query variables. A complete list of those is described in the Reserved Terms section. In particular, capital letters should be avoided.

Better be safe than sorry when registering custom taxonomies for custom post types. Use register_taxonomy_for_object_type() right after the function to interconnect them. Else you could run into minetraps where the post type isn’t attached inside filter callback that run during parse_request or pre_get_posts.

Additional Parameter Information

$taxonomy is the name of the taxonomy. Name should only contain lowercase letters and the underscore character, and not be more than 32 characters long (database structure restriction). Default: None
$object_type is the name of the object type for the taxonomy object. Object-types can be built-in Post Type or any Custom Post Type that may be registered. Default is None.
Built-in Post Types:

  • post
  • page
  • attachment
  • revision
  • nav_menu_item
  • custom_css
  • customize_changeset
Custom Post Types:

  • {custom_post_type} – Custom Post Type names must be all in lower-case and without any spaces.
  • null – Setting explicitly to null registers the taxonomy but doesn’t associate it with any objects, so it won’t be directly available within the Admin UI. You will need to manually register it using the ‘taxonomy’ parameter (passed through $args) when registering a custom post_type (see register_post_type()), or using register_taxonomy_for_object_type().
$args
(array/string) (optional) An array of Arguments.

Default: None

Arguments

label
(string) (optional) A plural descriptive name for the taxonomy marked for translation.

Default: overridden by $labels->name
labels
(array) (optional) labels – An array of labels for this taxonomy. By default tag labels are used for non-hierarchical types and category labels for hierarchical ones.

Default: if empty, name is set to label value, and singular_name is set to name value
  • name’ – general name for the taxonomy, usually plural. The same as and overridden by $tax->label. Default is _x( 'Post Tags', 'taxonomy general name' ) or _x( 'Categories', 'taxonomy general name' ). When internationalizing this string, please use a gettext context matching your post type. Example: _x('Writers', 'taxonomy general name');
  • singular_name’ – name for one object of this taxonomy. Default is _x( 'Post Tag', 'taxonomy singular name' ) or _x( 'Category', 'taxonomy singular name' ). When internationalizing this string, please use a gettext context matching your post type. Example: _x('Writer', 'taxonomy singular name');
  • menu_name’ – the menu name text. This string is the name to give menu items. If not set, defaults to value of name label.
  • all_items’ – the all items text. Default is __( 'All Tags' ) or __( 'All Categories' )
  • edit_item’ – the edit item text. Default is __( 'Edit Tag' ) or __( 'Edit Category' )
  • view_item’ – the view item text, Default is __( 'View Tag' ) or __( 'View Category' )
  • update_item’ – the update item text. Default is __( 'Update Tag' ) or __( 'Update Category' )
  • add_new_item’ – the add new item text. Default is __( 'Add New Tag' ) or __( 'Add New Category' )
  • new_item_name’ – the new item name text. Default is __( 'New Tag Name' ) or __( 'New Category Name' )
  • parent_item’ – the parent item text. This string is not used on non-hierarchical taxonomies such as post tags. Default is null or __( 'Parent Category' )
  • parent_item_colon’ – The same as parent_item, but with colon : in the end null, __( 'Parent Category:' )
  • search_items’ – the search items text. Default is __( 'Search Tags' ) or __( 'Search Categories' )
  • popular_items’ – the popular items text. This string is not used on hierarchical taxonomies. Default is __( 'Popular Tags' ) or null
  • separate_items_with_commas’ – the separate item with commas text used in the taxonomy meta box. This string is not used on hierarchical taxonomies. Default is __( 'Separate tags with commas' ), or null
  • add_or_remove_items’ – the add or remove items text and used in the meta box when JavaScript is disabled. This string is not used on hierarchical taxonomies. Default is __( 'Add or remove tags' ) or null
  • choose_from_most_used’ – the choose from most used text used in the taxonomy meta box. This string is not used on hierarchical taxonomies. Default is __( 'Choose from the most used tags' ) or null
  • not_found’ (3.6+) – the text displayed via clicking ‘Choose from the most used tags’ in the taxonomy meta box when no tags are available and (4.2+) – the text used in the terms list table when there are no items for a taxonomy. Default is __( 'No tags found.' ) or __( 'No categories found.' )
  • back_to_items’ – the text displayed after a term has been updated for a link back to main index. Default is __( ' Back to tags' ) or __( ' Back to categories' )
public
(boolean) (optional) Whether 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_menus` are inherited from `$public`.

Default: true
publicly_queryable
(boolean) (optional) Whether the taxonomy is publicly queryable.

Default: $public
show_ui
(boolean) (optional) Whether to generate a default UI for managing this taxonomy.

Default: if not set, defaults to value of public argument. As of 3.5, setting this to false for attachment taxonomies will hide the UI.
show_in_menu
(boolean) (optional) Where to show the taxonomy in the admin menu. show_ui must be true.

Default: value of show_ui argument
  • ‘false’ – do not display in the admin menu
  • ‘true’ – show as a submenu of associated object types
show_in_nav_menus
(boolean) (optional) true makes this taxonomy available for selection in navigation menus.

Default: if not set, defaults to value of public argument
show_in_rest
(boolean) (optional) Whether to include the taxonomy in the REST API. You will need to set this to true in order to use the taxonomy in your gutenberg metablock.

Default: false
rest_base
(string) (optional) To change the base url of REST API route.

Default: $taxonomy
rest_controller_class
(string) (optional) REST API Controller class name.

Default: WP_REST_Terms_Controller
show_tagcloud
(boolean) (optional) Whether to allow the Tag Cloud widget to use this taxonomy.

Default: if not set, defaults to value of show_ui argument
show_in_quick_edit
(boolean) (optional) Whether to show the taxonomy in the quick/bulk edit panel. (Available since 4.2)

Default: if not set, defaults to value of show_ui argument
meta_box_cb
(callback) (optional) Provide a callback function name for the meta box display. (Available since 3.8)

Default: null

Note: Defaults to the categories meta box (post_categories_meta_box() in meta-boxes.php) for hierarchical taxonomies and the tags meta box (post_tags_meta_box() ) for non-hierarchical taxonomies. No meta box is shown if set to false.

show_admin_column
(boolean) (optional) Whether to allow automatic creation of taxonomy columns on associated post-types table. (Available since 3.5)

Default: false
description
(string) (optional) Include a description of the taxonomy.

Default: “”
hierarchical
(boolean) (optional) Is this taxonomy hierarchical (have descendants) like categories or not hierarchical like tags.

Default: false

Note: Hierarchical taxonomies will have a list with checkboxes to select an existing category in the taxonomy admin box on the post edit page (like default post categories). Non-hierarchical taxonomies will just have an empty text field to type-in taxonomy terms to associate with the post (like default post tags).

update_count_callback
(string) (optional) A function name that will be called when the count of an associated $object_type, such as post, is updated. Works much like a hook.

Default: None – but see Note, below.

Note: While the default is '', when actually performing the count update in wp_update_term_count_now() , if the taxonomy is only attached to post types (as opposed to other WordPress objects, like user), the built-in _update_post_term_count() function will be used to count only published posts associated with that term, otherwise _update_generic_term_count() will be used instead, that does no such checking.

This is significant in the case of attachments. Because an attachment is a type of post, the default _update_post_term_count() will be used. However, this may be undesirable, because this will only count attachments that are actually attached to another post (like when you insert an image into a post). This means that attachments that you simply upload to WordPress using the Media Library, but do not actually attach to another post will not be counted. If your intention behind associating a taxonomy with attachments was to leverage the Media Library as a sort of Document Management solution, you are probably more interested in the counts of unattached Media items, than in those attached to posts. In this case, you should force the use of _update_generic_term_count() by setting ‘_update_generic_term_count’ as the value for update_count_callback.

Another important consideration is that _update_post_term_count() only counts published posts. If you are using custom statuses, or using custom post types where being published is not necessarily a consideration for being counted in the term count, then you will need to provide your own callback that doesn’t include the post_status portion of the where clause.

query_var
(boolean or string) (optional) False to disable the query_var, set as string to use custom query_var instead of default which is $taxonomy, the taxonomy’s “name”. True is not seen as a valid entry and will result in 404 issues.

Default: $taxonomy

Note: The query_var is used for direct queries through WP_Query like new WP_Query(array('people'=>$person_name)) and URL queries like /?people=$person_name. Setting query_var to false will disable these methods, but you can still fetch posts with an explicit WP_Query taxonomy query like WP_Query(array('taxonomy'=>'people', 'term'=>$person_name)).

rewrite
(boolean/array) (optional) Set to false to prevent automatic URL rewriting a.k.a. “pretty permalinks”. Pass an $args array to override default URL settings for permalinks as outlined below:

Default: true
  • slug’ – Used as pretty permalink text (i.e. /tag/) – defaults to $taxonomy (taxonomy’s name slug)
  • with_front’ – allowing permalinks to be prepended with front base – defaults to true
  • hierarchical’ – true or false allow hierarchical urls (implemented in Version 3.1) – defaults to false
  • ep_mask’ – (Required for pretty permalinks) Assign an endpoint mask for this taxonomy – defaults to EP_NONE. If you do not specify the EP_MASK, pretty permalinks will not work. For more info see this Make WordPress Plugins summary of endpoints.

Note: You may need to flush the rewrite rules after changing this. You can do it manually by going to the Permalink Settings page and re-saving the rules — you don’t need to change them — or by calling $wp_rewrite->flush_rules(). You should only flush the rules once after the taxonomy has been created, not every time the plugin/theme loads.

capabilities
(array) (optional) An array of the capabilities for this taxonomy.

Default: None
  • manage_terms’ – ‘manage_categories’
  • edit_terms’ – ‘manage_categories’
  • delete_terms’ – ‘manage_categories’
  • assign_terms’ – ‘edit_posts’
sort
(boolean) (optional) Whether this taxonomy should remember the order in which terms are added to objects.

Default: None
_builtin
(boolean) (not for general use) Whether this taxonomy is a native or “built-in” taxonomy. Note: this entry is for documentation – core developers recommend you don’t use this when registering your own taxonomy

Default: false

Reserved Terms

Avoiding the following reserved terms is particularly important if you are passing the term through the $_GET or $_POST array. Doing so can cause WordPress to respond with a 404 error without any other hint or explanation.

  • attachment
  • attachment_id
  • author
  • author_name
  • calendar
  • cat
  • category
  • category__and
  • category__in
  • category__not_in
  • category_name
  • comments_per_page
  • comments_popup
  • custom
  • customize_messenger_channel
  • customized
  • cpage
  • day
  • debug
  • embed
  • error
  • exact
  • feed
  • fields
  • hour
  • link_category
  • m
  • minute
  • monthnum
  • more
  • name
  • nav_menu
  • nonce
  • nopaging
  • offset
  • order
  • orderby
  • p
  • page
  • page_id
  • paged
  • pagename
  • pb
  • perm
  • post
  • post__in
  • post__not_in
  • post_format
  • post_mime_type
  • post_status
  • post_tag
  • post_type
  • posts
  • posts_per_archive_page
  • posts_per_page
  • preview
  • robots
  • s
  • search
  • second
  • sentence
  • showposts
  • static
  • status
  • subpost
  • subpost_id
  • tag
  • tag__and
  • tag__in
  • tag__not_in
  • tag_id
  • tag_slug__and
  • tag_slug__in
  • taxonomy
  • tb
  • term
  • terms
  • theme
  • title
  • type
  • types
  • w
  • withcomments
  • withoutcomments
  • year

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

VersionDescription
5.9.0Introduced rest_namespace argument.
5.5.0Introduced default_term argument.
5.4.0Added the registered taxonomy object as a return value.
5.1.0Introduced meta_box_sanitize_cb argument.
4.7.0Introduced show_in_rest, 'rest_base' and 'rest_controller_class' arguments to register the taxonomy in REST API.
4.5.0Introduced publicly_queryable argument.
4.4.0The public argument now controls whether the taxonomy can be queried on the front end.
4.2.0Introduced show_in_quick_edit argument.
2.3.0Introduced.
Show 4 moreShow less

User Contributed Notes

  1. Skip to note 17 content

    If you want your taxonomy panel to be visible at the sidebar of the block editor, you should set show_in_rest to true.

  2. Skip to note 18 content

    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 );
  3. Skip to note 19 content

    Be careful not to use a reserved word for slug, query_var or $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 slug or query_var of 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.

  4. Skip to note 20 content

    Note that the taxonomy name – the $taxonomy param above – should include only the characters a-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 through sanitize_key() – such as during AJAX tag searches – which will lead to subtle sorts of breakage.

  5. Skip to note 21 content

    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.php template 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 );
  6. Skip to note 22 content

    Example Private Taxonomy

    If you do not want your taxonomy to be exposed publicly, you can use the public and rewrite parameters 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 );
  7. Skip to note 24 content

    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.

  8. Skip to note 25 content

    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.

  9. Skip to note 26 content

    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 );
    
    }
  10. Skip to note 27 content

    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 );
  11. Skip to note 28 content

    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 );

  12. Skip to note 29 content

    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' );
  13. Skip to note 31 content

    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 )

  14. Skip to note 32 content

    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 get_the_term_list() and other term display functions.

You must log in before being able to contribute a note or feedback.