Recently for a theme I was building I found myself in need of some custom metaboxes to be filled with data by the users. The default “custom fields” box can work, but it can also be confusing to people who don’t really know what their doing. It’s also a lot easier to tell someone to “check the “proofread” checkbox” instead of telling them to select “proofread” item from the “name” column and then type “true” into the corresponding “value” text area. There are a lot of reasons why you might do this, not the least of which is that it makes things cleaner on the back end.
Anyway, I came across a really great, and fairly lightweight function at wefunction.com that makes it really simple to add new metaboxes. It’s really great too because it stores all of the data as a serialized array which can cut down on mysql retrieval costs if you’re needing to pull down a lot of these at once. But, the function he gives doesn’t work if you need a checkbox (which I needed). So I’ve made a simple, but important modification to allow for more flexible input. This is the full code that you would put into your functions.php file:
<?php
$key = "GSD"; //table prefix do not change once set
$meta_boxes = array(
"callnumber" => array(
"name" => "callnumber",
"title" => "Call Number",
"description" => "enter in the unique library call number for this record",
"type" => "text"
),
"curated" => array(
"name" => "curated",
"title" => "Curated",
"description" => "Is this post curated?",
"type" => "checkbox"
)
);
function create_meta_box() {
global $key;
if( function_exists( 'add_meta_box' ) ) {
add_meta_box( 'new-meta-boxes', ucfirst( $key ) . ' Custom Options', 'display_meta_box', 'post', 'normal', 'high' );
}
}
function display_meta_box() {
global $post, $meta_boxes, $key;
?>
<div>
<?php
wp_nonce_field( plugin_basename( __FILE__ ), $key . '_wpnonce', false, true );
foreach($meta_boxes as $meta_box) {
$data = get_post_meta($post->ID, $key, true);
?>
<div>
<label for="<?php echo $meta_box[ 'name' ]; ?>"><?php echo $meta_box[ 'title' ]; ?></label>
<?php if( $meta_box[ 'type' ] == "text"): ?>
<input type="type" name="<?php echo $meta_box[ 'name' ]; ?>" value="<?php echo htmlspecialchars( $data[ $meta_box[ 'name' ] ] ); ?>" />
<?php elseif($meta_box[ 'type' ] == "checkbox") : ?>
<input type="checkbox" name="<?php echo $meta_box[ 'name' ]; ?>" <?php if( $data[ $meta_box[ 'name' ] ] ) echo "checked='checked'"; ?> value="true"/>
<?php endif; ?>
<p><?php echo $meta_box[ 'description' ]; ?></p>
</div>
<?php } ?>
</div>
<?php
}
function save_meta_box( $post_id ) {
global $post, $meta_boxes, $key;
foreach( $meta_boxes as $meta_box ) {
$data[ $meta_box[ 'name' ] ] = $_POST[ $meta_box[ 'name' ] ];
}
if ( !wp_verify_nonce( $_POST[ $key . '_wpnonce' ], plugin_basename(__FILE__) ) )
return $post_id;
if ( !current_user_can( 'edit_post', $post_id ))
return $post_id;
update_post_meta( $post_id, $key, $data );
}
add_action( 'admin_menu', 'create_meta_box' );
add_action( 'save_post', 'save_meta_box' );
?>
In most ways it’s identical to the code that I found, but I added a bit of logic to slightly change the html that the script writes for the different input types. I added one element called ‘type’ to the array that you pass into the function :
$meta_boxes = array(
"callnumber" => array(
"name" => "callnumber",
"title" => "Call Number",
"description" => "enter in the unique library call number for this record",
"type" => "text"
),
"curated" => array(
"name" => "curated",
"title" => "Curated",
"description" => "Is this post curated?",
"type" => "checkbox" //this is the addition and should correspond to standard html form language
)
);
then I added a simple if statement that looks at the value of this ‘type’ value and decides how to print the html and post the data:
<?php if( $meta_box[ 'type' ] == "text"): ?>
<input type="type" name="<?php echo $meta_box[ 'name' ]; ?>" value="<?php echo htmlspecialchars( $data[ $meta_box[ 'name' ] ] ); ?>" />
<?php elseif($meta_box[ 'type' ] == "checkbox") : ?>
<input type="checkbox" name="<?php echo $meta_box[ 'name' ]; ?>" <?php if( $data[ $meta_box[ 'name' ] ] ) echo "checked='checked'"; ?> value="true"/>
<?php endif; ?>
Right now it only recognizes input types of ‘text’ and ‘checkbox’ but following this same logic you could just add other elseif statements and one line of html and make any type of form input work.
It’s a really elegant solution that was already pretty flexible and expandable (it’s not hard to add any number of metaboxes now!), and now it’s just a little bit more versatile.
note: The metadata is stored in a single table entry which makes retrieving a lot of data very simple and fast. However for this same reason, you cannot sort a query from metadata stored with this method. If you need to sort also, take a look at the earlier entry on metaboxes.