This post was published 9 years ago
There's a chance things are out of date or no longer reflect my views today
Wordpress custom fields
I have only recently looked into using the custom meta boxes that come with Wordpress. I’ve been a fan of Advanced Custom Fields for a long time, so it’s something I’ve never had a great urge to use.I’m going share with you over the course of this post how to get them set up. You’ll learn to add them efficiently, how to add custom CSS, change placement to under the title and finally how to use them in your theme.
I have only recently looked into using the custom meta boxes that come with Wordpress. I’ve been a fan of Advanced Custom Fields for a long time, so it’s something I’ve never had a great urge to use.
I’m going share with you over the course of this post how to get them set up. You’ll learn to add them efficiently, how to add custom CSS, change placement to under the title and finally how to use them in your theme.
Introducing the code we’ll be using
All meta boxes are built with add_meta_box
, which takes 6 parameters. The approach we will be using will build upon this to add them in a more efficient and customisable manner.
add_meta_box( $id, $title, $callback, $screen, $context, $priority, $callback_args );
I have used much of the code, what’s set by the references of the Wordpress Theme Boilerplate and Wordpress Codex.
The code
Find and replace ‘iamsteve’ with your own prefix.
// Start with an underscore to hide fields from custom fields list
$prefix = '_iamsteve_meta_';
$meta_boxes = array(
array(
'id' => 'meta-testimonial',
'title' => 'Role',
'pages' => array('jetpack-testimonial'), // multiple post types
'context' => 'advanced', // 'normal', 'advanced', or 'side'
'priority' => 'high', // 'high', 'core', 'default' or 'low'
'fields' => array(
array(
'name' => 'Role',
'desc' => 'This can be a company name or role they fulfilled.',
'id' => $prefix . 'role',
'type' => 'text',
'std' => '',
'placeholder' => 'Photographer'
))
)
);
foreach ($meta_boxes as $meta_box)
{
$box = new Iamsteve_Meta_Box($meta_box);
}
class Iamsteve_Meta_Box
{
protected $_meta_box;
// Create meta box based on given data
function __construct( $meta_box ) {
$this->_meta_box = $meta_box;
add_action( 'admin_menu', array(&$this, 'add') );
add_action( 'save_post', array(&$this, 'save') );
// Add our styles to the places they’re required
add_action( 'admin_print_styles-post-new.php', array(&$this, 'style'), 11 );
add_action( 'admin_print_styles-post.php', array(&$this, 'style'), 11 );
}
function style()
{
wp_enqueue_style('iamsteve-meta-box-style', get_template_directory_uri() . 'css/meta-box.css');
}
/// Add meta box for multiple post types
function add()
{
foreach ( $this->_meta_box['pages'] as $page )
{
add_meta_box($this->_meta_box['id'], $this->_meta_box['title'], array(&$this, 'show'), $page, $this->_meta_box['context'], $this->_meta_box['priority']);
}
}
// Callback function to show fields in meta box
function show()
{
global $post;
// Use nonce for verification
echo '<input type="hidden" name="iamsteve_meta_box_nonce" value="', wp_create_nonce(basename(__FILE__)), '">';
// Wordpress uses a table based setup for form fields, so following that pattern we will stick to it
echo '<table class="form-table">';
foreach ($this->_meta_box['fields'] as $field) {
// Get current post meta data
$meta = get_post_meta($post->ID, $field['id'], true);
echo '<tr>';
echo '<th class="screen-reader-text"><label for="' . $field['id'] . '">' . $field['name'] . '</label></th>';
echo '<td>';
switch ($field['type'])
{
case 'text' :
echo '<input type="text" name="' . $field['id'] . '" id="' . $field['id'] . '" value="' . ( $meta ? $meta : $field['std'] ) . '" size="30">';
echo '<p><small>' . $field['desc'] . '</small></p>';
break;
case 'textarea':
echo '<textarea name="' . $field['id'] . '" id="' . $field['id'] . '">' . ( $meta ? $meta : $field['std'] ) . '</textarea>';
echo '<p class="meta-box-description"><small>' . $field['desc'] . '</small></p>';
break;
case 'select':
echo '<select name="' . $field['id'] . '" id="' . $field['id'] . '">';
foreach ($field['options'] as $option)
{
echo '<option value="' . $option['value'] . '"' . ( $meta == $option['value'] ? ' selected="selected"' : '' ) . '>' . $option['name'] . '</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>';
echo '</tr>';
}
echo '</table>';
}
// Save data from meta box
function save($post_id)
{
// Verify nonce
if ( !isset($_POST['iamsteve_meta_box_nonce']) || !wp_verify_nonce($_POST['iamsteve_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;
}
}
else if ( !current_user_can('edit_post', $post_id) )
{
return $post_id;
}
foreach ( $this->_meta_box['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);
}
}
}
}
Explanation
Here is an overview of what all the code is doing. Generally if you find yourself getting stuck with the code this should help you.
$prefix = ‘iamsteve’
You use a prefix with an underscore at the start as this ensures our fields can’t be used anywhere or conflict potentially. You may have seen this in some themes, where you can select custom fields. It can be really confusing for a user if there is no output from it.
$meta_boxes array
The array has a nested array for each meta box you create, which contains the parameters which match up with add_meta_box()
.
The important part is the ‘fields’ array. Which relies on the function within the class
called show
. This has a case
statement which checks for which field type is passed. You can adjust this here should you need more field types.
The class
Inside the construct you have the code to make sure the fields are setup properly.
Part of the setup uses admin_menu
hook, to make sure our fields are added through the add
function. This function does the bulk of the work for displaying the fields. Calling the show
function, based on the field we defined in our $meta_boxes
array.
Another part uses the save_post
action, which calls save function. This checks for correct nonce, permissions and whether it’s a new field or we’re updating an existing field.
The final hooks add your custom CSS, found inside the ‘style’ function. You can replace wp_enqueue_style
and echo
some CSS between <style>
tags, if you only require minimal CSS.
Moving the meta box under the title
Utilising the ‘advanced’ context, the following code will place them the title. I think this is a good way to utilise the advanced context. You can add this with the rest of your meta box code.
add_action('edit_form_after_title', 'advanced_meta_boxes_under_title');
function advanced_meta_boxes_under_title()
{
global $post, $wp_meta_boxes;
do_meta_boxes(get_current_screen(), 'advanced', $post);
unset($wp_meta_boxes[get_post_type($post)]['advanced']);
}
Credit: Andrew, Wordpress Stack Exchange
Using the fields in your theme
To use the custom fields within your theme, you use the get_post_meta
function, within your loop.
get_post_meta takes 3 parameters
- The post ID, inside the loop this is easy to get with
get_the_ID()
- The field key, in our case this would be the field ID in the array
_iamsteve_meta_role
- The single parameter, which if set to true will return a single result. Otherwise it will return an array.
$role = get_post_meta( get_the_ID(), '_iamsteve_meta_role', true );
if (have_posts()) :
while (have_posts()) : the_post();
if ( ! empty($role) ) echo $role;
endwhile;
endif;
That’s custom fields
That’s it, there is quite a bit to custom fields. I would like to explore in future posts more detailed uses of setting up the boxes with more complex fields.