I have a custom meta box for a custom post type that my client wants placed between the title/permalink section and the post editor in the admin panel. Is this possible and if so is there a hook/filter/etc that I would need to use?
5 Answers
- Simply add a meta box using the advanced context, and high priority
- Then, latch on to the
edit_form_after_title
hook Print your meta boxes out there, then remove it so it doesn't appear twice.
// Move all "advanced" metaboxes above the default editor add_action('edit_form_after_title', function() { global $post, $wp_meta_boxes; do_meta_boxes(get_current_screen(), 'advanced', $post); unset($wp_meta_boxes[get_post_type($post)]['advanced']); });
-
A site I'm working on registers some metaboxes using the
register_meta_box_cb
parameter of theregister_post_type
function. I've tried your code but the metaboxes don't move above the editor. Can this be used in my case? Thanks– leemonCommented Aug 28, 2016 at 18:57 -
3I would recommend using a custom
$context
, instead ofadvanced
, use something likemy_before_editor
, so that you do not move all meta boxes in theadvanced
context, you specifically target your specific meta boxes .. see developer.wordpress.org/reference/functions/add_meta_box Commented Dec 8, 2017 at 21:41 -
1
edit_form_after_title
not supported by block editor github.com/WordPress/gutenberg/issues/5821– FankyCommented Jun 9, 2022 at 12:29
Here is how you can move specific meta boxes above the editor, but before I post the code I just would like to thank Andrew and mhulse. You guys rock!
function foo_deck( $post_type ) {
if ( in_array( $post_type, array( 'post', 'page' ) ) ) {
add_meta_box(
'contact_details_meta',
'Contact Details',
'contact_details_meta',
$post_type,
'test', // change to something other then normal, advanced or side
'high'
);
}
}
add_action('add_meta_boxes', 'foo_deck');
function foo_move_deck() {
# Get the globals:
global $post, $wp_meta_boxes;
# Output the "advanced" meta boxes:
do_meta_boxes( get_current_screen(), 'test', $post );
# Remove the initial "advanced" meta boxes:
unset($wp_meta_boxes['post']['test']);
}
add_action('edit_form_after_title', 'foo_move_deck');
-
1
change to something other then normal, advanced or side
-was the key in my case. Thanks for the info. Commented Sep 28, 2014 at 9:39 -
To provide a full code example based on Andrew's answer ... I needed a way to include a "Deck" (aka subhead) to my posts; I wanted the deck field to appear after the main title bar.
/**
* Add a "deck" (aka subhead) meta box to post page(s) and position it
* under the title.
*
* @todo Move to class.
* @see http://codex.wordpress.org/Function_Reference/add_meta_box
* @see http://wordpress.org/extend/ideas/topic/add-meta-box-to-multiple-post-types
* @see https://github.com/Horttcore/WordPress-Subtitle
* @see http://codex.wordpress.org/Function_Reference/wp_nonce_field
*/
# Adds a box to the main column on the Post and Page edit screens:
function foo_deck($post_type) {
# Allowed post types to show meta box:
$post_types = array('post', 'page');
if (in_array($post_type, $post_types)) {
# Add a meta box to the administrative interface:
add_meta_box(
'foo-deck-meta-box', // HTML 'id' attribute of the edit screen section.
'Deck', // Title of the edit screen section, visible to user.
'foo_deck_meta_box', // Function that prints out the HTML for the edit screen section.
$post_type, // The type of Write screen on which to show the edit screen section.
'advanced', // The part of the page where the edit screen section should be shown.
'high' // The priority within the context where the boxes should show.
);
}
}
# Callback that prints the box content:
function foo_deck_meta_box($post) {
# Use `get_post_meta()` to retrieve an existing value from the database and use the value for the form:
$deck = get_post_meta($post->ID, '_deck', true);
# Form field to display:
?>
<label class="screen-reader-text" for="foo_deck">Deck</label>
<input id="foo_deck" type="text" autocomplete="off" value="<?=esc_attr($deck)?>" name="foo_deck" placeholder="Deck">
<?php
# Display the nonce hidden form field:
wp_nonce_field(
plugin_basename(__FILE__), // Action name.
'foo_deck_meta_box' // Nonce name.
);
}
/**
* @see https://wordpress.stackexchange.com/a/16267/32387
*/
# Save our custom data when the post is saved:
function foo_deck_save_postdata($post_id) {
# Is the current user is authorised to do this action?
if ((($_POST['post_type'] === 'page') && current_user_can('edit_page', $post_id) || current_user_can('edit_post', $post_id))) { // If it's a page, OR, if it's a post, can the user edit it?
# Stop WP from clearing custom fields on autosave:
if ((( ! defined('DOING_AUTOSAVE')) || ( ! DOING_AUTOSAVE)) && (( ! defined('DOING_AJAX')) || ( ! DOING_AJAX))) {
# Nonce verification:
if (wp_verify_nonce($_POST['foo_deck_meta_box'], plugin_basename(__FILE__))) {
# Get the posted deck:
$deck = sanitize_text_field($_POST['foo_deck']);
# Add, update or delete?
if ($deck !== '') {
# Deck exists, so add OR update it:
add_post_meta($post_id, '_deck', $deck, true) OR update_post_meta($post_id, '_deck', $deck);
} else {
# Deck empty or removed:
delete_post_meta($post_id, '_deck');
}
}
}
}
}
# Get the deck:
function foo_get_deck($post_id = FALSE) {
$post_id = ($post_id) ? $post_id : get_the_ID();
return apply_filters('foo_the_deck', get_post_meta($post_id, '_deck', TRUE));
}
# Display deck (this will feel better when OOP):
function foo_the_deck() {
echo foo_get_deck(get_the_ID());
}
# Conditional checker:
function foo_has_subtitle($post_id = FALSE) {
if (foo_get_deck($post_id)) return TRUE;
}
# Define the custom box:
add_action('add_meta_boxes', 'foo_deck');
# Do something with the data entered:
add_action('save_post', 'foo_deck_save_postdata');
/**
* @see https://wordpress.stackexchange.com/questions/36600
* @see https://wordpress.stackexchange.com/questions/94530/
*/
# Now move advanced meta boxes after the title:
function foo_move_deck() {
# Get the globals:
global $post, $wp_meta_boxes;
# Output the "advanced" meta boxes:
do_meta_boxes(get_current_screen(), 'advanced', $post);
# Remove the initial "advanced" meta boxes:
unset($wp_meta_boxes['post']['advanced']);
}
add_action('edit_form_after_title', 'foo_move_deck');
Obviously, the code above could use some more work, but it should help others trying to do the same stuff (Andrew's answer shined light, but I thought it might be helpful to actually provide a working example).
Improvements that could be made:
- Make OOP/class(es).
- Add styles/js to make it look/feel/behave like the title field.
I plan on making the above improvements at some point in future, but at least the above code should help others trying to figure this out.
See source code here for more inspiration (they opted to use jQuery to move the "sub-title").
-
In case it helps anyone going down the same path: I've asked a question here which has some related/similar code (I opted to use the "title" field to hold and filter the subhead).– mhulseCommented May 21, 2013 at 0:14
Instead of moving everything in the advanced section to the top, why not create a new section and move that to the top:
// Create 'top' section and move that to the top
add_action('edit_form_after_title', function() {
global $post, $wp_meta_boxes;
do_meta_boxes(get_current_screen(), 'top', $post);
unset($wp_meta_boxes[get_post_type($post)]['top']);
});
Now all you need to do is register the meta box using top
for the section and high
for the priority.
It's working on WordPress 4.4.2 for me. I haven't tested this on other WP versions.
There is an other way, by the way we can put the editor to any position:
Remove editor from support param when you register post_type
add a fake metabox
add_meta_box( 'does-not-matter', __( 'Description'), function($post){ wp_editor($post->post_content,'post_content',array('name'=>'post_content')); }, 'post_type_type', 'advanced', 'high' );
-
FYI, this still works, but when you move the box it causes some weird behavior with the content of the field. Users beware.– EcksteinCommented Feb 12, 2018 at 4:19