Custom Taxonomy Not Showing in WordPress Admin: Causes, Diagnosis, and Fixes

Custom Taxonomy Not Showing in Admin

Custom Taxonomy Not Showing in WordPress Admin: Causes, Diagnosis, and Fixes

You registered a custom taxonomy, the code looks right, the function is firing — and the taxonomy doesn’t appear in the WordPress admin. This is a common pattern. The cause is almost always one of a handful of register_taxonomy() parameter mistakes, a registration sequence problem, or a conflict with how WordPress renders admin UI elements after recent changes to the block editor and REST API.

This guide walks through the actual causes in order of how often they show up in real debugging sessions. The decision-flow approach is faster than reading every section — start with the symptoms you’re seeing and follow the path that matches.

How to use this guide

The taxonomy-not-showing problem manifests in several distinct ways, and each manifestation points to a different cause. Identify your specific symptom first:

  • Taxonomy is missing from the admin sidebar / Posts menu entirely → Most often a show_ui or show_in_menu parameter issue, or taxonomy not associated with a post type. Start with Cause #1.
  • Taxonomy shows in the sidebar but not in the post-edit screen meta box → Usually a meta_box_cb or show_in_rest issue. Jump to Cause #4.
  • Taxonomy works on classic editor but not in Gutenberg / block editor → Almost always a show_in_rest issue. Jump to Cause #4.
  • Taxonomy was working, then disappeared after a plugin or theme change → Conflict diagnosis. Jump to Cause #5.
  • Taxonomy appears but admin column doesn’t showshow_admin_column parameter. Jump to Cause #3.
  • Taxonomy appears but you can’t add new terms → Capability issue. Jump to Cause #6.

If you don’t know which category matches yours yet, work through the causes in order — each section starts with a quick “does this match your symptoms” check.

Cause #1 — Missing register_taxonomy() call or wrong hook timing

The most common reason a taxonomy doesn’t appear in the admin is that the register_taxonomy() call isn’t actually executing at the right point in WordPress’s request lifecycle. The function needs to run on the init hook (or earlier), and it needs to run on every request — not just admin requests, not just when a specific page loads.

Does this match your symptoms?
– Taxonomy is completely absent from the admin sidebar
– You don’t see it in Posts → All Posts filter dropdowns
– No taxonomy archive URL exists on the front end either

Diagnosis:

Add a temporary debug line at the top of your register_taxonomy() call to confirm it’s running:

add_action( 'init', 'myplugin_register_taxonomy' );

function myplugin_register_taxonomy() {
    error_log( 'Taxonomy registration running' );
    register_taxonomy( /* ... */ );
}

Reload any page on the site and check the PHP error log. If you don’t see “Taxonomy registration running,” the function isn’t being called and you have a hook problem, not a register_taxonomy() problem.

Common causes of the function not running:

  • Registration code is inside a conditional that only fires on specific pages (is_admin(), is_singular(), etc.). Remove the conditional — taxonomy registration must happen on every request.
  • Registration code is wrapped in an unnecessary class method that isn’t being instantiated.
  • The hook is admin_init instead of init. Use init.
  • The hook priority is too late (init, 999) and another piece of code is interfering before yours runs. Use the default priority (10) unless you have a specific reason.

Fix: Ensure the registration runs on init with default priority, unconditionally:

add_action( 'init', function() {
    register_taxonomy(
        'genre',
        'post',
        [
            'label'        => 'Genres',
            'public'       => true,
            'hierarchical' => true,
            'show_ui'      => true,
            'show_in_menu' => true,
            'show_in_rest' => true,
            'rewrite'      => [ 'slug' => 'genre' ],
        ]
    );
} );

Cause #2 — Taxonomy not associated with a post type

register_taxonomy() requires a post type as its second argument. If the post type is wrong (typo, doesn’t exist yet at registration time, or wrong post type name), the taxonomy registers but doesn’t connect to anything visible in the admin.

Does this match your symptoms?
– Taxonomy is technically registered (visible in get_taxonomies() debug output) but not in any meta box
– No filter dropdown in the post list

Diagnosis:

Run a quick debug check to see what the taxonomy is associated with:

add_action( 'wp_loaded', function() {
    $taxonomy = get_taxonomy( 'your_taxonomy_slug' );
    if ( $taxonomy ) {
        error_log( print_r( $taxonomy->object_type, true ) );
    } else {
        error_log( 'Taxonomy not registered' );
    }
} );

The object_type array should contain the post types you intended. Empty or wrong = your second argument to register_taxonomy() is the problem.

Fix: Verify the post type slug matches the actual registered post type. For built-in post types: 'post', 'page', 'attachment'. For custom post types: the slug you used in register_post_type().

For multiple post types:

register_taxonomy( 'genre', [ 'post', 'page', 'book' ], $args );

The second argument can be a string (single post type) or an array (multiple).

Custom post type ordering matters. If your custom post type and your taxonomy are both registered on init and the taxonomy registers first, the post type doesn’t exist yet from the taxonomy’s perspective. Either register the post type with a slightly higher priority (e.g., init with priority 9) or use register_taxonomy_for_object_type() after both are registered:

add_action( 'init', 'register_my_post_type', 10 );
add_action( 'init', 'register_my_taxonomy', 11 );

Cause #3 — show_in_menu, show_ui, and show_admin_column parameters

The register_taxonomy() arguments include several visibility flags that control different parts of the admin UI. Missing or wrong values produce different missing-from-admin symptoms.

show_ui (default: value of public) — controls whether the admin UI exists at all. If false, the taxonomy is registered but has no admin pages, meta boxes, or list tables. Useful for taxonomies used internally that don’t need admin UI.

show_in_menu (default: value of show_ui) — controls whether the taxonomy appears in the admin sidebar / navigation menu. Can be true, false, or the name of a parent menu page to nest under. If you want the taxonomy invisible in the sidebar but still editable from the post-edit screen, set show_in_menu to false and keep show_ui as true.

show_admin_column (default: false) — controls whether the taxonomy shows as a column in the post list table (e.g., the column showing categories next to each post in the Posts list). Default is false even for public taxonomies, which catches people off-guard.

show_in_rest (default: false) — required for the block editor (Gutenberg) to show the taxonomy as a sidebar panel. Without this, classic-editor users see the taxonomy but block-editor users don’t. Covered in Cause #4 in more detail.

meta_box_cb — controls the meta box rendering callback. Default is null (WordPress decides based on hierarchical). Set to false to disable the meta box entirely while keeping the taxonomy otherwise visible.

Fix: For a taxonomy that should be fully visible:

register_taxonomy( 'genre', 'post', [
    'public'            => true,
    'show_ui'           => true,
    'show_in_menu'      => true,
    'show_in_nav_menus' => true,
    'show_in_rest'      => true,    // for Gutenberg
    'show_admin_column' => true,    // for post list column
    'show_tagcloud'     => true,
    'hierarchical'      => true,
] );

Cause #4 — Missing in Gutenberg (block editor) but works in classic editor

This is one of the most common modern WordPress taxonomy issues. The fix is show_in_rest => true in the register_taxonomy() arguments. Without it, the block editor doesn’t know the taxonomy exists.

Does this match your symptoms?
– Taxonomy works on the classic editor (if you have Classic Editor plugin installed)
– Taxonomy is invisible in the block editor sidebar
– Taxonomy appears correctly in the admin sidebar / Posts menu

Diagnosis:

Check whether show_in_rest is set:

$taxonomy = get_taxonomy( 'your_taxonomy_slug' );
error_log( 'show_in_rest: ' . var_export( $taxonomy->show_in_rest, true ) );

If it returns false, that’s the issue.

Fix: Add show_in_rest => true to your register_taxonomy() arguments. You may also want to specify rest_base if your taxonomy slug has unusual characters:

register_taxonomy( 'genre', 'post', [
    // ... other args
    'show_in_rest' => true,
    'rest_base'    => 'genres', // optional, defaults to taxonomy slug
] );

For custom REST controllers (rare):

'show_in_rest'          => true,
'rest_controller_class' => 'My_Custom_REST_Controller',

After adding show_in_rest, the taxonomy appears in the block editor’s sidebar Document panel under the Taxonomies section.

Cause #5 — Plugin or theme conflict

If the taxonomy was working previously and suddenly disappeared, the most likely cause is a plugin or theme interfering with the registration. Some performance plugins, security plugins, and theme frameworks override or block taxonomy registration on certain conditions.

Does this match your symptoms?
– Taxonomy was visible before, then disappeared
– Coincides with a plugin update, theme switch, or WordPress core update
– Other custom code seems to be misbehaving too

Diagnosis:

The standard plugin-conflict isolation workflow:

  1. Switch to a default WordPress theme (Twenty Twenty-Five or similar). If the taxonomy reappears, the issue is theme-related.
  2. Deactivate all plugins except the one registering the taxonomy. If it reappears, the issue is a plugin conflict.
  3. Reactivate plugins one at a time, checking after each, until you find the culprit.

Common conflict sources:

  • Performance plugins (WP Rocket, WP Super Cache) that aggressively cache the admin or interfere with the init hook
  • Security plugins that override admin permissions in ways that hide taxonomies
  • Custom post type plugins (CPT UI, Pods) that override register_taxonomy() calls if you’ve created a duplicate definition
  • Page builders that override admin column behavior

Fix: Once you’ve identified the conflicting plugin, you have three options: deactivate it (if you don’t need it), find a configuration setting that resolves the conflict, or contact the plugin author with a reproduction case.

Cause #6 — Capability or user role issue

If the taxonomy is registered correctly and visible to administrators but invisible to other roles, you have a capability mapping issue. By default, register_taxonomy() uses capability mapping that requires specific roles to manage terms.

Does this match your symptoms?
– Taxonomy is visible when logged in as administrator
– Editor / Author / Contributor users don’t see it
– “Add new term” button is missing for non-admin users

Diagnosis:

Check the taxonomy’s capability mapping:

$taxonomy = get_taxonomy( 'your_taxonomy_slug' );
error_log( print_r( $taxonomy->cap, true ) );

By default, the capabilities are:
manage_termsmanage_categories
edit_termsmanage_categories
delete_termsmanage_categories
assign_termsedit_posts

So by default, only users who can manage_categories (administrators) can add or edit terms, but users who can edit_posts (editors, authors, contributors) can assign them to posts.

Fix: Adjust capabilities to allow other roles:

'capabilities' => [
    'manage_terms' => 'edit_posts',    // editors can add terms
    'edit_terms'   => 'edit_posts',
    'delete_terms' => 'edit_posts',
    'assign_terms' => 'edit_posts',    // anyone who can edit posts can assign
],

Or, for full custom capability mapping, define custom capabilities and assign them via a role-management plugin or code.

Cause #7 — Cache or rewrite rules issue

Less common but worth checking when the taxonomy appears in the admin sidebar but front-end archive URLs return 404, or when changes to taxonomy configuration don’t take effect.

Does this match your symptoms?
– Taxonomy is visible in admin
– Front-end taxonomy archive (/genre/comedy/) returns 404
– Or: you changed register_taxonomy() arguments and the changes don’t seem to apply

Diagnosis:

Visit Settings → Permalinks and click “Save Changes” without modifying anything. This forces WordPress to flush rewrite rules. If your archive URLs work after this, the issue was stale rewrite rules.

Fix:

In production code, you don’t want to flush rewrite rules on every page load (it’s expensive). The correct pattern is to flush on plugin/theme activation and deactivation:

register_activation_hook( __FILE__, 'myplugin_activate' );
register_deactivation_hook( __FILE__, 'myplugin_deactivate' );

function myplugin_activate() {
    myplugin_register_taxonomy(); // your registration function
    flush_rewrite_rules();
}

function myplugin_deactivate() {
    flush_rewrite_rules();
}

For caching issues during development, clear any object cache (Redis, Memcached) and any page cache after taxonomy changes:

wp cache flush
wp transient delete --all

Cause #8 — Slug formatting issues

The taxonomy slug (the first argument to register_taxonomy()) has constraints WordPress doesn’t always enforce loudly. Spaces, uppercase letters, special characters, and excessive length can cause the registration to fail silently or behave unexpectedly.

Does this match your symptoms?
– Taxonomy uses unusual characters in its slug
– Registration appears to run but the taxonomy is broken in subtle ways

Fix: Use only lowercase letters, numbers, hyphens, and underscores. Maximum 32 characters. No spaces, no special characters, no uppercase:

// Bad
register_taxonomy( 'My Custom Taxonomy', 'post', [ /* ... */ ] );
register_taxonomy( 'category-of-thing!', 'post', [ /* ... */ ] );

// Good
register_taxonomy( 'product_category', 'post', [ /* ... */ ] );
register_taxonomy( 'genre', 'post', [ /* ... */ ] );

If you need user-facing capitalization or spaces, that’s what the label and singular_name arguments are for:

register_taxonomy( 'product_category', 'post', [
    'labels' => [
        'name'          => 'Product Categories',
        'singular_name' => 'Product Category',
    ],
] );

A debugging toolkit for taxonomy issues

Before reaching for code changes, three debugging tools will tell you what’s actually happening in your WordPress install. Most taxonomy problems are diagnosed faster with these tools than with grep’ing through code.

wp_get_object_taxonomies() — what taxonomies are actually attached to a post type

This is the single most useful diagnostic for “is my taxonomy connected to the right post type.” Drop it anywhere after init has fired:

add_action( 'wp_loaded', function() {
    $taxonomies = wp_get_object_taxonomies( 'book', 'objects' );
    foreach ( $taxonomies as $tax ) {
        error_log( sprintf(
            'Book taxonomy: %s (label: %s, public: %s, show_in_rest: %s)',
            $tax->name,
            $tax->label,
            $tax->public ? 'yes' : 'no',
            $tax->show_in_rest ? 'yes' : 'no'
        ) );
    }
} );

If your taxonomy doesn’t appear in the output, it’s either not registered yet at this point in the request, or it’s not associated with the post type you queried.

WP-CLI commands for taxonomy state inspection

If you have WP-CLI installed (most managed WordPress hosts include it), several commands inspect taxonomy state directly without writing diagnostic PHP:

# List all registered taxonomies
wp taxonomy list

# Get details for a specific taxonomy
wp taxonomy get genre

# List terms in a taxonomy
wp term list genre

# Check which post types a taxonomy is registered for
wp taxonomy get genre --field=object_type

# List post types and their taxonomies
wp post-type list --fields=name,labels.name

These commands run against your actual WordPress install state, so the output reflects what init actually produced. If wp taxonomy list doesn’t show your taxonomy, the registration code isn’t running at all (likely a hook problem from Cause #1).

Query Monitor for hook firing and request lifecycle

Query Monitor is a developer plugin that adds an admin bar with detailed request information including which hooks fired in what order. For taxonomy registration problems, the relevant sections are:

  • Hooks & Actions — verify init is firing as expected, with your callback in the action list
  • Database — confirm the registration happens before any query that depends on the taxonomy
  • Conditionals — check is_post_type_archive() and similar functions return what you expect on archive pages

Install Query Monitor, reload an admin page, and use the admin-bar menu to inspect what’s happening. It’s particularly useful for “taxonomy works on the front end but not in the admin” because you can see the admin-side hook order separately.

REST API endpoint visibility check

If you’ve set show_in_rest => true and want to verify the taxonomy is actually exposed, fetch the REST endpoint directly:

curl -s https://yoursite.com/wp-json/wp/v2/taxonomies/ | python3 -m json.tool

Your taxonomy should appear in the response. If it doesn’t, the registration isn’t actually setting show_in_rest => true, or there’s a rest_base mismatch.

For taxonomy term endpoints:

curl -s https://yoursite.com/wp-json/wp/v2/genres | python3 -m json.tool

The base path defaults to the taxonomy slug; if you set rest_base to something different, use that instead.

Working with CPT UI, Pods, and Toolset

A significant share of WordPress sites register taxonomies through plugins (Custom Post Type UI, Pods, Toolset, ACF Extended) rather than code. The diagnosis is similar but the fix path is different.

Diagnosing through-plugin registrations:

  • Use the debugging toolkit above (wp_get_object_taxonomies(), WP-CLI) to inspect the actual registered state — the plugin’s UI may say one thing while the registration produces another.
  • Check the plugin’s own diagnostic or export feature. CPT UI has “Get Code” which shows what register_taxonomy() call the plugin is making — useful for verifying arguments.
  • If the plugin allows exporting to code, do that and check the export against the working baseline below.

Common UI-plugin gotchas:

  • The UI may not expose all register_taxonomy() arguments. If you need show_in_rest for Gutenberg and the plugin doesn’t have that toggle, you may need to either upgrade to a newer plugin version or supplement with code.
  • Some plugins re-register taxonomies on admin_init rather than init, which can cause hook-order issues with custom code that depends on the taxonomy being available.
  • Plugin-registered taxonomies are still subject to the same template hierarchy, cache, and rewrite considerations.

If you’re maintaining a site where you didn’t set up the taxonomies, find out which plugin registers them before assuming code changes will work — modifying register_taxonomy() calls in your theme functions while the plugin is overriding them is a fast path to confusion.

Programmatic term creation and management

Once your taxonomy is registered and visible, you may need to create or modify terms in code (during plugin activation, data migrations, automated content workflows). The functions are well-documented but have subtle failure modes.

// Create a term
$result = wp_insert_term(
    'Comedy',           // term name
    'genre',            // taxonomy slug
    [
        'description' => 'Funny books',
        'slug'        => 'comedy',
        'parent'      => 0,    // for hierarchical taxonomies
    ]
);

if ( is_wp_error( $result ) ) {
    error_log( 'Term creation failed: ' . $result->get_error_message() );
} else {
    error_log( 'Created term with ID: ' . $result['term_id'] );
}

Common failures:

  • wp_insert_term() returns WP_Error if the taxonomy doesn’t exist yet — verify with taxonomy_exists( 'genre' ) first if running early in the request lifecycle
  • Returns WP_Error with code term_exists if a term with the same name and parent already exists (often what you want — handle it specifically rather than treating as failure)
  • For hierarchical taxonomies, parent must be a valid existing term ID — invalid parent IDs cause silent failures or unexpected behavior

For assigning terms to posts:

wp_set_object_terms( $post_id, [ 'Comedy', 'Satire' ], 'genre', true );
// true = append; false (default) = replace existing terms

Multisite considerations

On WordPress multisite networks, taxonomy registration runs per-site, not network-wide. Each site registers its own taxonomies based on its active plugins and theme.

Common multisite gotchas:

  • Taxonomies registered by a network-activated plugin appear on every site, but terms are per-site
  • Taxonomies registered by a theme only appear when that theme is active on a given site
  • Network admin pages don’t have access to per-site taxonomies — you’ll see taxonomies registered in the bootstrap (mu-plugins, network-active plugins) only
  • The switch_to_blog() / restore_current_blog() pattern doesn’t re-trigger init, so taxonomies from another site aren’t accessible after switching unless they happen to be registered globally

For multisite-aware code, register taxonomies in a network-active plugin or mu-plugin rather than in a theme, and use switch_to_blog() carefully when accessing terms cross-site.

A working register_taxonomy() baseline

If you’re not sure where to start, here’s a register_taxonomy() call that handles the most common cases — visible in admin, visible in Gutenberg, visible in post list column, visible on front end:

add_action( 'init', function() {
    register_taxonomy( 'genre', 'post', [
        'labels' => [
            'name'              => 'Genres',
            'singular_name'     => 'Genre',
            'search_items'      => 'Search Genres',
            'all_items'         => 'All Genres',
            'parent_item'       => 'Parent Genre',
            'parent_item_colon' => 'Parent Genre:',
            'edit_item'         => 'Edit Genre',
            'update_item'       => 'Update Genre',
            'add_new_item'      => 'Add New Genre',
            'new_item_name'     => 'New Genre Name',
            'menu_name'         => 'Genres',
        ],
        'hierarchical'      => true,
        'public'            => true,
        'show_ui'           => true,
        'show_admin_column' => true,
        'show_in_nav_menus' => true,
        'show_in_rest'      => true,
        'show_tagcloud'     => true,
        'rewrite'           => [
            'slug'         => 'genre',
            'with_front'   => false,
            'hierarchical' => true,
        ],
    ] );
} );

Start from this baseline, then remove parameters you don’t need rather than trying to remember which ones are required.

Frequently asked questions

Why does my custom taxonomy work in the classic editor but not in Gutenberg?

You’re missing show_in_rest => true in your register_taxonomy() arguments. The block editor uses the REST API to load taxonomy data, and without REST exposure, the taxonomy is invisible to it.

Do I need both show_ui and show_in_menu?

show_in_menu defaults to the value of show_ui. If you want both, set show_ui => true and you don’t need to explicitly set show_in_menu. If you want the taxonomy editable from the post screen but not in the sidebar, set show_ui => true and show_in_menu => false.

What’s the difference between register_taxonomy() and register_taxonomy_for_object_type()?

register_taxonomy() registers a new taxonomy. register_taxonomy_for_object_type() associates an existing taxonomy with an additional post type. Use the former when creating; use the latter when adding more post types to an existing taxonomy.

Why does my taxonomy show in the admin but the archive URL returns 404?

Stale rewrite rules. Visit Settings → Permalinks and save (no changes needed) to flush. In production code, flush rewrite rules on plugin activation, not on every page load.

Can I register taxonomies inside a class method?

Yes, but make sure the class is instantiated and the method is hooked to init:

class MyPlugin {
    public function __construct() {
        add_action( 'init', [ $this, 'register_taxonomies' ] );
    }
    public function register_taxonomies() {
        register_taxonomy( /* ... */ );
    }
}
new MyPlugin();

If you forget to instantiate the class, the hook is never added, the function never runs, and the taxonomy never registers.

How do I check if my taxonomy’s REST endpoint is accessible?

Fetch the REST API taxonomies index to see what’s actually exposed:

curl -s https://yoursite.com/wp-json/wp/v2/taxonomies/ | python3 -m json.tool

If your taxonomy doesn’t appear in the response, show_in_rest isn’t actually set in your register_taxonomy() arguments — or there’s a typo in the taxonomy slug. The terms endpoint follows the pattern /wp-json/wp/v2/{taxonomy-slug}/ (or /wp-json/wp/v2/{rest_base}/ if you set a custom rest_base).

Why does the taxonomy term metabox appear but not save the selected terms?

Usually a capability mismatch — the user can see the metabox (because show_ui is on) but doesn’t have assign_terms capability for the taxonomy. Check the taxonomy’s capability mapping and verify the user’s role has the required capability. Alternatively, the meta box is being rendered via a custom meta_box_cb callback that doesn’t include the correct nonce or form fields — verify the callback is producing the expected HTML.

Can I register a taxonomy for a post type that hasn’t been registered yet?

Not reliably. WordPress validates the post type slug when register_taxonomy() runs, and an unknown post type silently means the taxonomy isn’t associated with anything. Either register the post type first (with a slightly earlier priority on the init hook), or use register_taxonomy_for_object_type() after both are registered. The cleanest pattern:

add_action( 'init', 'register_my_post_types', 10 );
add_action( 'init', 'register_my_taxonomies', 11 );

Why doesn’t flush_rewrite_rules() work when I call it during normal page loads?

It does work, but it’s an expensive operation (rewriting the rewrite rules cache) and you shouldn’t call it on every request. The right pattern is to flush only on activation/deactivation hooks. For development, visit Permalinks settings instead.

My taxonomy is for a custom post type — what order do I register them?

Register the post type first (lower priority number, fires earlier), then the taxonomy (higher priority number, fires later). Or use register_taxonomy_for_object_type() after both are registered. The most reliable pattern:

add_action( 'init', 'register_my_post_type', 10 );
add_action( 'init', 'register_my_taxonomy', 11 );

What to do next

If you’ve gone through the causes above and your taxonomy is still not appearing, the next step is to instrument your code with error_log() calls to track exactly which stage is failing. The most common diagnostic gaps are:

  • The registration function isn’t actually running (hook problem)
  • The registration is running but the arguments are wrong (parameter problem)
  • The registration succeeds but UI conditions hide it (capability or show_in_* problem)

If those checks all pass and the taxonomy is still missing, switch to plugin-conflict isolation — deactivate all plugins, then reactivate one by one until the taxonomy appears or disappears.

If the symptoms point to a Gutenberg-specific issue, the answer is almost always show_in_rest => true. That single argument resolves more “taxonomy not in block editor” issues than any other fix.

WordPress’s taxonomy system is well-designed but has enough parameters that getting them all right takes practice. Working from a baseline that handles the common cases (above) and adjusting from there is usually faster than debugging from a minimal starting point.


Discover more from WP Winners 🏆

Subscribe to get the latest posts sent to your email.

More WorDPRESS Tips, tutorials and Guides

Discover more from WP Winners 🏆

Subscribe now to keep reading and get access to the full archive.

Continue reading