20

Anyone know how to disable this functionality so the meta boxes can't be repositioned?

8 Answers 8

15

I had the same problem, and Google lead me here. Unfortunately none of these answers helped, but I ultimately figured out the answer, and it's quite easy!

  1. First, enqueue a JavaScript file (I won't rehash this process; there are many tutorials that can describe this process better than I). I hooked into admin_enqueue_scripts, and it worked fine.
  2. Disable the sorting functionality by putting this in that JavaScript file:

    jQuery(document).ready( function($) {
        $('.meta-box-sortables').sortable({
            disabled: true
        });
    
        $('.postbox .hndle').css('cursor', 'pointer');
    });
    

Essentially this just disables jQuery UI Sortable, which powers the metabox dragging functionality (postbox.dev.js:64). This also switches the cursor on the metabox handle to a standard mouse pointer instead of a move cursor (idea courtesy of brasofilo below).

Hope this helps!

Edit: I should add that it's probably worth following some of the other advice here and disabling the saving of the metabox order. It will prevent confusion on the off-chance something gets mistakenly re-enabled.

Second edit: For the benefit of future generations (and future Google searchers), this fix was tested on WordPress 3.3.1. I can't speak to other versions!

3
  • +1 less hassle free solution for the Q, IMHO of course. And lots of heavy-weights weighted in ;) :::: I'm using only the JS for all, adding $('.postbox .hndle').css('cursor','default'); :::: Re: 2nd edit, you'll have to keep updating the Answer in the foreseeable future :P
    – brasofilo
    Jan 6, 2013 at 16:27
  • Manipulating the CSS from the JS is clever! I'll add that to my answer. Jan 11, 2013 at 21:15
  • This code is working with current WordPress 3.9.1 - very nice! :)
    – Philipp
    Jul 27, 2014 at 14:41
4

I answered a similar question with the suggestion to allow dragging, but disable saving the new order on the server side. This might give you more control, and be more future-proof as the JavaScript could change quickly, but the protocol to communicate with the server might stay more robust. This example disables all dragging, but you could expand it to check for your specific box or meta page.

add_action('check_ajax_referer', 'prevent_meta_box_order');
function prevent_meta_box_order($action)
{
   if ('meta-box-order' == $action /* && $wp_user == 'santa claus' */) {
      die('-1');
   }
}
3
  • Thanks Jan - I added this to my functions.php but it doesn't do anything?
    – fxfuture
    Oct 6, 2010 at 9:25
  • @fxfuture: Silly me, check_ajax_referer is an action, not a filter. You should just die() there to end script execution, not return anything. I'll fix my code.
    – Jan Fabry
    Oct 6, 2010 at 10:55
  • Yea, your correction doesn't work..Or, FireFox and Chrome are caching the page for some reason. :/
    – Zack
    Feb 2, 2011 at 21:47
3

The fastest way is deactivate the JS for this function. But i think, it is better when you also deregister the style for the box and init a custom style without the effects for the mouse and the open/close icon on the meta boxes.

function fb_remove_postbox() {
    wp_deregister_script('postbox');
}
add_action( 'admin_init', 'fb_remove_postbox' );
6
  • what about if you just want to disable the dragging for a specific metabox on a specific custom post type? Oct 4, 2010 at 8:18
  • 4
    This works but it also disables other functionality like post status
    – fxfuture
    Oct 6, 2010 at 9:45
  • I think yes, but i dont test this. You can hide with the plugin Adminimize as an easy way.
    – bueltge
    Oct 7, 2010 at 19:38
  • 1
    Nice one! How would we dispatch that admin_init only in some specific post type?
    – brasofilo
    Jan 6, 2013 at 16:15
  • 1
    seemed a perfect solution at first - but alas - this also disables all functionality for adding category/taxonomy...
    – ptriek
    Nov 12, 2013 at 15:07
3

The wordpress javascript identifies the draggable metaboxes by their h3 title with a class of "hndle". It's simple enough to disable these specifically by referencing the metabox in question (if you are creating custom metaboxes, you will have assigned it an identifier) and disabling any hndle classes by removing the classname or by renaming it. In my case, I have several separator types that I labeled with .hndle h3's, but it is unlikely anyone else will have done things this way. So, you can do what I did below, or you may use .find('.hndle').attr('class','').... or something similar. This would go in a .js file that you enqueued in your functions.php file (whether it be in your themes folder or your plugins folder). The enqueueing would be called by an admin_print_scripts, init or whatever hook you prefer to use to add stuff to your admin pages.

jQuery("#MY_METABOX_ID h3.hndle").each(function(e){
jQuery(this).attr("class", "hndlle");
});
2

I would also add this Javascript Hack :

<script type='text/javascript'>
    jQuery(document).ready(function ($) {
        $('.handlediv').remove();
    });
</script>

... and this CSS :

.postbox .hndle:hover {
    cursor:default;
}

I used that code to take advantage of the meta boxes but without the drag-and-drop and the open/close functions.

1
  • Good addition to @bueltge answer ( i used a combination of both ) - though you could also skip the jQuery bit, and add .postbox:hover .handlediv { display:none; } in CSS to hide the .handlediv
    – ptriek
    Nov 12, 2013 at 9:25
1

Just found the simple way, hope new seeker would helped with this. Assuming you could adding a css file on admin enqueue style, I only using css to do that and sorry for my bad english.

.postbox#your-metabox-id .ui-sortable-handle {
    pointer-events: none;
}

Hope it helps.

0

I noticed this question has remain unaswered, insofar as the asker not selecting a correct answer.

Jan gave a working example of stopping the metabox re-ordering being saved over Ajax, whilst others gave suggestions relating to the JS.

As far as i understand it all you want to do is disable dragging, nothing more. To do that you'll need two things, firstly a function to intercept the ajax saving action, but secondly you also need to stop the JS dragging and dropping without killing of functionality anywhere else in the page, whilst also being to do it selectively for a post type or particular metabox.

Using Jans function and some jQuery we can do that without totally killing other functionality the postbox script creates, like so..

PHP Code for theme functions file or plugin file

Uncomment 1 of the appropriate lines to make the enqueue work.

add_action( 'admin_enqueue_scripts' , 'disable_metabox_dragging' );
add_action( 'check_ajax_referer',     'disable_metabox_ordering' );

function disable_metabox_dragging( $hook ) {

    if( !in_array( $hook, array( 'post.php', 'post-new.php' ) ) )
        return;

    global $post_type;
    if( !in_array( $post_type, array( 'book' ) ) )
        return;

    // Uncomment the following line if using inside a child theme
    //wp_enqueue_script( 'unsortable-meta', trailingslashit( get_stylesheet_directory_uri() ) . 'unsortable-metaboxes.js', array(), false );

    // Or uncomment the following line if using inside a parent theme
    //wp_enqueue_script( 'unsortable-meta', trailingslashit( get_template_directory_uri() ) . 'unsortable-metaboxes.js', array(), false );

    // Or ncomment the following line if using inside a plugin file
    //wp_enqueue_script( 'unsortable-meta', plugins_url( '/unsortable-metaboxes.js', __FILE__ ), array(), false );
}

function disable_metabox_ordering($action) {

    global $post_type;
    if( !in_array( $post_type, array( 'book' ) ) )
        return;

    if( 'meta-box-order' == $action )
        die;
}

jQuery/JS for the Javascript file referenced in the above

Very basic jquery that removes the metabox sortable class from appliable elements, this prevents the dragging.

jQuery(document).ready(function($){
    $('.meta-box-sortables').removeClass('meta-box-sortables');
});

As you can see i've added in 1 example post type to add the code, book in this case. However you mentioned wanting to also have the possibility of disabling it for specific metaboxes.

It can be done, there's just a few small side-effects one of those being, that by removing classes from given metaboxes to prevent dragging, you do also prevent the toggle function working(ie. the metabox title toggle functionality).

That said, it can be done...

First, you'd update the disable_metabox_dragging function to..

function disable_metabox_dragging( $hook ) {

    if( !in_array( $hook, array( 'post.php', 'post-new.php' ) ) )
        return;

    global $post_type;
    if( !in_array( $post_type, array( 'book' ) ) )
        return;

    // Uncomment the following line if using inside a child theme
    // wp_enqueue_script( 'some-unsortables', trailingslashit( get_stylesheet_directory_uri() ) . 'unsortable-somemetaboxes.js', array('postbox') );

    // Or uncomment the following line if using inside a parent theme
    //wp_enqueue_script( 'some-unsortables', trailingslashit( get_template_directory_uri() ) . 'unsortable-somemetaboxes.js', array('postbox') );

    // Or uncomment the following line if using inside a plugin file
    //wp_enqueue_script( 'some-unsortables', plugins_url( '/unsortable-somemetaboxes.js', __FILE__ ), array('postbox') );

    wp_localize_script( 'some-unsortables', 'NonDragMetaboxes', array( 0 => '', 'postcustom', 'postexcerpt' ) );
}

Again, noting you need to uncomment the applicable wp_enqueue_script line.

The array inside the localize call is what determines which metaboxes to disable, the empty 0 keyed item is there purposely because the localize script function strips any 0 keyed indexes in the array.

Second, the new JS file referenced in the above tweaked enqueue function.

jQuery(document).ready(function($){
    // For each item in the JS array created by the localize call
    $.each( NonDragMetaboxes, function(index,value) {

        // Remove postbox class(disables drag) and add stuffbox class(styling is close to the original)
        $( '#' + value ).removeClass('postbox').addClass('stuffbox');

        // Remove redundant handle div
        if( $( '#' + value ).has('.handlediv') )
            $( '#' + value ).children('.handlediv').remove();

        // Remove redundant cursor effect on hover
        if( $( '#' + value ).has('h3') )
            $( '#' + value ).children('h3').css('cursor','default');
    } );
});

Only thing you need do is determine the ID for the metaboxes you want to hide, and pass them into the array that sets the disabled metaboxes(in the wp_localize_scipt call).

Overall i don't think selectively disabling metaboxes is short of drawbacks, there's just no support to re-config the sortable init action in WordPress, so disabling metabox sorting on a per element basis is going to be hacky at best(my code above is evidence of that). Ideally, what's needed here is an action in WordPress to hook the sortable init, but that's currently hardcoded into the postbox javascript(which does more than just setup sortable).

In any case, i hope that's helped address the original question.

1
  • 1
    Note: This code is not working anymore with current version of WordPress (3.9.1)
    – Philipp
    Jul 27, 2014 at 14:37
0

To add to all of the previous answers, if you also want to prevent WordPress from loading custom positions, the following should do the trick (replace post with any post type):

add_filter( 'get_user_option_meta-box-order_post', '__return_empty_string' );

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.