2

To remove a metabox from all post types at once, using a foreach seems like the logical thing to do. However it doesn't always work and I don't understand why.

For examlple viewing the "Post" post type the following only removes the trackbacksdiv :

function remove_metabox_from_all_post_types() {
$post_types = get_post_types();
foreach ( $post_types as $post_type )
            remove_meta_box('trackbacksdiv', $post_type, 'normal');
            remove_meta_box('postcustom', $post_type, 'normal');
            remove_meta_box('authordiv', $post_type, 'normal');
            remove_meta_box('postexcerpt', $post_type, 'normal');

}
add_action('admin_menu', 'remove_metabox_from_all_post_types', 999);

While this removes all of them when viewing the "Post" post type:

function remove_metabox_from_all_post_types() {
$post_types = get_post_types();
foreach ( $post_types as $post_type )
            remove_meta_box('trackbacksdiv', 'post', 'normal');
            remove_meta_box('postcustom', 'post', 'normal');
            remove_meta_box('authordiv', 'post', 'normal');
            remove_meta_box('postexcerpt', 'post', 'normal');

}
add_action('admin_menu', 'remove_metabox_from_all_post_types', 999);

I would think that get_post_types is fired after the metaboxes are registered, but that's the only reason I can guess it's not working the first way, unless it's a careless syntax error that I'm not picking up. I tried using the do_metaboxes actions hook as well but it didn't make a difference.

Any ideas?

2 Answers 2

7

Remember Apple's "Goto Fail"?

Similar situation:

Your code actually does this, when indentation is corrected:

 foreach ( $post_types as $post_type )
        remove_meta_box('trackbacksdiv', $post_type, 'normal');

 remove_meta_box('postcustom', $post_type, 'normal');
 remove_meta_box('authordiv', $post_type, 'normal');
 remove_meta_box('postexcerpt', $post_type, 'normal');

So, it should does the job for trackbacksdiv, but not for the rest because the function calls are outside of the foreach and $post_type is not defined.

If you replace $post_type with post it works, because..well, the function arguments are complete.

Wrap your foreach in { } and try it again.

5
  • An re-formatting or re-indenting editor would have corrected the indentation making this issue obvious, preventing it from ever have occurring
    – Tom J Nowell
    Jul 8, 2014 at 20:10
  • Thanks for the answer. I knew it was something obvious I wasn't noticing like wrapping the foreach. It works fine with just wrapping the foreach. I am curious about the $ post_type vs post method. Can you give an example of that? Jul 10, 2014 at 7:13
  • @TomJNowell not obvious for airheads apparently. I actually was using the code snippets plugin which was correcting indentation but I kept thinking there was something wrong with the editor. Thanks for pointing that out though haha Jul 10, 2014 at 7:21
  • By the way for any else making this dumb mistake an foreach($post_types as $post_type): .... endforeach; should work as well Jul 10, 2014 at 7:28
  • 1
    I'd advise against the shorthand syntax as its not as well supported by editors, try installing a PHP Mess Detector package in your editor, and it'll pick up a lot of common mistakes
    – Tom J Nowell
    Jul 10, 2014 at 12:32
5

Please note, this should not be the accepted answer, this is only an extension to the answer given by @ungestaltbar, so please, @willow, accept the other answer, and if you deemed my answer useful, simply just give me an upvote :-)

The biggest issue that should solve your problem have been discussed in the other answer, but I would like to point out some other issues, as I personally think that your code is not fully optimized and running unnecessary.

As your code currently stands, you have the following issues:

  • your code runs on every single page load on front end, unnecessarily. You would only want your code to run on an admin screen, back end. For this you can use the is_admin() conditional tag to check if you are on a admin screen

  • get_post_types gets all post types, which is unnecessary, you only want to get the public post types

  • If you need this code to run for only admin (current_user_can('manage_options')), or non-admin (!current_user_can('manage_options')), you should specify this

  • The proper fail safe hook to use here would be add_meta_boxes to hook your function to. This will make sure that all meta boxes are loaded before they are removed.

So, putting this all together, your code should look like this

function remove_metabox_from_all_post_types() {
    if( is_admin() && current_user_can('manage_options') ) {
    $args = array(
       'public'   => true,
    );
    $output = 'names'; // names or objects, note names is the default
    $operator = 'and'; // 'and' or 'or'

    $post_types = get_post_types( $args, $output, $operator ); 
        foreach ( $post_types  as $post_type ) {
            remove_meta_box('trackbacksdiv', $post_type, 'normal');
            remove_meta_box('postcustom', $post_type, 'normal');
            remove_meta_box('authordiv', $post_type, 'normal');
            remove_meta_box('postexcerpt', $post_type, 'normal');
        }
    }
}
add_action('add_meta_boxes', 'remove_metabox_from_all_post_types', 999);
2
  • Appreciate the added suggestions. I've always used admin_menu or do_meta_boxes as the action hook. WordPress.org actually says to use admin_menu. Why is add_meta_boxes preferred? Jul 10, 2014 at 7:49
  • 1
    Please have a look at remove_meta_box`. I also don't say your methods are wrong, neither are mine correct. Anyone of these hooks will work. This is just a suggestion, one which has always worked for me :-) Jul 10, 2014 at 9:00

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.