I recently had a request to move a WordPress custom metabox created with the Toolset Types plugin above the WYSIWYG Editor (a.k.a. Visual Editor).
While this seems like a simple request, as so often happens in programming this was more complex than expected.
The Solution
The solution is to check the global variable $wp_meta_boxes
early (specifically just before the WYSIWYG editor, on the edit_form_after_title
hook).
If your metabox appears in $wp_meta_boxes
, you output it early and then remove the metabox from $wp_meta_boxes
(so it doesn’t display a second time).
This code was funded by Blinebury Design. Thanks to their generosity, this code is now available on GitHub (or you can copy it from below).
If you find this code useful, you might want to send them a tweet of thanks.
Moving Your Metabox
In addition to the plugin code, you’ll need to add a code snippet to tell the plugin which metabox to move.
Step 1: Find the Group ID of Your Metabox
When editing the metabox in Toolset Types, find the group_id
value in the URL.
In this screenshot, the group_id
is 4
.
Step 2: Add the Configuration Code
You can add this code in your theme’s functions.php
(or in a mu-plugin).
add_filter( 'fe_tmm_move_metabox_after_title_ids', function ( $group_ids ) {
// Add 4 to the list of Group IDs to move above the WYSIWYG editor (by default this list is empty).
$group_ids[] = 4;
return $group_ids;
} );
Plugin Code
This is the code available on GitHub at salcode/toolset-metabox-move-above-wysiwyg. This code needs to be running, in addition to the configuration code you created above.
<?php
/**
* Plugin Name: Move Toolset Metabox Above WYSIWYG Editor
* Plugin URI: http://salferrarello.com/move-toolset-metabox-above-wysiwyg-editor/
* Description: Allows moving metaboxes created with the Toolset plugin above the WYSIWYG editor, with the filter <strong>fe_tmm_move_metabox_after_title_ids</strong>. Example: <code>add_filter( 'fe_tmm_move_metabox_after_title_ids', function ( $ids ) { $ids[] = 1813; return $group_ids; } );</code>
* Version: 1.0.0
* Author: Sal Ferrarello
* Author URI: http://salferrarello.com/
* Text Domain: toolset-metabox-move-above-wysiwyg
* Domain Path: /languages
*
* Example filter to move Toolset metaboxes 1813 and 1820 above the WYSIWYG editor.
* add_filter( 'fe_tmm_move_metabox_after_title_ids', function ( $group_ids ) {
* $group_ids[] = 1813; // Move group id 1813 above the WYSIWYG editor.
* $group_ids[] = 1820; // Move group id 1820 above the WYSIWYG editor.
* return $group_ids;
* } );
*
* @package toolset-metabox-move-above-wysiwyg
*/
// If this file is called directly, abort.
if ( ! defined( 'WPINC' ) ) {
die;
}
add_action( 'edit_form_after_title', 'fe_tmm_move_metabox_after_title' );
/**
* Move a Metabox created with the Toolset plugin after the title on the editor page.
*
* In other words, move the metabox above the WYSIWYG editor.
*
* @hook filter fe_tmm_move_metabox_after_title_ids An array of metabox Group IDs to move below the title.
*/
function fe_tmm_move_metabox_after_title() {
global $post, $wp_meta_boxes;
$group_ids = apply_filters( 'fe_tmm_move_metabox_after_title_ids', array() );
$post_type = get_post_type( $post );
// Contexts are: [ 'normal', 'advanced' ].
$context = 'normal'; // Toolset Types uses a context of 'normal', from available context
// Priorities are: [ 'default', 'high', 'low' ].
$priority = 'high'; // Toolset Types uses a priority of 'high'.
foreach ( $wp_meta_boxes[ $post_type ][ $context ][ $priority ] as $key => $metabox ) {
if ( 'wpcf-group-' === substr( $key, 0, 11 ) && in_array( $wp_meta_boxes[ $post_type ][ $context ][ $priority ][ $key ]['args']['id'], $group_ids, true ) ) {
$box = $wp_meta_boxes[ $post_type ][ $context ][ $priority ][ $key ];
// Render the single metabox.
fe_tmm_do_single_meta_box( $box, get_current_screen(), $post );
// Remove the metabox we rendered for $wp_meta_boxes, to prevent rendering a second time.
unset( $wp_meta_boxes[ $post_type ][ $context ][ $priority ][ $key ] );
}
}
}
/**
* Display a Single Metabox
*
* This code is taken from the do_meta_boxes() function in
* /wp-admin/includes/template.php
*
* @param array $box An associative array defining a single metabox.
* @param string|WP_Screen $screen Screen identifier
* @param mixed $object gets passed to the box callback function as first parameter.
*/
function fe_tmm_do_single_meta_box( $box, $screen, $object ) {
$page = $screen->id;
$hidden_class = '';
echo '<div id="' . $box['id'] . '" class="postbox ' . postbox_classes($box['id'], $page) . $hidden_class . '" ' . '>' . "\n";
if ( 'dashboard_browser_nag' != $box['id'] ) {
$widget_title = $box[ 'title' ];
if ( is_array( $box[ 'args' ] ) && isset( $box[ 'args' ][ '__widget_basename' ] ) ) {
$widget_title = $box[ 'args' ][ '__widget_basename' ];
// Do not pass this parameter to the user callback function.
unset( $box[ 'args' ][ '__widget_basename' ] );
}
echo '<button type="button" class="handlediv button-link" aria-expanded="true">';
echo '<span class="screen-reader-text">' . sprintf( __( 'Toggle panel: %s' ), $widget_title ) . '</span>';
echo '<span class="toggle-indicator" aria-hidden="true"></span>';
echo '</button>';
}
echo "<h2 class='hndle'><span>{$box['title']}</span></h2>\n";
echo '<div class="inside">' . "\n";
call_user_func($box['callback'], $object, $box);
echo "</div>\n";
echo "</div>\n";
}
Hi,
This doesn’t seem to work with Gutenberg. Is there a solution for that?