UPDATE: For anyone following this thread, the plugin solution does work, but seems to have a problem on my multisite format. I have now tested on 3 individual installs and on 3 multisites. On the multisites, the red "undeletable" marker appears next to the categories in the array, but they can get deleted. This may well be down to a problem with my particular install, as it works properly with newly created subsites.

Original Post: Working on a multisite & would like a way to protect a couple of default categories from being deleted by site owners.

I'm already using the "members" plugin to define admin roles, but the only option there is "manage categories", and if I disable that capability they can't delete categories, but they can't create new ones either.

Any way to allow new categories but not to delete a few special ones??

  • Updated answer. I forgot to mention since moment zero that the code was developed and tested in a Multisite environment. I really don't know why this would be failing on your side. A third party testing is needed.
    – brasofilo
    Commented Nov 19, 2012 at 22:37
  • Just created a brand new subsite on my original test multisite & it works perfectly! Don't understand this at all. All the old sites I tested on still don't work, the new one does? Thanks Commented Nov 19, 2012 at 23:01
  • I'm running 3.4.2. Just a guess: maybe another plugin is using the same hooks. Try modifying the actions priority (delete_term_taxonomy, edit_term_taxonomies). Instead of 10, try 1 (highest) or 9999 (lowest), i.e.: add_action( 'delete_term_taxonomy', 'wpse_70758_del_tax', 1, 1 );
    – brasofilo
    Commented Nov 19, 2012 at 23:19
  • @brasofilo - Thanks for your further input. I have tried your suggestions & disabled all site & network plugins but still refuses to protect cats from deletion. However, given that the plugin works properly with newly created subsites I'm happy to accept that it's an issue with my setup. Maybe something is corrupted - this multisite shares a common database & I've been doing a LOT of testing various things over the last few months. So kudos for coming up with a great answer to the challenge & then creating a plugin to make it work - Cheers :-) Commented Nov 20, 2012 at 7:40

2 Answers 2


Extending @Roman's answer.

The following was developed and tested in a Multisite environment - local and live WP installs.

Looking at the source of wp_delete_term, there are some hooks that are triggered when the function is called.

I'm not sure if this is the best way of doing this, but it works.

add_action( 'delete_term_taxonomy', 'wpse_70758_del_tax', 10, 1 );

function wpse_70758_del_tax( $tt_id )
    $undeletable = array( 'undeletable', 'uncategorized', 'other-cat' );
    $term = get_term_by( 'id', $tt_id, 'category' );

    if( in_array( $term->slug, $undeletable ) ) 
        wp_die( 'cant delete' );

So, when trying to delete the "Undeletable" category (using the Quick Edit menu), it produces:

can't delete category

As the deletion happens via Ajax, we are breaking its execution and WP dumps that error message (modifying that text deserves a separate Question).

If we use the "Bulk actions", that wp_die() is printed in the screen.

But that's not all. Before the actual deletion (action hook delete_term_taxonomy), the child categories of the one we are blocking are "unparented", line #1772:

// Update children to point to new parent

There's another hook where this action happens and we can insert an early break to prevent the "unparenting":

add_action( 'edit_term_taxonomies', 'wpse_70758_del_child_tax', 10, 1 );

function wpse_70758_del_child_tax( $arr_ids )
    $undeletable = array( 'undeletable', 'uncategorized', 'other-cat' );
    foreach( $arr_ids as $id )
        $term   = get_term_by( 'id', $id, 'category' );
        $parent = get_term_by( 'id', $term->parent, 'category' );

        if( in_array( $parent->slug, $undeletable ) ) 
            wp_die( 'cant delete' );        

Use this inside a Must Use Plugin and it will be automatically active in the network.

The snapshot above has a custom ID column in the category listing. That's done with the following code (an here with an extra column marking the "undeletable" categories with a big red bullet):

add_filter( 'manage_edit-category_columns', 'wpse_70758_cat_edit_columns' );
add_filter( 'manage_category_custom_column', 'wpse_70758_cat_custom_columns', 10, 3 );

function wpse_70758_cat_edit_columns( $columns )
    $columns['tt_id'] = 'ID';   
    $columns['undeletable'] = 'Undeletable';   
    return $columns;

function wpse_70758_cat_custom_columns( $value, $name, $tt_id )
    if( 'tt_id' == $name ) 
        echo $tt_id;

    $term = get_term_by( 'id', $tt_id, 'category' );
    $undeletable = array( 'undeletable', 'uncategorized', 'other-cat' );

    if( 'undeletable' == $name && in_array( $term->slug, $undeletable ) )
        echo '<span style="color:#f00;font-size:5em;line-height:.5em">&#149;</span>';

Full working plugin: https://gist.github.com/4110831

  • Thanks for your input guys - I'll try and check this out over the weekend. Commented Nov 17, 2012 at 9:56
  • Need a little more help with one I'm afraid. I added the first bit of code in functions.php and changed the 'undeletable' to an existing category & it worked perfectly. Got all excited and changed it again to 'product' but that category DID get deleted. Now tried creating a whole bunch of new categories but everything always gets deleted now? Did also try the rest of the code and the big red buttons showed up (nice touch) but categories still get deleted - any ideas what I'm doing wrong? THANKS Commented Nov 19, 2012 at 9:13
  • @user22537 : I've modified all conditionals to use the in_array logic. So, you can check for a bunch of undeletable categories. Make sure the Category slug matches the list in the $undeletable arrays.
    – brasofilo
    Commented Nov 19, 2012 at 11:12
  • I've tried to show the actual code I'm using in the answer above, but not sure if you will be able to see it? I created a new category called "bob". It shows the red undeletable besided it, but still gets deleted. Feel I must be doing something stupid - thanks for your support Commented Nov 19, 2012 at 12:18
  • @user22537 please add code and other relevant details to your question rather that someone's answer (that makes things confusing).
    – Rarst
    Commented Nov 19, 2012 at 12:31

Maybee you can hook to wp_delete_term function with action "delete_term" (see info at: http://adambrown.info/p/wp_hooks/hook/delete_term?version=3.4&file=wp-includes/taxonomy.php) and if such particular term is deleted, you can insert it once again...

this is not so clean solution and users would look bit surprised that term remains still after they clicked "delete link" but it can do the job, actually i think it is only solution...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.