Using add_meta_box()

Note: Updated to be compatible with WP2.7.

Note: Technical content to follow.

In the WordPress 2.5 upgrade, Automattic completely revamped the administration interface – including the way that boxes were created for plugins (well, really the entire administration back end; however I will be focusing on plugins). Previously, you had to create the boxes manually, hard coding something to the effect of:

<div class="dbx-b-ox-wrapper">
<fieldset id="myplugin_fieldsetid" class="dbx-box">
<div class="dbx-handle-wrapper"><h3 class="dbx-handle"><?php _e( 'My Post Section Title', 'myplugin_textdomain' ); ?></h3></div>
<div class="dbx-content-wrapper">
<div class="dbx-content">
Your plugin box content here
</div>
</div>
</fieldset>
</div>

Source: http://codex.wordpress.org/Function_Reference/add_meta_box

But how do you get those slick looking boxes seen in WordPress 2.5 and WordPress 2.6 and WordPress 2.7? I looked online and I found plenty of sites detailing how to add meta boxes to the post page. However, I didn’t find anything describing how to implement the add_meta_box() function for your own plugin page.

I spent a bit of time time and reverse engineered the process. Once you have it figured out, it’s really quite simple. At the very least, it’s a lot more intuitive.

First, you’ll want to wrap your content you want to display in a function that echos it out. You’ll need a separate function for every box you want to add. After the function has been declared, you’ll want to add it using the add_meta_box() call. The usage for add_meta_box is:

<?php add_meta_box('id', 'title', 'callback', 'page', 'context', 'priority'); ?>

Here’s the PHPDoc data:
string $id String for use in the ‘id’ attribute of tags.
string $title Title of the meta box
string $callback Function that fills the box with the desired content. The function should echo its output.
string $page The type of edit page on which to show the box (post, page, link)
string $context The context within the page where the boxes should show (‘normal’, ‘advanced’)
string $priority The priority within the context where the boxes should show (‘high’, ‘low’)

add_meta_box simply adds the box to a queue. It doesn’t actually spit out any code. Thus, after you’ve created all the content callback functions and added them to the meta box queue with add_meta_box, you’ll need to execute do_meta_boxes().

<?php do_meta_boxes('page', 'context', 'object'); ?>

string $page The edit page which you want to display; this will be the same as $page specified in add_meta_box.
string $context The context within the page where the boxes should show (‘normal’, ‘advanced’).
? $object I don’t know, I just have it set to null.

All together, the code might look something like:

<?php
function yourplugin_helloworld_meta_box(){
?>
Hello, world!
<?php
}
add_meta_box("yourplugin_helloworld", __('Say Hello', 'yourplugin'), "yourplugin_helloworld_meta_box", "yourplugin");
do_meta_boxes('yourplugin','advanced',null);
?>

One weird/interesting thing I discovered is that ‘yourplugin’ can only consist of lowercase letters a-z and the hyphen “-” symbol. For all you programmers, it must return true when matched against /^[a-z-]+$/

I don’t know what, but that’s the check run on line 620 of /wp-admin/admin-ajax.php from WordPress 2.6.2.

That’s the most basic level of creating your own meta boxes. However, there’s more. Do you notice how sometime the meta boxes are closed on the posts (or pages, or links) page? The open/closed position is remembered using some AJAX. The actual data is stored per user in the wp_usermeta table with a meta_key of ‘closedpostboxes_yourplugin’. The data is a serialized array that lists just the closed the boxes.

To get this functionality, you’ll need to perform a couple more steps. First, you’ll need to add some javascript. This code does two things, on load it closes boxes that should be closed (because they were previously closed) and it allows the boxes to be toggled open and closed.

jQuery(document).ready( function($) {
	// close postboxes that should be closed
	jQuery('.if-js-closed').removeClass('if-js-closed').addClass('closed');
		
	// postboxes
	<?php
	global $wp_version;
	if(version_compare($wp_version,"2.7-alpha", "<")){
		echo "add_postbox_toggles('yourpluging');"; //For WP2.6 and below
	}
	else{
		echo "postboxes.add_postbox_toggles('yourplugin');"; //For WP2.7 and above
	}
	?>
			
});

You’ll also need to add this PHP code:

<?php
wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false );
wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false );
?>

This code registers a new nonce that your plugin will use to send authorized AJAX requests.

And that’s it. Give a holler in the comments if you have questions and I’ll try my best to answer them.

See also: http://xref.fergcorp.com/

21 Replies to “Using add_meta_box()”

  1. Thanks for the second part of your post. I will use the hook for own boxes in my blugon-page. when i use your code, the have all bboxes non style from WordPress. is it not posible to use the design of WordPress?

  2. @Andrew: i have write a test-plugin with your code. Now i have the boxes in my plugin-page, non deisgn of wordpress, only the text and the html. I think, wordpress have not the css for this html in the gloval.css and wp-admin.css or give it a function for include the design of WordPress Adminarea. I have found fuctions for add the javascript to use drag&drop of the boxes.

    wp_enqueue_script('postbox');
    wp_enqueue_script('jquery-ui-draggable');
    

    I will use the do_Action Hook and add my own boxes. I like the design of the boxes in WordPress and i will use the deisg of WordPress, the same in dashbaord, link, edit-pages.
    THX

  3. I’ve used the add_meta_box action to place a box on the post screen.
    In 2.6 the box is at the top of the advanced boxes. Now in 2.7 my box is at the bottom of the pile. Do you know what would be needed to move a box to the top? I know I could drag it, but a novice user may not know to drag and may not find the box if there’s many.
    Also I’ve noticed that the idea “Advanced” isn’t present on the new 2.7 screen.
    So I wonder what “context” may imply now. maybe instead of (normal or advanced) it’s (normal or side).

  4. Yes I am, the 2.7 post-edit screen doesn’t have an “advanced” area. So what does advanced do? and normal? I know your post is about how to add metabox to a plugin settings screen, but I thought maybe you knew plenty about the metabox. I’ve recently added one for a plugin to do advanced shortcode insert into post.

  5. For putting on post and page pages, function called is my_writebox which creates the box content:

    function my_print_box() {
    if (is_admin ()) {

    if( function_exists( 'add_meta_box' )) {
    add_meta_box( 'my_section', __( 'Add my-box', $my_domain ), array(&$this,'my_writebox'), 'post', 'advanced', 'high');
    add_meta_box( 'my_section', __( 'Add SuperSlider-show', $my_domain ), array(&$this,'my_writebox'), 'page', 'advanced', 'high' );
    }
    }
    }

  6. Hello Andrew. Because lack of information at codex pages i did investigate more deeply this metabox thing. I need a complete working meta box implemenation at my own plugin pages. So i wrote an example plugin that demonstrates this and also an article (2.7 related, download of example plugin also contained) that descibes: How to use meta boxes at your own plugin pages
    Now you should able to use the meta box concept inside you own plugin pages too.
    Should answer some open questions, isn’t it ?

  7. Just a note – the regular expression you put to match the plugin name is not accurate. You can’t put hyphen at the end of a character class without sometimes having unpredictable results, since a hyphen also denotes a character range. In order to represent a literal hyphen, it has to be at the start.

    It should have been /^[-a-z]+$/

  8. Thanks for the tutorial! I’m trying to understand this metabox stuff and it’s very complex.

    object seems to be passed as parameter to the callback, so I believe you’d pass it if your callback function needs it. Probably it’s just an array of parameters, to allow the code that adds the metabox to send data to the metabox generation code.

    1. @Joshua: I don’t know off the top of my head, but I’d imagine you could do some JS validation on the front end to check if a box is being moved to a different column and then declare the move as FALSE to reject it.

  9. Thanks Andrew, really helpful start.

    To take it a bit further for WordPress 3.2.1 The add_meta_box call has an undocumented argument allowing you to pass an argument to the function you define

    add_meta_box($id, $title, $callback, $page, $context = ‘advanced’, $priority = ‘default’, $callback_args=null)

    when it is called by do_meta_boxes it uses the following
    call_user_func($box[‘callback’], $object, $box);
    This would make your callback look like this
    myMetaBoxRender($object,$box){
    //acces inside your function to what ever you passed like this
    echo $box[‘args’];
    }

    And notice that $object is also passed in – that’s what the final argument of do_meta_boxes was !

    yippee – dynamic metaboxes

Leave a Reply

Your email address will not be published. Required fields are marked *