Reusable Custom Meta Boxes Part 2: Advanced Fields

Reusable Custom Meta Boxes Part 2: Advanced Fields

Tutorial Details
  • Program: WordPress
  • Difficulty: Moderate
  • Estimated Completion Time: 10-15 Minutes
This entry is part 2 of 4 in the series Reusable Custom Meta Boxes

In Part 1 of our custom meta box template tutorial series, we covered how to set up a custom meta box that loops through an array of fields and outputs each one with the necessary html for various types of form fields. Now we’re ready to start adding a few advanced items to the array and switch case.


Radio Group

Radio buttons are practically never used on their own as they are used to force a user to select one of at least two options, not as an on/off switch like a checkbox. The first thing we’ll need to do is add a radio item to our $custom_meta_fields array.

array (
	'label' => 'Radio Group',
	'desc'	=> 'A description for the field.',
	'id'	=> $prefix.'radio',
	'type'	=> 'radio',
	'options' => array (
		'one' => array (
			'label' => 'Option One',
			'value'	=> 'one'
		),
		'two' => array (
			'label' => 'Option Two',
			'value'	=> 'two'
		),
		'three' => array (
			'label' => 'Option Three',
			'value'	=> 'three'
		)
	)
)

Be sure to add this among the other array items in the original $custom_meta_fields array we started in Part 1.

This array is almost identical to our select box item. It has a main label, a description and unique id. The type is defined and then an array of options is added. It’s important that the option key is the same as the option value because we’re going to check our saved array for the saved value later.

// radio
case 'radio':
	foreach ( $field['options'] as $option ) {
		echo '<input type="radio" name="'.$field['id'].'" id="'.$option['value'].'" value="'.$option['value'].'" ',$meta == $option['value'] ? ' checked="checked"' : '',' />
				<label for="'.$option['value'].'">'.$option['label'].'</label><br />';
	}
break;  

This code will be added after the last “break;” in our meta box switch.

  • Loop through each option in the field’s nested “options” array
  • Use an inline conditional to determine if the saved value matches the value of the current open and output the “checked” attribute if it’s true
  • Use the option’s value as the unique id for the label
  • Add a break at the end so that the next option is on a new line
  • end it with the description field. No need for a preceding “<br />” since we have one left over from looping through the options

Checkbox Group

We’ve covered being able to use a checkbox as an on/off switch and how to be able to select one option from many, but what we want to be able to save more than one value for the same field? That’s where a checkbox group comes in handy.

array (
	'label'	=> 'Checkbox Group',
	'desc'	=> 'A description for the field.',
	'id'	=> $prefix.'checkbox_group',
	'type'	=> 'checkbox_group',
	'options' => array (
		'one' => array (
			'label' => 'Option One',
			'value'	=> 'one'
		),
		'two' => array (
			'label' => 'Option Two',
			'value'	=> 'two'
		),
		'three' => array (
			'label' => 'Option Three',
			'value'	=> 'three'
		)
	)
)

Again, we’re adding this to our $custom_meta_fields array and the set up is nearly identical to similar fields with a unique id, and the type defined.

// checkbox_group
case 'checkbox_group':
	foreach ($field['options'] as $option) {
		echo '<input type="checkbox" value="'.$option['value'].'" name="'.$field['id'].'[]" id="'.$option['value'].'"',$meta && in_array($option['value'], $meta) ? ' checked="checked"' : '',' /> 
				<label for="'.$option['value'].'">'.$option['label'].'</label><br />';
	}
	echo '<span class="description">'.$field['desc'].'</span>';
break;  

The biggest difference here is that we’re saving this data as an array.

  • Loop through each option defined in the array
  • Store the data in an array by adding square brackets to the end of the name: []
  • In our inline conditional for outputting the “checked” attribute, check for the value to be inside an array by using “in_array()”
  • Just like before, add the value for each input, close the loop, and output the description

Taxonomy Select

Being able to have custom taxonomies for various uses is great, but sometimes you want to limit the user to only be able to select one term per post. A simple solution is to remove the default selection box WordPress adds to the Write Post page, and add it as a select box to your custom meta box.

array(
	'label' => 'Category',
	'id'	=> 'category',
	'type'	=> 'tax_select'
)

For this example, I’m just going to use the built in taxonomy, “category”. Add this to your $custom_meta_fields array. Make sure ‘id’ is identical to the name of taxonomy.

// tax_select
case 'tax_select':
	echo '<select name="'.$field['id'].'" id="'.$field['id'].'">
			<option value="">Select One</option>'; // Select One
	$terms = get_terms($field['id'], 'get=all');
	$selected = wp_get_object_terms($post->ID, $field['id']);
	foreach ($terms as $term) {
		if (!empty($selected) && !strcmp($term->slug, $selected[0]->slug)) 
			echo '<option value="'.$term->slug.'" selected="selected">'.$term->name.'</option>'; 
		else
			echo '<option value="'.$term->slug.'">'.$term->name.'</option>'; 
	}
	$taxonomy = get_taxonomy($field['id']);
	echo '</select><br /><span class="description"><a href="'.get_bloginfo('home').'/wp-admin/edit-tags.php?taxonomy='.$field['id'].'">Manage '.$taxonomy->label.'</a></span>';
break;

There is a little bit more information that we need for this field to work completely than the other fields we’ve already set up.

  • Open the select box and add a blank value as “Select One”
  • Get the all of the terms of the set taxonomy
  • Get the terms that have been saved for the current taxonomy
  • Begin looping through each term.
  • To keeps things simple and easy to read, we’re using a full sized conditional an outputting an option that is selected if it matches the saved term, and a regular option for the rest.
  • As you close the loop and the select box, we want to get a bit of information about the taxonomy and store it in a variable.
  • Use the description area as an easy way to link the user to the area where they can manage the taxonomy terms. Use the label from the $taxonomy information we gathered so that the plural is correct (there’s no such thing as categorys).

Remove the Default Taxonomy Box

Since we want to override the default box with our custom select box and not have any conflicts in the UX or in saving the data, it’s necessary to remove the taxonomy’s edit box from the screen.

function remove_taxonomy_boxes() {
	remove_meta_box('categorydiv', 'post', 'side');
}
add_action( 'admin_menu' , 'remove_taxonomy_boxes' );

You could get fancy here and use the $custom_meta_fields array again to loop through each “tax_select” field and add it to this remove function, but it’s probably a lot simpler to name them individually. You’ll need to know the ID if the div for the taxonomy box in order to remove it properly. Read more about remove_meta_box() in the WordPress Codex.

Save the Terms

One final step to this field is to make sure that the taxonomy gets saved as such instead of as a custom field. To do that, we’ll go back and modify the save_custom_meta() function we created in Part 1 of this series.

First, skip it in the field loop. Find this line:

foreach ($custom_meta_fields as $field) {

and after that, add this line:

if($field['type'] == 'tax_select') continue;

Then after your foreach loop, add this:

// save taxonomies
$post = get_post($post_id);
$category = $_POST['category'];
wp_set_object_terms( $post_id, $category, 'category' );

This simply grabs the value from our category select field, then sets it as the taxonomy terms for the post.


Post Select

Another unlikely but useful field is to associate another post with a post by saving the ID in a custom field. This is very CMS-like and I have found it to be useful for things like linking a slide post type to go to another post or page on the site just by selecting it from a dropdown menu. You can use the ID to query the post later on in another function to get any information you need from that post.

array(
	'label' => 'Post List',
	'desc' => 'A description for the field.',
	'id' 	=>  $prefix.'post_id',
	'type' => 'post_list',
	'post_type' => array('post','page')
)

We have all of our usual suspects here, but then at the end we’ve added an additional variable the saves which post types you want to be in the list. You can include, posts, pages, and any other custom post type in this array.

// post_list
case 'post_list':
$items = get_posts( array (
	'post_type'	=> $field['post_type'],
	'posts_per_page' => -1
));
	echo '<select name="'.$field['id'].'" id="'.$field['id'].'">
			<option value="">Select One</option>'; // Select One
		foreach($items as $item) {
			echo '<option value="'.$item->ID.'"',$meta == $item->ID ? ' selected="selected"' : '','>'.$item->post_type.': '.$item->post_title.'</option>';
		} // end foreach
	echo '</select><br /><span class="description">'.$field['desc'].'</span>';
break;  

There are a lot of options you can add to filter this query, but we’re using a basic grab of all posts of the set post types.

  • Query all posts
  • Open the select field and add a blank value
  • Loop through each post and set the ID as the value of the option, and the title labeled with the post type as the displayed text to select from
  • Close the loop and the select field and add the description

Conclusion

If you’ve been following along with both parts of this series so far, your final box should look like the one pictured here:

Custom Meta Box

We are really filling out our reusable template for creating repeatable custom meta box fields with the additional of this advanced and perhaps even unorthodox fields. We’ll wrap up the series in the next post with a few even trickier but useful fields like a datepicker and image uploader.


Other parts in this series:Reusable Custom Meta Boxes Part 1: Intro and Basic FieldsReusable Custom Meta Boxes Part 3: Extra Fields
Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://www.ruturaaj.com Ruturaaj

    This series is really excellent and I’m leaning a lot from all of these posts. I’m eagerly waiting for your next post which will demonstrate me the “image uploader”, something which I tried before but couldn’t achieve the desired result. I hope and in fact would like to request you to please demonstrate how to save the uploaded images in a specific custom folder. Also, another thing that I wish to learn from Master people like you… how to integrate jQuery Color Picker. Can you please include this field too in your next post? That will be really great.

    Once again, thanks so much for this wonderful tutorial series… I’ve just started learning WP stuff and these tutorials are helping me a lot. :-)

  • Vadim

    This is great follow up, thank you for finishing it up! Are you planing on doing step 3 by any chance? Maybe upload fields with thumb preview? That would be bassically what i ever need in a metabox. Personally I tryed doing that before but never got the url to save inside the input field :)

    thanks again!

    • http://www.outerspiceweb.com Brian McCulloh

      “We’ll wrap up the series in the next post with a few even trickier but useful fields like a datepicker and image uploader.”

      Looks like she’s planning on it! Very good and useful tutorial, thanks a lot!

      • Vadim

        Of course I would miss that :p

        That’s great!

  • dj

    Is it intentional that you are not including a link to download code – or do you intend to include on in the final segment? Would be nice to avoid all the cut and pasting and/or retyping and its attendant errors. You would also get more user help in ferreting out any errors which have crept in. Thanks.

  • http://nonsensecreativity.com Jake

    How about checkbox taxonomy? Hope to see it in the next post

  • http://www.offdutygamers.com Mark

    Im creating a custom post type and using a custom meta for it.

    1. How do you force a custom meta to show up by default (rather than the user checking it at the top of the page if they dont see it)?

    2. How do you load that custom meta only on a particular post type?

    3. Bonus round… how do you get the ID of some metas that are from plugins so you can clean up your page so meta’s that arent necessary arent shown?

    Thanks in advance

    • Chris

      You need to put some conditional logic in when building the form elements in ‘show_custom_meta_box()’.

      A quick example would be a radio button, in the foreach loop that builds the radio buttons you have the variable $options['value']. In the begining of a fresh post this value you is empty so all you need to do is say.

      // Set the default value of the radio if empty as in new post
      if (empty($option['value'])
      {
      $option['value'] == ‘yourdefault’
      }

      // Check matching meta and marked checked
      // if the test fails mark ‘yourdefault’ as checked
      if($meta == $option['value'])
      {
      echo ‘ checked=”checked” />’;
      }
      elseif ($option['value'] == “yourdefault”)
      {
      echo ‘checked=”checked” />’;
      }

      • Matt

        where does this get placed in the foreach loop? not sure how to rebuild the foreach loop to include this snippit, as i get syntax errors. i’m a bit of a novice (^_^);

      • Matt

        Just figured it out, or at least for radio buttons. But the code above was checking option[value] of the radion array not the current value of the meta. (When new posts are created this meta is empty or none existent). this below all i did was add a conditional to check and see if the meta is empty. If so make it false.

        foreach ( $field['options'] as $option ) {
        // Set the default value of the radio if meta is ” empty as in new post ”

        if ($meta == ”){$meta = ‘false’; }

        echo ‘

        ‘.$option['label'].”;
        }
        break;

  • Pingback: WordPress Community Roundup for the Week Ending December 17 - Charleston WordPress User Group

  • Jermaine

    Great post, when is the final part coming.

  • http://www.nouveller.com/ Benjamin Reid

    This plugin is pretty good for building custom meta boxes in pseudo style.

    http://wordpress.org/extend/plugins/custom-field-template/

  • Pingback: Reusable Custom Meta Boxes Part 3: Extra Fields | Wptuts+

  • skylos

    Thank you, I have been looking for a tut like ‘Taxonomy Select’ everywhere for ages!

  • http://N/A Caroline

    Tammy,

    Thanks for the great tutorial. Question: What is the best way to print the selected radio field? For example, this is the code I’m using right now (following the guide above) to create different “post format” displays.

    array(
    ‘label’=> ‘Post Format’,
    ‘desc’ => ‘The format the post will be displayed in on the homepage and other archives pages.’,
    ‘id’ => $prefix.’radio’,
    ‘type’ => ‘radio’,
    ‘options’ => array (
    ‘one’ => array (
    ‘label’ => ‘Full’,
    ‘value’ => ‘one’
    ),
    ‘two’ => array (
    ‘label’ => ‘Standard’,
    ‘value’ => ‘two’
    ),
    ‘three’ => array (
    ‘label’ => ‘Gallery’,
    ‘value’ => ‘three’
    )
    )
    )

    And to print:

    ID;
    $options = get_post_meta($post_id,’custom_radio’,true);
    $template_url = get_bloginfo(‘template_url’);

    switch ( $options ) {
    case “one”:
    ?>
    // Put post layout one here

    // Put post layout two here

    // Put post layout three here

    This works, but I don’t think this is the best way…

  • Pingback: Best of Tuts+ in January 2012 | SearchPsd Blog

  • Pingback: Best of Tuts+ in January 2012 | | The online portfolio and blog of freelance graphic and web designer Ben BradshawThe online portfolio and blog of freelance graphic and web designer Ben Bradshaw

  • Pingback: Best of Tuts+ in January 2012 | Shadowtek | Hosting and Design Solutions

  • Pingback: Best of Tuts+ in January 2012 | cssWOW Showcase | Css Gallery | Css Awards | Design Inspiration Tutorials

  • Pingback: My Stream | Best of Tuts+ in January 2012 | My Stream

  • Pingback: Best of Tuts+ in January 2012 | GMancer

  • http://wpforce.com Jonathan Dingman

    When you build the options array, is there a way to do a nested array inside there, so I can have multiple values for a single option?

    example, ‘value1′, ‘value2′, ‘value3′ => ‘Label1′,

    So that way I can use a radio button, and have it reflect multiple different values .. instead of being forced to use 3 different radio buttons just to get each value?

    Thank you!

  • BK

    Thank you for the post. It has been very useful for me. However, I am hung up on how to save a checkbox group and echo the results on the template page.

    What do you mean by this: In our inline conditional for outputting the “checked” attribute, check for the value to be inside an array by using “in_array()” ?

    An explanation might give me some hint on how to troubleshoot.

    Thanks again!

  • Pingback: Reusable Custom Meta Boxes Part 4: Using the Data | How to Web

  • http://www.pinpersia.com milad

    Hi and thanks for great tutorial. could u tell me how can i add an upload media button in replace of wordpress default button ? this is url : http://www.pinpersia.com ..thanks again

  • Pascal

    Great tutorial Tammy. Using the scenario above with the Taxonomy and Post_List I would like to be able once selecting a category that my Post_List only shows the post in that Category. How would I do that?

    Thanks,

  • Joseph

    Hi Tammy,
    I am just wandering how you would handle a post list which allows you to select multiple fields.

    I have changed the code so that the generated postlist select box allows multiple selections
    however when i save it, only the first selection that i made gets saved. not any of the other selections.

    Any ideas on how to fix this would greatly be appreciated.
    Thankyou on a good tutorial.

  • Pingback: WordPress Plugin Development Resources : WPMayor

  • http://www.pachakamaq.com Fliberty

    Hi, I need to use groups of checkboxes for the tutorial http://wp.tutsplus.com/tutorials/creative-coding/posting-via-the-front-end-advanced-submission/
    How it could be implemented in the form and to print in single.php, thank you very much.

  • Pingback: Best Custom Meta Box Tutorials & Resources : WPMayor

  • Scorch

    Is there any way I can enable multiple select values from the post list, this seems so close I just cannot make it store the values either as a Checkbox group or a multiple select list.

    Many thanks