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/

7ads6x98y