Sometimes, due to meta boxes added by plugins, the excerpt gets moved down the order in the admin page.
Is there a way I can force it to always be directly below the post content?
Here is the way I’ve tried:
function remove_wordpress_meta_boxes() {
remove_meta_box( 'postexcerpt', 'page', 'normal' );
add_meta_box('postexcerpt', __('Excerpt'), 'post_excerpt_meta_box', 'page', 'normal', 'high');
}
add_action( 'admin_menu', 'remove_wordpress_meta_boxes' );
remove_meta_box()
works as expected, but re-adding the excerpt meta box doesn’t seem to do anything to the ordering – I still have a plugin metabox appear above the excerpt.
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.