Custom Fields and Meta Boxes

Monday, October 13th, 2014

This is an extension of my 2014 High Ed Web presentation: WordPress and Beer

Custom fields

In our example, each of the brewing ingredients is stored a custom post type. There is also a bunch of data that needs to be associated with each ingredient – this is where the custom fields come into play.

Custom fields are built into WordPress – you can start using them without any extra code. Here we see some data for our hops:

Screen Shot 2014-10-13 at 3.39.48 PM

If you do use the fields “as-is” it’s important to know that there is arbitrary limit of 30 shown in the drop down at any time. To correct this, you can use a simple filter:

// show more than 30 custom fields in select list
add_filter( ‘postmeta_form_limit’ , ‘agb_customfield_limit_increase’ );
function agb_customfield_limit_increase( $limit ) {
    return 100;

Meta boxes

If you use custom fields a lot (as I do), you may want to build meta boxes. These make the custom field data feel like an integrated part of the admin page. There are a lot of ways to build meta boxes, but here is what I like to do:

Screen Shot 2014-10-13 at 5.27.58 PM

Set the data

Start by building an array of the data that you want to show/save in the meta box. This data is in the global scope so that you can easily refer to it from the build/save functions:

// set array of custom fields to put into meta ("name" => custom fiels, type=number/text for validation, "title" => a nice name, "value" => keep blank )
$agb_hops_meta = array(
    array( "name" => "agb_hops_alphahigh", "title" => "Alpha (high)", "type" => "number",  "value" => "" ),
    array( "name" => "agb_hops_alphalow", "title" => "Alpha (low)", "type" => "number",  "value" => "" ),
    array( "name" => "agb_hops_betahigh", "title" => "Beta (high)", "type" => "number",  "value" => "" ),
    array( "name" => "agb_hops_betalow", "title" => "Beta (low)", "type" => "number",  "value" => "" ),
    array( "name" => "agb_hops_hsi", "title" => "Storage index", "type" => "number",  "value" => "" ),
    array( "name" => "agb_hops_origin", "title" => "Origin", "type" => "text",  "value" => "" ),
array( "name" => "agb_hops_type", "title" => "Type", "type" => "text",  "value" => "" )

Build the box

We hook our ‘metaboxes’ function to the creation of the admin_menu, then use ‘add_meta_box’ for the specific kind of post type that we have (hops).

[php]/* === Adds Custom META pannels  === */
add_action(‘admin_menu’, ‘agb_metaboxes’);

function agb_metaboxes() {
//add_meta_box( $id, $title, $callback, $post_type, $context, $priority, $callback_args );
add_meta_box( ‘agb-hops-metabox’, ‘Hops Details’, ‘agb_build_metabox’, ‘agb_hops’, ‘normal’,’high’,array("meta_arrays"=>$agb_hops_meta));

function agb_build_metabox($post, $callback_args){
$tab_index = 3000;
$meta_arrays = $callback_args[‘args’][‘meta_arrays’];

foreach($meta_arrays as &$meta){
// Is there a recorded value?
$meta[‘value’] = get_post_meta($post->ID, $meta[‘name’], true);
// Set tab index
$meta[‘tab’] = $tab_index;
// Create inputs
echo'<input type="hidden" name="’.$meta[‘name’].’_noncename" id="’.$meta[‘name’].’_noncename" value="’.wp_create_nonce( plugin_basename(__FILE__) ).’" />’;
echo'<p><label style="width:200px; display:block; float:left; clear:left;" for="’.$meta[‘name’].’">’.$meta[‘title’].’:</label>’;
echo'<input type="’.$meta[‘type’].’" step="any" name="’.$meta[‘name’].’" tabindex="’.$meta[‘tab’].’" value="’.esc_attr($meta[‘value’]).’" /></p>’;

Save the data

We also need to use a hook for saving the data. You could easily create individualized save functions to validate all the data. Here we just do it all at once.

[php]// save all
add_action(‘save_post’, ‘agb_save_metabox’, 1); // do this ASAP!
function agb_save_metabox( $post_id ){
    global $agb_grain_meta,$agb_hops_meta,$agb_yeast_meta,$agb_water_meta;
    // let’s just go through it all
    $uber_array = array($agb_grain_meta,$agb_hops_meta,$agb_yeast_meta,$agb_water_meta);
    foreach($uber_array as &$meta_array){
        // save meta
        foreach($meta_array as &$meta){
            // if data is available
            if( isset($_POST[$meta[‘name’]]) ){
                // Verify
                if ( !isset($_POST[$meta[‘name’].’_noncename’]) || !wp_verify_nonce( $_POST[$meta[‘name’].’_noncename’], plugin_basename(__FILE__) )){
                    return $post_id;
                if ( ‘page’ == $_POST[‘post_type’] ){
                    if ( !current_user_can( ‘edit_page’, $post_id )) return $post_id;
                    if ( !current_user_can( ‘edit_post’, $post_id )) return $post_id;

                // Trim any leading ws and escape
                $data = trim($_POST[$meta[‘name’]]);

                // New? Add it
                if(get_post_meta($post_id, $meta[‘name’]) == "") add_post_meta($post_id, $meta[‘name’], $data, true);
                // Empty? Remove it!
                elseif($data == "" || $data == $pcc_alert_meta_default) delete_post_meta($post_id, $meta[‘name’], get_post_meta($post_id, $meta[‘name’], true));
                // Changed? Update it!
                elseif($data != get_post_meta($post_id, $meta[‘name’], true)) update_post_meta($post_id, $meta[‘name’], $data);


Here is all the code together:

One Response to “Custom Fields and Meta Boxes”

  1. gabriel nagmay (dot com) | Archive » WordPress and Beer: Homebrew web applications with WP Says:

    […] Custom Fields and Meta Boxes […]

Leave a Reply

You know you want to...