Custom Taxonomy Generator

Generate register_taxonomy() code with labels, the post types it applies to, hierarchy, REST support and rewrite rules.

Live output

Enable JavaScript to customise; default output below.

Prefix it with something of your own so it cannot collide with another plugin.

Stored in the database and used in code. WordPress caps it at 32 characters and it cannot be renamed later without a migration.

One or more post type keys, comma separated. They must be registered by the time this runs.

Live preview taxonomy.php
<?php
/**
 * Registers the "genre" taxonomy for post.
 */
function my_plugin_register_genre() {
	$labels = array(
		'name'          => _x( 'Genres', 'Taxonomy general name', 'my-plugin' ),
		'singular_name' => _x( 'Genre', 'Taxonomy singular name', 'my-plugin' ),
		'menu_name'     => __( 'Genres', 'my-plugin' ),
		'all_items'     => __( 'All Genres', 'my-plugin' ),
		'edit_item'     => __( 'Edit Genre', 'my-plugin' ),
		'add_new_item'  => __( 'Add New Genre', 'my-plugin' ),
		'search_items'  => __( 'Search Genres', 'my-plugin' ),
		'parent_item'   => __( 'Parent Genre', 'my-plugin' ),
		'not_found'     => __( 'No Genres found.', 'my-plugin' ),
	);

	$args = array(
		'labels'             => $labels,
		'hierarchical'       => true,
		'public'             => true,
		'show_in_rest'       => true,
		'show_admin_column'  => true,
		'show_in_quick_edit' => true,
		'rewrite'            => array(
			'slug'         => 'genre',
			'hierarchical' => false,
		),
	);

	register_taxonomy(
		'genre',
		array_map( 'trim', explode( ',', 'post' ) ),
		$args
	);
}
add_action( 'init', 'my_plugin_register_genre' );

Output is valid and updates as you type.

Pick the taxonomy key, the post types it applies to and whether it behaves like categories or tags, and the generator writes the register_taxonomy() call with its labels and rewrite rules.

How to use

  1. Name the taxonomy key. It is stored in the database, capped at 32 characters, and renaming it later means migrating every term relationship.
  2. List the post types it attaches to, comma separated. They have to be registered by the time this code runs.
  3. Choose hierarchical for category behaviour, with parents and checkboxes, or leave it off for tag behaviour with a free-text box.
  4. Set the permalink option. Default uses the taxonomy key as the slug; custom lets you nest it under a path.
  5. Paste the result into your plugin, then visit Settings, Permalinks once so the rewrite rules are flushed.

Example

A books site adds a flat Topics taxonomy across three post types, nested under a library path, with a default term applied to anything untagged:

$args = array(
	'labels'             => $labels,
	'hierarchical'       => false,
	'public'             => true,
	'show_in_rest'       => true,
	'default_term'       => array(
		'name' => 'General Interest',
		'slug' => 'general-interest',
	),
	'rewrite'            => array(
		'slug'         => 'library/topics',
		'hierarchical' => true,
	),
);

register_taxonomy(
	'topic',
	array_map( 'trim', explode( ',', 'post, book, guide' ) ),
	$args
);

show_in_rest is on by default because the block editor’s taxonomy panel does not appear without it, which is the most common reason a new taxonomy seems to register but never shows up.

Pitfalls

  • The taxonomy key is capped at 32 characters and cannot be changed without a migration. Term relationships are stored against it.
  • Registering on the wrong hook is the usual failure. It must run on init, not plugins_loaded and not inside a wp_loaded callback.
  • Rewrite rules are cached. A new or changed slug 404s until permalinks are flushed, which is one visit to Settings, Permalinks.
  • show_in_rest off means no block editor panel, no matter what the other arguments say.
  • hierarchical is about behaviour, not appearance. Turning it on after posts are tagged leaves existing terms flat but the UI switches to checkboxes.
  • A taxonomy key that collides with an existing one, including core’s category and post_tag, silently wins or loses depending on load order. Prefix it.
  • default_term creates the term at registration. Changing its name later does not rename the term that already exists.
  • Attaching to a post type that registers later means the taxonomy is simply not attached; the code runs without an error.

Compatibility

register_taxonomy() has accepted this argument shape since WordPress 4.7, when show_in_rest arrived. default_term needs WordPress 5.5 or later; on older versions the argument is ignored rather than fatal. The generated code targets PHP 7.0 and up, and the tool runs entirely in your browser.

Frequently asked questions

Should this be a taxonomy or a custom field?
A taxonomy is for grouping things people browse by, and it gives you archive pages and term queries. A custom field is for a value that belongs to one post and is not a shared axis.
Why does my new taxonomy 404 on the front end?
Rewrite rules are cached until they are flushed. Visit Settings, Permalinks once after registering, and never call flush_rewrite_rules() on every page load.
Can one taxonomy serve several post types?
Yes, that is what the post types field does. Terms are shared across all of them, so a term added on one post type appears on the others.
How do I show it in the block editor?
Keep show_in_rest on. The panel is built from the REST schema, so without it the editor has nothing to render.
Does hierarchical change the URL?
Only if you also turn on hierarchical URLs. That writes parent terms into the path, as in /genre/fiction/crime/, which changes existing term links.

From the people who built this tool

WP Adminify

The WordPress admin, rebuilt: a dashboard worth looking at, menu and column control, a real file manager and the login page your client sees.

See WP Adminify Free version on WordPress.org

Weekly drops

New tools, when there are new tools

One email when something worth using ships. No schedule to fill, so no filler.

Your address goes nowhere else, and one click unsubscribes.