Disable dragging of meta boxes?

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

Related posts

Leave a Reply

8 comments

  1. 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!

  2. 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. 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' );
    
  4. 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");
    });
    
  5. 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.

  6. 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.

  7. 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.

  8. 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' );