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.