skip to Main Content

I would like to prevent that some categories are accidentally deleted. For this I use a meta entry for the category to be protected.

I use the following code for this:

// edit: wrong hook! ** add_action( 'delete_term_taxonomy', 'taxonomy_delete_protection', 10, 1 );
add_action( 'pre_delete_term', 'taxonomy_delete_protection', 10, 1 );
function taxonomy_delete_protection ( $term_id )
{
    
    if (get_term_meta ($term_id, 'delete-protect', true) === true)
    {
      wp_die('Cannot delete this category');
    }
    
}

Unfortunately, instead of my error message, only "Something went wrong" is displayed. Why?


Edit: The `delete_term_taxonomy` is the wrong hook for my code, because it deleted the meta before i can check the meta entry. `pre_delete_term` does fire before anything happens with the category.

4

Answers


  1. Chosen as BEST ANSWER

    This is my current solution, not perfect but it works.

    The "Something went wrong" message show up if you delete the taxonomy with the row action. So i unset the "delete" action so it couldn't be triggered this way.

    add_filter ('category_row_actions', 'unset_taxonomy_row_actions', 10, 2);
    function unset_taxonomy_row_actions ($actions, $term)
    {
    
    $delete_protected = get_term_meta ($term->term_id, 'delete-protect', true);
    
       if ($delete_protected)
       {
        unset ($actions['delete']);
       }
    
    return $actions;
    }
    

    Then i hide the "Delete" Link in the taxonomy edit form with css. It's still could be triggered if you inspect the site and it's link, but there is no hook to remove this action otherwise.

    add_action( 'category_edit_form', 'remove_delete_edit_term_form', 10, 2 );
    
    function remove_delete_edit_term_form ($term, $taxonomy)
    {
    
        $delete_protected = get_term_meta ($term->term_id, 'delete-protect', true);
        
        if ($delete_protected)
        {
            // insert css
            echo '<style type="text/css">#delete-link {display: none !important;}</style>';
        }
        
    }
    

    Finally the check before deleting the taxonomy. This should catch all other ways, like the bulk action "delete". I didn't found another way yet to stop the script from deleting the taxonomy.

    add_action ('pre_delete_term', 'taxonomy_delete_protection', 10, 1 );
    
    function taxonomy_delete_protection ( $term_id )
    {
        
        $delete_protected = get_term_meta ($term_id, 'delete-protect', true);
        
        if ($delete_protected)
        {
            $term = get_term ($term_id);
    
            $error = new WP_Error ();
            $error->add (1, '<h2>Delete Protection Active!</h2>You cannot delete "' . $term->name . '"!');
            wp_die ($error);
        }
    }
    

  2. The "Why" is because of the following JavaScript that ships with WordPress:

    $.post(ajaxurl, data, function(r){
        if ( '1' == r ) {
            $('#ajax-response').empty();
            tr.fadeOut('normal', function(){ tr.remove(); });
    
            /**
             * Removes the term from the parent box and the tag cloud.
             *
             * `data.match(/tag_ID=(d+)/)[1]` matches the term ID from the data variable.
             * This term ID is then used to select the relevant HTML elements:
             * The parent box and the tag cloud.
             */
            $('select#parent option[value="' + data.match(/tag_ID=(d+)/)[1] + '"]').remove();
            $('a.tag-link-' + data.match(/tag_ID=(d+)/)[1]).remove();
    
        } else if ( '-1' == r ) {
            $('#ajax-response').empty().append('<div class="error"><p>' + wp.i18n.__( 'Sorry, you are not allowed to do that.' ) + '</p></div>');
            tr.children().css('backgroundColor', '');
    
        } else {
            $('#ajax-response').empty().append('<div class="error"><p>' + wp.i18n.__( 'Something went wrong.' ) + '</p></div>');
            tr.children().css('backgroundColor', '');
        }
    });
    

    The expected response to this POST request is:

    • '1' if the term was deleted
    • '-1' if your user doesn’t have permission to delete the term.

    For all other cases, "Something went wrong" is displayed.

    You are terminating the script early with wp_die, yielding an unexpected response, which comes under "other cases".

    There isn’t a way to provide a custom error message in the notice box here without writing some JavaScript of your own.

    Login or Signup to reply.
  3. This solution provides a way to disable all categories from being deleted by a non Admin. This is for anyone like myself who’s been searching.

    function disable_delete_cat() {
      global $wp_taxonomies;
      if(!current_user_can('administrator')){ 
      $wp_taxonomies[ 'category' ]->cap->delete_terms = 'do_not_allow';
      }
    }
    add_action('init','disable_delete_cat'); 
    
    Login or Signup to reply.
  4. The easiest solution (that will automatically take care of all different places where you can possibly delete the category/term) and in my opinion the most flexible one is using the user_has_cap hook:

    function maybeDoNotAllowDeletion($allcaps, $caps, array $args, $user)
    {
        if ($args[0] !== 'delete_term') return $allcaps;
    
        // you can skip protection for any user here
        // let's say that for the default admin with id === 1
        if ($args[1] === 1) return $allcaps;
    
        $termId = $args[2];
        $term = get_term($termId);
    
        // you can skip protection for all taxonomies except
        // some special one - let's say it is called 'sections'
        if ($term->taxonomy !== 'sections') return $allcaps;
    
        // you can protect only selected set of terms from
        // the 'sections' taxonomy here
        $protectedTermIds = [23, 122, 3234];
        
        if (in_array($termId, $protectedTermIds )) {
          $allcaps['delete_categories'] = false;
          // if you have some custom caps set
          $allcaps['delete_sections'] = false;
        }
    
        return $allcaps;
    }
    add_filter('user_has_cap', 'maybeDoNotAllowDeletion', 10, 4);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search