User-friendly custom fields with Meta Boxes in WordPress
Ryan Taylor explains how to add metadata to a WordPress post by creating and adding Meta Boxes and improving the usability of custom fields.
- Knowledge needed: PHP, experience with WordPress
- Requires: WordPress
- Project Time: 30 minutes
In a previous tutorial I talked about Post Formats, a new feature introduced in WordPress 3.1. A Post Format is a piece of meta information that can be assigned to individual posts and used by a theme to customise the presentation of those posts. I also discussed the current limitations of Post Formats in WordPress when compared to services like Tumblr. With Tumblr, whichever Post Format you select determines the form fields youre presented with. In Wordpress, by default, you only have the title and post editor fields.
We can of course add additional metadata to a post by using Custom Fields:
The problem with Custom Fields is they’re not very user-friendly. If you’re designing for a client you need to explain what they are, what needs to be entered and also hope they don’t forget to do it.
This is where Meta Boxes come in handy!
01. What are Meta Boxes?
A Meta Box is a custom section that can be added to a post/page screen. It can be used to group Custom Fields together and give them context. Here’s a Meta Box that I use in conjunction with Post Formats for my blog (ryanhavoctaylor.com):
You can have as many form fields as you need in a Meta Box as well as use other input types such as checkboxes and radio buttons. Under the hud, they’re still Custom Fields and you call the values in your theme the exact same way:
get_post_meta($post_id, $key, $single);
We’re just making the admin UI more usable with labels, instructions and better formatting.
Get the Creative Bloq Newsletter
Daily design news, reviews, how-tos and more, as picked by the editors.
02. Create a Meta Box
When I build WordPress themes I use Meta Boxes with my posts all the time and often I have Custom Post Types (codex.wordpress.org/Post_Types) registered that I also want to have Meta Boxes applied to.
The code I’m now going to talk you through will enable you to quickly add Meta Boxes to any and all of your themes Post Types.
We start off by adding the following code to our functions.php template file (if this file doesn’t exist in your theme then create it):
//We create an array called $meta_box and set the array key to the relevant post type
$meta_box['post'] = array(
//This is the id applied to the meta box
'id' => 'post-format-meta',
//This is the title that appears on the meta box container
'title' => 'Additional Post Format Meta',
//This defines the part of the page where the edit screen section should be shown
'context' => 'normal',
//This sets the priority within the context where the boxes should show
'priority' => 'high',
//Here we define all the fields we want in the meta box
'fields' => array(
array(
'name' => 'Link - URL',
'desc' => 'URL for the link',
'id' => 'pf_link_url',
'type' => 'text',
'default' => ''
),
array(
'name' => 'Quote - Source',
'desc' => '(Optional) URL to the quote source',
'id' => 'pf_quote_source',
'type' => 'text',
'default' => ''
)
)
);
This is simply an array declaration that we will pass to a series of functions to create our Meta Box. We’re going to look at those functions next, but once they’re written, all you’ll need to do is add array entries like the one above to your function.php file to quickly add Meta Boxes to your themes.
The above entry will add the Additional Post Format Meta box that I use on my blog to the post screen.
If you’re using Custom Post Types you can add a Meta Box to them as well by adding another array entry. Here’s an example for a Post Type called Books:
$meta_box['books'] = array(
'id' => 'book-meta-details',
'title' => 'Book Meta Details',
'context' => 'normal',
'priority' => 'high',
'fields' => array(
array(
'name' => 'Summary',
'desc' => '(Max 45 words) Note: Leave all other fields blank if the book is not on sale yet.',
'id' => 'book_summary',
'type' => 'textarea',
'default' => ''
),
array(
'name' => 'Buy Now URL:',
'desc' => '',
'id' => 'book_ buy_now_link',
'type' => 'text',
'default' => ''
),
array(
'name' => 'Price:',
'desc' => 'e.g. £9.95',
'id' => 'book_price',
'type' => 'text',
'default' => ''
),
array(
'name' => 'Book is on sale?',
'desc' => '',
'id' => 'book_on_sale',
'type' => 'checkbox',
'default' => ''
),
array(
'name' => 'Sample PDF Url',
'desc' => '(Optional) Link to a sample PDF.',
'id' => 'book_sample_url',
'type' => 'text',
'default' => ''
)
)
);
Notice that we change the array key to reflect the post type that the entry applies to. Once you’ve created all the array entries that you want you need to add the following line of code to run the functions that will actually create the Meta Box(es).
add_action('admin_menu', 'plib_add_box');
Note that this line only needs to be run once.
03. Keeping everything tidy
This is an optional step, but to keep everything tidy I’ve created a file called preset-library.php, which I add to my themes and include at the top of function.php like so:
include('preset-library.php');
I find separating functions that never change from the code that calls them easier to work with than having everything clumped together.
If you want to do this too, add the following functions to preset-library.php, otherwise add them to the top of functions.php.
04. Adding the Meta Box
The first function is a relatively simple one.
//Add meta boxes to post types
function plib_add_box() {
global $meta_box;
foreach($meta_box as $post_type => $value) {
add_meta_box($value['id'], $value['title'], 'plib_format_box', $post_type, $value['context'], $value['priority']);
}
}
We loop through the $meta_box array we defined earlier and pass each entry into the WordPress function add_meta_box (codex.wordpress.org/Function_Reference/add_meta_box). You’ll see that one of the parameters for this function is a callback to another function called plib_format_box. We’ll cover this one next.
05. Formatting the Meta Box
This function applies the HTML formatting within the Meta Box for each input field.
//Format meta boxes
function plib_format_box() {
global $meta_box, $post;
// Use nonce for verification
echo '<input type="hidden" name="plib_meta_box_nonce" value="', wp_create_nonce(basename(__FILE__)), '" />';
echo '<table class="form-table">';
foreach ($meta_box[$post->post_type]['fields'] as $field) {
// get current post meta data
$meta = get_post_meta($post->ID, $field['id'], true);
echo '<tr>'.
'<th style="width:20%"><label for="'. $field['id'] .'">'. $field['name']. '</label></th>'.
'<td>';
switch ($field['type']) {
case 'text':
echo '<input type="text" name="'. $field['id']. '" id="'. $field['id'] .'" value="'. ($meta ? $meta : $field['default']) . '" size="30" style="width:97%" />'. '<br />'. $field['desc'];
break;
case 'textarea':
echo '<textarea name="'. $field['id']. '" id="'. $field['id']. '" cols="60" rows="4" style="width:97%">'. ($meta ? $meta : $field['default']) . '</textarea>'. '<br />'. $field['desc'];
break;
case 'select':
echo '<select name="'. $field['id'] . '" id="'. $field['id'] . '">';
foreach ($field['options'] as $option) {
echo '<option '. ( $meta == $option ? ' selected="selected"' : '' ) . '>'. $option . '</option>';
}
echo '</select>';
break;
case 'radio':
foreach ($field['options'] as $option) {
echo '<input type="radio" name="' . $field['id'] . '" value="' . $option['value'] . '"' . ( $meta == $option['value'] ? ' checked="checked"' : '' ) . ' />' . $option['name'];
}
break;
case 'checkbox':
echo '<input type="checkbox" name="' . $field['id'] . '" id="' . $field['id'] . '"' . ( $meta ? ' checked="checked"' : '' ) . ' />';
break;
}
echo '<td>'.'</tr>';
}
echo '</table>';
}
The function loops through the fields section of each entry of the $meta_box array and prints out the supplied values.
06. Saving data from the Meta Box
Finally we need to tell WordPress that the fields exist and how to save them with the Post.
// Save data from meta box
function plib_save_data($post_id) {
global $meta_box, $post;
//Verify nonce
if (!wp_verify_nonce($_POST['plib_meta_box_nonce'], basename(__FILE__))) {
return $post_id;
}
//Check autosave
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return $post_id;
}
//Check permissions
if ('page' == $_POST['post_type']) {
if (!current_user_can('edit_page', $post_id)) {
return $post_id;
}
} elseif (!current_user_can('edit_post', $post_id)) {
return $post_id;
}
foreach ($meta_box[$post->post_type]['fields'] as $field) {
$old = get_post_meta($post_id, $field['id'], true);
$new = $_POST[$field['id']];
if ($new && $new != $old) {
update_post_meta($post_id, $field['id'], $new);
} elseif ('' == $new && $old) {
delete_post_meta($post_id, $field['id'], $old);
}
}
}
add_action('save_post', 'plib_save_data');
07. Conclusion
And that’s it! If your themes need more information than the basic title and post editor fields then Meta Boxes are a great way to improve the usability of Custom Fields for the user, whether they’re technical or not.
Ryan Taylor ryanhavoctaylor.com/ is a freelance designer and front-end developer. He runs his own business at Havoc Inspired (havocinspired), blogs at ryanhavoctaylor.com and tweets under @ryanhavoc (twitter.com/ryanhavoc). He’s obsessed with clean, efficient and semantic HTML, CSS and jQuery (his favourite framework).
Thank you for reading 5 articles this month* Join now for unlimited access
Enjoy your first month for just £1 / $1 / €1
*Read 5 free articles per month without a subscription
Join now for unlimited access
Try first month for just £1 / $1 / €1
The Creative Bloq team is made up of a group of design fans, and has changed and evolved since Creative Bloq began back in 2012. The current website team consists of eight full-time members of staff: Editor Georgia Coggan, Deputy Editor Rosie Hilder, Ecommerce Editor Beren Neale, Senior News Editor Daniel Piper, Editor, Digital Art and 3D Ian Dean, Tech Reviews Editor Erlingur Einarsson and Ecommerce Writer Beth Nicholls and Staff Writer Natalie Fear, as well as a roster of freelancers from around the world. The 3D World and ImagineFX magazine teams also pitch in, ensuring that content from 3D World and ImagineFX is represented on Creative Bloq.