Move excerpt to always be directly below post content in admin

The reason why your code doesn’t work is most likely that you’ve ordered your metaboxes before, and the that order has been saved into the meta-box-order_page meta value. This overrides the default setup.

Here’s an example of the meta-box-order_post meta value:

a:3:{
     s:4:"side";    
         s:61:"submitdiv,formatdiv,categorydiv,tagsdiv-post_tag,postimagediv";
     s:6:"normal";  
         s:96:"revisionsdiv,postexcerpt,trackbacksdiv,postcustom,
               commentstatusdiv,commentsdiv,slugdiv,authordiv";
     s:8:"advanced";
         s:0:"";
}

Here I’ve just reformatted the serialized array for better readability.

Sticky MetaBoxes:

To move a given metabox to the top position, for a given context and post-type, you can use this code snippet:

/**
 * Set some sticky metaboxes
 */

add_action( 'admin_init', function()
{
    if( function_exists( 'wpse_sticky_metabox' ) )
    {
         // Sticky metabox #1:
         wpse_sticky_metabox(
             array(
                 'cpt'      => 'page',
                 'context'  => 'normal',
                 'metabox'  => 'postexcerpt'
             )
         );

         // Sticky metabox #2:
         wpse_sticky_metabox(
             array(
                 'cpt'      => 'post',
                 'context'  => 'side',
                 'metabox'  => 'authordiv' 
             )
         );
    }
});

where you can adjust this to your needs.

Some info on the input parameters:

  • cpt is the custom post type of the edit screen ( i.e. post, page, …)
  • context is the section where you want to make the metabox sticky. ( i.e. normal, side, advanced, … )
  • metabox is the id of the sticky meta-box ( i.e. postexcerpt, authordiv, … )

Sticky MetaBoxes – the plugin:

This is supported by the following demo plugin:

/**
 * Plugin Name: Sticky Meta-Boxes
 * Description: Set a given meta-box to the top, for a given cpt and context.
 * Plugin URI:  http://wordpress.stackexchange.com/a/174980/26350
 * Author:      Birgir Erlendsson (birgire)
 * Version:     0.0.2
 */

function wpse_sticky_metabox( $args = array() )
{
    if( class_exists( 'MetaBoxSticker' ) )
    {
        $o = new MetaBoxSticker;
        $o->setup( $args )->activate();
    }
}

class MetaBoxSticker
{
    private $args;

    public function setup( $args = array() )
    {
        $default = array(
            'cpt'      => 'post',
            'context'  => 'normal',
            'metabox'  => 'postexcerpt'
        );
        $this->args = wp_parse_args( $args, $default );
        return $this;
    }

    public function activate()
    {
        add_filter(
            sprintf(
                'get_user_option_meta-box-order_%s',
                $this->args['cpt']
            ),
            array( $this, 'filter' ),
            PHP_INT_MAX
        );

        add_action( 
            'add_meta_boxes', 
            array( $this, 'relocate' ), 
            PHP_INT_MAX 
        );
    }

    public function relocate()
    {
        //-----------------------
        // Get the user input:
        //-----------------------
        $_cpt      = sanitize_key( $this->args['cpt']     );
        $_metabox  = sanitize_key( $this->args['metabox'] );
        $_context  = sanitize_key( $this->args['context'] );

        //-----------------------
        // Relocate 'high' metaboxes to 'default' in the current context
        //-----------------------                  
        global $wp_meta_boxes;
        if( isset( $wp_meta_boxes[$_cpt][$_context]['high'] ) )
        {                                                           
            foreach( $wp_meta_boxes[$_cpt][$_context]['high'] as $id => $item )
            {
                if( isset( $item['callback'] ) )
                {
                    remove_meta_box( 
                        $id, 
                        $_cpt, 
                        $_context 
                    );

                    add_meta_box( 
                        $id, 
                        $item['title'], 
                        $item['callback'], 
                        $_cpt, 
                        $_context, 
                        'default', 
                        $item['args'] 
                    );
                }
            }
        }
    }

    public function filter( $order )
    {
        //-----------------------
        // Get the user input:
        //-----------------------                               
        $_cpt      = sanitize_key( $this->args['cpt']     );
        $_metabox  = sanitize_key( $this->args['metabox'] );
        $_context  = sanitize_key( $this->args['context'] );

        //-----------------------
        // Handle the case if the current user hasn't made any meta-box ordering before:
        //-----------------------
        if( empty( $order ) )
        {
            global $wp_meta_boxes;
            if( ! isset( $wp_meta_boxes[$_cpt][$_context] ) )
               return $order;

            $order = array();
            foreach( $wp_meta_boxes[$_cpt] as $context_key => $context_item )
            {
                $tmp = array();
                foreach( $context_item as $priority_key => $priority_item )
                {
                    foreach( $priority_item as $metabox_key => $metabox_item )
                    {
                        $tmp[] = $metabox_key;
                    }
                }
                $order[$context_key] = join( ',', $tmp );
            }
        }

        //-----------------------
        // Let's make sure the context exists:
        //-----------------------
        if( ! isset( $order[$_context] ) )
            return $order;

        //-----------------------
        // Remove the given meta-box from the whole order array:
        //-----------------------
        foreach( $order as $context_key => $string )
        {
            $tmp = explode( ',', $string );
            $key = array_search( $_metabox, $tmp );
            if( ! empty( $key ) )
            {
                unset( $tmp[$key] );
                $order[$context_key] = join( ',', $tmp );
            }
        }

        //-----------------------
        // Make the given meta-box sticky for a given context
        //-----------------------
        $tmp = explode( ',', $order[$_context] );
        array_unshift( $tmp, $_metabox );
        $order[$_context] = join( ',', $tmp );

        return $order;
    }

} // end class

This plugin should also work, even if you haven’t made any ordering before.

It also respects the Screen Options, i.e. wether a meta-box is visible or not.

I hope you can extend this further to your needs.

Leave a Comment