WordPress Custom Taxonomy Example: Register Topic Tags for Structured Content
A production-ready custom taxonomy plugin example with REST support, rewrite rules, capability choices, testing steps, and SEO notes.
Published
April 17, 2026
Reading Time
4 min read
Updated
April 17, 2026

Implementation Notes
Extension points, code paths, and implementation choices that should survive contact with production.
Best For
WordPress developers, agencies, and technical teams building custom plugin or theme functionality with cleaner operational defaults.
Primary Topics
Editorial Focus
Build Pattern: Extension points, code paths, and implementation choices that should survive contact with production. Updated on April 17, 2026.
Full Report
Last reviewed: April 17, 2026
Searches for a WordPress custom taxonomy example usually come from the same practical problem: the default categories and tags are not structured enough for the content model. A site may need product types, documentation topics, vulnerability classes, locations, industries, or editorial themes that should be queryable, visible in the editor, and stable across theme changes.
This guide shows how to register a custom taxonomy in a small plugin, attach it to posts, expose it to the block editor, and avoid the common mistakes that make taxonomy work painful later. The example is intentionally production-oriented, not only a minimal snippet for functions.php.
Who this guide is for
This article is for WordPress developers, agencies, SEO teams, and site owners who need a cleaner information architecture. If visitors, editors, or API consumers need a second classification layer beyond categories, a custom taxonomy is usually the correct tool.
When to create a custom taxonomy
Create a taxonomy when the relationship is reusable across many posts and should be used for filtering, archives, editor workflows, or REST API responses. Do not create a taxonomy just because one page needs a visual label. A taxonomy becomes part of the site’s content model, so it should describe a real editorial or product dimension.
- Use categories for broad editorial sections.
- Use tags for loose, general labeling.
- Use a custom taxonomy when the labels have a specific business meaning.
Plugin example: register a topic taxonomy
The example below creates a non-hierarchical taxonomy called topic_tag for normal blog posts. It appears in the editor, adds an admin column, supports REST API usage, and uses a public archive slug of /topic/example-term/.
<?php
/**
* Plugin Name: VulnWP Topic Taxonomy
* Description: Registers a topic taxonomy for structured editorial tagging.
* Version: 1.0.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
add_action( 'init', 'vulnwp_register_topic_taxonomy' );
function vulnwp_register_topic_taxonomy() {
$labels = array(
'name' => __( 'Topics', 'vulnwp-topic-taxonomy' ),
'singular_name' => __( 'Topic', 'vulnwp-topic-taxonomy' ),
'search_items' => __( 'Search Topics', 'vulnwp-topic-taxonomy' ),
'popular_items' => __( 'Popular Topics', 'vulnwp-topic-taxonomy' ),
'all_items' => __( 'All Topics', 'vulnwp-topic-taxonomy' ),
'edit_item' => __( 'Edit Topic', 'vulnwp-topic-taxonomy' ),
'update_item' => __( 'Update Topic', 'vulnwp-topic-taxonomy' ),
'add_new_item' => __( 'Add New Topic', 'vulnwp-topic-taxonomy' ),
'new_item_name' => __( 'New Topic Name', 'vulnwp-topic-taxonomy' ),
'separate_items_with_commas' => __( 'Separate topics with commas', 'vulnwp-topic-taxonomy' ),
'add_or_remove_items' => __( 'Add or remove topics', 'vulnwp-topic-taxonomy' ),
'choose_from_most_used' => __( 'Choose from the most used topics', 'vulnwp-topic-taxonomy' ),
'not_found' => __( 'No topics found.', 'vulnwp-topic-taxonomy' ),
'menu_name' => __( 'Topics', 'vulnwp-topic-taxonomy' ),
);
register_taxonomy(
'topic_tag',
array( 'post' ),
array(
'labels' => $labels,
'description' => __( 'Structured topic labels for editorial content.', 'vulnwp-topic-taxonomy' ),
'public' => true,
'publicly_queryable' => true,
'hierarchical' => false,
'show_ui' => true,
'show_admin_column' => true,
'show_in_rest' => true,
'rewrite' => array(
'slug' => 'topic',
'with_front' => false,
),
'capabilities' => array(
'manage_terms' => 'manage_categories',
'edit_terms' => 'manage_categories',
'delete_terms' => 'manage_categories',
'assign_terms' => 'edit_posts',
),
)
);
}
register_activation_hook(
__FILE__,
function () {
vulnwp_register_topic_taxonomy();
flush_rewrite_rules();
}
);
register_deactivation_hook(
__FILE__,
function () {
flush_rewrite_rules();
}
);
Why this should be a plugin
A taxonomy describes content, not theme presentation. If the active theme changes, the terms should still exist, the editor should still display them, and API consumers should not lose the field. That is why a custom taxonomy usually belongs in a plugin or must-use plugin, not in functions.php.
Important arguments explained
register_taxonomy() should run on the init hook. WordPress also documents that the taxonomy key must stay short and use safe lowercase characters. Treat that key as permanent because changing it later can break stored term relationships, REST consumers, templates, and archive URLs.
show_in_restmakes the taxonomy available to the block editor and REST API clients.show_admin_columnhelps editors audit term usage from the post list screen.hierarchicalcontrols whether it behaves like categories or tags.rewritecontrols archive URLs and should be chosen before launch.capabilitiesseparates who can manage terms from who can assign them.
Hierarchical or non-hierarchical?
Use hierarchical => true when terms need parent-child structure, such as industries, regions, departments, or product families. Use hierarchical => false when terms behave like tags, such as techniques, frameworks, or vulnerability names.
Do not choose hierarchy only because it looks organized in the admin UI. Parent-child taxonomies create URL, migration, and editorial governance decisions. If editors cannot explain the tree rules, a flat taxonomy is safer.
How to test after activation
- Activate the plugin on a staging site first.
- Open the post editor and confirm the Topics panel appears.
- Add two or three terms and save a post.
- Open the post list and confirm the admin column appears.
- Visit a term archive URL such as
/topic/security/. - Check the REST API response for the taxonomy relationship.
curl -s https://example.com/wp-json/wp/v2/taxonomies/topic_tag | jq
curl -s 'https://example.com/wp-json/wp/v2/posts?per_page=1&_fields=id,topic_tag' | jq
Common mistakes
- Putting taxonomy registration in the theme. The content model disappears when the theme is changed or disabled.
- Changing the taxonomy key after launch. The key is stored throughout WordPress data and integrations.
- Forgetting
show_in_rest. Editors may not see the taxonomy correctly in the block editor. - Skipping rewrite flushing on activation. Archive URLs may return 404 until permalink rules are refreshed.
- Creating too many overlapping taxonomies. Editorial teams need clear rules, not more dropdowns.
SEO and information architecture notes
Custom taxonomy archives can help discovery when they represent meaningful topic clusters. They can also create thin, duplicate, or low-value archive pages if every one-off label becomes public. Before exposing archives to search engines, decide which terms deserve indexable landing pages and which should remain internal organization tools.
If the taxonomy is only for internal editorial workflow, set public or publicly_queryable accordingly and avoid creating public archives. If the taxonomy should rank, write useful term descriptions, link related articles, and avoid empty archives.
Related reading
This pairs well with our custom post type example. A CPT defines the content object; a taxonomy defines how those objects are grouped and discovered.


