Reusable Custom Meta Boxes Part 1: Intro and Basic Fields

Reusable Custom Meta Boxes Part 1: Intro and Basic Fields

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

There are a lot of tutorials on creating custom meta boxes, even just here on Wptuts, and it goes to show that having a good knowledge of these and a system for creating them is crucial to a successful WordPress theme or plugin project. In this series we won’t rehash what meta boxes are but instead we’ll create an easy system for plugging them into whatever your latest project is to keep your work moving consistently.


Create a Meta Box

As usual, the first step is to set up our code for creating a meta box. We’re just creating a library that we can come back to, so we’ll use a really generic name for everything. Some settings can also change whether you’re coming from a theme or a plugin, but the simplest way is to build it into a theme, so that’s what we’ll cover here. All of our code will either be placed into functions.php, or in a file that you include from functions.php in your theme.

// Add the Meta Box
function add_custom_meta_box() {
    add_meta_box(
		'custom_meta_box', // $id
		'Custom Meta Box', // $title 
		'show_custom_meta_box', // $callback
		'post', // $page
		'normal', // $context
		'high'); // $priority
}
add_action('add_meta_boxes', 'add_custom_meta_box');
  

This will add a meta box to the Write/Edit Post screen.

  • The $id will be added to the box as an id to make it easy to reference in style sheets and other functions
  • The $title will be displayed in the handle of the box
  • The $callback is the function we’ll use to define the output inside the box
  • $page is used to select which post type the box will be used on
  • We use $context to determine where the box will show up on the page
  • Having $priority set at “high” will put the box as close to the editor as we can and factors in other boxes added by core and plugins.

Create the Field Array

Since we’re building something that we can use over and over again, we won’t be defining the html for every field. Instead, we’ll create an array that holds all of the unique information for each field including a “type”. Then we’ll loop through each field and change the html output according to the type.

// Field Array
$prefix = 'custom_';
$custom_meta_fields = array(
	array(
		'label'=> 'Text Input',
		'desc'	=> 'A description for the field.',
		'id'	=> $prefix.'text',
		'type'	=> 'text'
	),
	array(
		'label'=> 'Textarea',
		'desc'	=> 'A description for the field.',
		'id'	=> $prefix.'textarea',
		'type'	=> 'textarea'
	),
	array(
		'label'=> 'Checkbox Input',
		'desc'	=> 'A description for the field.',
		'id'	=> $prefix.'checkbox',
		'type'	=> 'checkbox'
	),
	array(
		'label'=> 'Select Box',
		'desc'	=> 'A description for the field.',
		'id'	=> $prefix.'select',
		'type'	=> 'select',
		'options' => array (
			'one' => array (
				'label' => 'Option One',
				'value'	=> 'one'
			),
			'two' => array (
				'label' => 'Option Two',
				'value'	=> 'two'
			),
			'three' => array (
				'label' => 'Option Three',
				'value'	=> 'three'
			)
		)
	)
);

It’s important that your meta fields have a unique key so a $prefix is defined to make it simple to attach the same one to each field id. Then we begin an array of arrays where each item defines a new field with a label, description, unique id, and the type of field it is. The select box has additional data to add all of the options for the select box. Using this template, you can add as many of each type of field you want. The order in which you add them to the array is the order in which they will output in the meta box.


Outputting the Fields

Now we are ready to set up our callback function and being outputting the html for each field.

// The Callback
function show_custom_meta_box() {
global $custom_meta_fields, $post;
// Use nonce for verification
echo '<input type="hidden" name="custom_meta_box_nonce" value="'.wp_create_nonce(basename(__FILE__)).'" />';
	
	// Begin the field table and loop
	echo '<table class="form-table">';
	foreach ($custom_meta_fields as $field) {
		// get value of this field if it exists for this post
		$meta = get_post_meta($post->ID, $field['id'], true);
		// begin a table row with
		echo '<tr>
				<th><label for="'.$field['id'].'">'.$field['label'].'</label></th>
				<td>';
				switch($field['type']) {
					// case items will go here
				} //end switch
		echo '</td></tr>';
	} // end foreach
	echo '</table>'; // end table
}
  

This code sets up the callback with a table for the fields and loops through each field in a table row.

  • Echo a hidden nonce field to verify the fields when we save them later
  • Start a table and begin a loop through each field from the $custom_meta_fields array.
  • Get the value of the field if it has been saved for the current post already so that we can output it in the field
  • Begin a table row with two cells: a <th> for the label of the field, and a <td> for the field itself.
  • Then we’ll insert our switch case items.
  • Finally, end the table row, the loop, and the table before closing the function

Case: Text Input

The basic idea here is to test what the field type is and change the output accordingly.

// text
case 'text':
	echo '<input type="text" name="'.$field['id'].'" id="'.$field['id'].'" value="'.$meta.'" size="30" />
		<br /><span class="description">'.$field['desc'].'</span>';
break;

The idea here is pretty simple.

  • If the field type is “text”, echo the html code using that field’s array settings
  • The field id is used for the name which will create the meta field’s unique key, and it’s used for the field id which we want so that we can link our label to the field and also call it in our style sheet later if we want
  • The value will output the $meta variable which is empty if this field hasn’t been saved for this post yet.
  • After the field, we’ll output the description for further explanation of what is expected

Case: Textarea

// textarea
case 'textarea':
	echo '<textarea name="'.$field['id'].'" id="'.$field['id'].'" cols="60" rows="4">'.$meta.'</textarea>
		<br /><span class="description">'.$field['desc'].'</span>';
break;

This follows the same principles as with the text field, except follows the standard of textarea html. The $meta is put between the opening and closing tags so that it outputs any saved text.

Case: Checkbox

// checkbox
case 'checkbox':
	echo '<input type="checkbox" name="'.$field['id'].'" id="'.$field['id'].'" ',$meta ? ' checked="checked"' : '','/>
		<label for="'.$field['id'].'">'.$field['desc'].'</label>';
break;

A check box can be a little tricky because the value of $meta is used to determine whether or not the box should be checked. In our code we use an inline conditional that outputs the “checked” attribute if the $meta value exists, and nothing if it doesn’t. The other difference here is that we use the field’s description in another label so that there’s a large clickable area for the user.

Case: Select Box

// select
case 'select':
	echo '<select name="'.$field['id'].'" id="'.$field['id'].'">';
	foreach ($field['options'] as $option) {
		echo '<option', $meta == $option['value'] ? ' selected="selected"' : '', ' value="'.$option['value'].'">'.$option['label'].'</option>';
	}
	echo '</select><br /><span class="description">'.$field['desc'].'</span>';
break;

The select box is tackled in a completely new way.

  • Open the select field
  • Loop through each of the options that we defined in our array
  • Use an inline conditional to determine if the current option is the one saved for the post and output the “selected” attribute if it is
  • Close the select field and add the description

Save the Data

We’ve set up our basic box with a nice array template for using and reusing multiple types of fields. Now we need to loop through them again, verify them, and save them to the post.

// Save the Data
function save_custom_meta($post_id) {
    global $custom_meta_fields;
	
	// verify nonce
	if (!wp_verify_nonce($_POST['custom_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;
	}
	
	// loop through fields and save the data
	foreach ($custom_meta_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);
		}
	} // end foreach
}
add_action('save_post', 'save_custom_meta');  

First we’ll go through a few security checks to see if the fields should be saved; nonce, autosave, and user capabilities are all checked. Then we loop through each field again.

  • Get the field’s value if it has been saved before and store it as $old
  • Get the current value that has been entered and store it as $new
  • If there is a $new value and it isn’t the same as old, update the post meta field with the $new value
  • If the $new value is empty and there is an $old value, delete the post meta field $old value
  • If there are no changes, nothing happens

Conclusion

Your final box should look like the one pictured here:

Custom Meta Box

We have started ourselves a nice little library and template for creating a custom meta box with multiple arrays. Now you can easily drop this into any theme or plugin and use the array to add as many text fields, textareas, single checkboxes, and select boxes as you need. In the continuing parts of this series, we’ll begin working with more advanced fields and even a couple fun ones that involve jQuery UI. You won’t want to miss them!


Other parts in this series:Reusable Custom Meta Boxes Part 2: Advanced Fields
Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://www.jaredatchison.com Jared

    This is a good basic explanation.

    There are also several scripts that build upon this exact method and let you build out custom metaboxes in no time. Several of them are on .org in plugin form, however if you are looking for a script to use for your theme I’d check out:

    Custom Metaboxes and Fields on GitHub (http://github.com/jaredatch/Custom-Metaboxes-and-Fields-for-WordPress)
    WPAlchemy Metaboxes (http://www.farinspace.com/wpalchemy-metabox/)

    • http://wp.envato.com/ Japh

      Thanks for the link to your GitHub repository, Jared! Super useful :)

    • Anghel Gabriel

      First i would like to thanks the author for this great tutorial.
      Second Thanks Jared for the github link.

    • http://www.sagive.co.il Sagive

      i love alchemy but cant find an explenation as to how to change the alchemy folder location.. since its located in wp-content its useless for themes you place to give away or sell..

  • Lucas C

    I loved the article, it was a great read.

    One thing I would suggest though, what about creating an ‘input’ function, that accepts parameters that determine what it outputs? E.G, name, value, etc, then the type just goes into the type parameter? It works well for me, and would make it even more extensible.

  • http://davidbecerra.com David B.

    Thank you Tammy! This is a lot more flexible than my template :)

    …FIRST (for good measure)

  • http://www.KelvinAlf.com KelvinAlf

    I just used a plugin for this after having a hard time making one without any full tutorials (most stopped without the call action). I will definitely love this. Thank you!

  • Vadim

    Very good. Clean and clear, thanks for sharing!

  • http://www.converttowordpress.net/ jzigbe

    Very nice tut. Thanks.

  • Pedro

    Great post.

    Do you know how to add the rich/html editor used for content post in that textarea???

    Thanks

    • JPry

      Once the 3.3 version of WordPress is out, you will be able to use the new wp_editor() function. Be sure to note, the new editor can be used in a custom meta box, but you should not try to move the meta box around.

  • Federico Schafer

    Great tutorial. I think it´s in the right direction to what us developers are really interested to read and learn. I´ll be waiting for the continuing tuts on this!.
    Thanks.

  • Pingback: Custom Meta Box Tutorial - Jean Galea | Web Designer and Developer in Malta | WordPress Consultant

  • http://www.jlapitan.com jlapitan

    how can i have dynamic options for the dropdown menu? lets say, the values will be coming from a custom post type

    • Sam

      This can involve two steps. First is create a function that queries data from your custom post type. This can be done in many ways, like using get_posts or $wpdb (for complex queries), whichever you choose.

      function get_my_songs()
      {
      $args = array(
      ‘numberposts’ = -1,
      ‘post_type’ = ‘song’,
      ‘orderby’ = ‘post_title’,
      ‘order’ = ‘ASC’
      );

      $my_songs = get_posts( $args );

      return $my_songs;
      }

      Then create a custom Case in function show_custom_meta_box (in the above tutorial) that iterates the result set of your function to display the desired data. It’s a good thing to have their post IDs be their option value.

      case ‘songs_select_box’:
      $my_songs = get_my_songs();

      echo ”;
      foreach ($my_songs as $my_song) {
      echo ‘ID ? ‘ selected=”selected”‘ : ”, ‘ value=”‘.$my_song->ID.’”>’.$my_song->post_title.”;
      }
      echo ”.$field['desc'].”;
      break;

      • Sam

        for code readability:

        function get_my_songs()
        {
        $args = array(
        ‘numberposts’ = -1,
        ‘post_type’ = ‘song’,
        ‘orderby’ = ‘post_title’,
        ‘order’ = ‘ASC’
        );

        $my_songs = get_posts( $args );

        return $my_songs;
        }

        case ‘songs_select_box’:
        $my_songs = get_my_songs();

        echo ‘<select name=”‘.$field['id'].’” id=”‘.$field['id'].’”>’;
        foreach ($my_songs as $my_song) {
        echo ‘<option’, $meta == $my_song->ID ? ‘ selected=”selected”‘ : ”, ‘ value=”‘.$my_song->ID.’”>’.$my_song->post_title.’</option>’;
        }
        echo ‘</select><br /><span class=”description”>’.$field['desc'].’</span>’;
        break;

    • http://www.tammyhartdesigns.com Tammy Hart

      I cover this in part 2 of the series which will be out sometime this week.

  • http://www.jaredatchison.com Jared

    It’s worth noting that this doesn’t cover sanitizing the data, which is very important.

    http://codex.wordpress.org/Data_Validation

    • http://wp.envato.com/ Japh

      Great point, Jared. Perhaps Tammy will cover that in future parts of the series.

  • Sam

    In some cases wherein you want to update the value of your postmeta (particularly using a checkbox) from checked to unchecked, you might find that it doesn’t get unchecked after updating the post. Reason for this is that the checkbox will only be included in $_POST (used by function save_custom_meta in the above tutorial) only when it is checked.

    A remedy to this problem is to use a hidden field alongside Case: Checkbox with the same name as your checkbox.

    • http://www.ryanmaurodesign.com Ryan Mauro

      Thanks for the fix! That worked for me.

    • ryanmaurodesign


      case 'checkbox':
      echo '';
      break;

    • ryanmaurodesign

      case ‘checkbox’: echo ”; break;

  • Rened

    To output the content it will be like this? or there is a better mode?

    ID, ‘custom_text’ , true);?>

  • Rened

    To output the content it will be like this? or there is a better mode?

    ID, ‘custom_text’ , true);?>

  • Rened

    To output the content it will be like this? or there is a better mode?

    <?php echo get_post_meta($post->ID, ‘custom_text’ , true);?>

    • http://www.tammyhartdesigns.com Tammy Hart
      Author

      Yes, that’s one way you can output the data. You can also use get_post_custom() [http://codex.wordpress.org/Function_Reference/get_post_custom] which puts all of the data in an array. I’ll be writing up a tutorial that shows how to create a nice little function for your custom fields. If you want to skip ahead, you can dig into my ReciPress plugin in the file “php/functions.php”: http://wordpress.org/extend/plugins/recipress/

      • Brent

        Hey,

        Was wondering if someone could give me a hand…

        I’m trying to get my meta box info outputted on the front end of my template but nothing I do seems to be working…

        When I place in this code into my template:

        ID, ‘fieldid’, true);?>

        It doesn’t show anything at all.

        However, when I place in this code:

        ID, ‘fieldid’, true);?>

        …It just displays the word ‘Array’ where the info that was inputted into the meta box should be.

        Am I supposed to place any more lines of code into my template file to get my meta box inputted info to display?

        I’m a massive newbie to all this so any help or advice would be much appreciated. Thanks!

  • Jermaine

    Question say I have a section on my site for multiple image, would I have to repeat me self in the code or it there to add repeating data.

    • http://www.tammyhartdesigns.com Tammy Hart
      Author

      Part 3 will cover repeatable fields. They are a bit tricky, but nice to have once they are in place.

  • Pingback: Reusable Custom Meta Boxes Part 2: Advanced Fields | Wptuts+

  • Pingback: My Stream » Reusable Custom Meta Boxes Part 2: Advanced Fields

  • Pingback: Reusable Custom Meta Boxes Part 2: Advanced Fields | Graphfucker

  • Pingback: wp-coder.net » WordPress News, Tutorials & Resources Roundup No.10

  • Steve

    Am I right in thinking that if you use multiples of the same type of field, ie. two text fields, that the same ID will be generated for each? In which case, that could cause problems. Is there a way round this?

    • http://www.tammyhartdesigns.com Tammy Hart
      Author

      Steve,

      When you duplicate a field in the array, you should change everything but the type. The name, description, id, etc. should be unique for each field. The Type tells the switch which html to use when outputting the field.

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

  • Pingback: My Stream » Reusable Custom Meta Boxes Part 3: Extra Fields

  • Tomica

    When I copy the first chunk of code and paste it in my functions.php, the Meta Box is created, but inside it I get this error:

    Warning: call_user_func(show_custom_meta_box) [function.call-user-func]: First argument is expected to be a valid callback in /xxx/yyy/zzz//wp-admin/includes/template.php on line 958.

    Any assistance on that, please?

    Also, would there be anything different if I decide to put this code in a plugin instead of functions.php? When I do that, I get the same error message as in the first case.

    • Tomica

      Disregard my question. Feeling silly now :) Never do coding after a busy night!

      I’ll answer myself, for those who get the same thing. You should first have your entire code inside your functions.php. Only partial code will of course not work.

  • Pingback: How To Be A ProWordPress News, Tutorials & Resources Roundup No.10 - How To Be A Pro - Plugins, Web Design, Web Development, Wordpress, Wordpress Plugins, Wordpress Templates, Wordpress Themes

  • Pingback: Reusable Custom Meta Boxes Part 1: Intro and Basic Fields | Wptuts+ | Wondercore

  • http://dellostritto.cl Drew

    What a wonderful post, I loved the looping form function – I’ve found it to be useful outside of wordpress for creating long forms (the only downside is that you loose some flexibility to insert text between form elements).

    Would it be possible to allow for a file upload?

    I’ve tried:

    // file
    case ‘file’:
    echo ‘<input type=”file” name=”‘.$field['id'].’” id=”‘.$field['id'].’” size=”30″ />
    <br /><span class=”description”>’.$field['desc'].’</span>
    <br />Currently set to: ‘.$meta.”;
    break;

    But the form takes it as a value, it doesn’t actually upload it. I’m not really sure how that would be done, but think it would be great if could be incorporated into this function. This way the user wouldn’t have to go get the image url, copy and paste it into the field.

    From another function that I use for creating an options page (not the correct settings API), I use another snippet:

    // Validate
    function validate_setting($plugin_options) {
    $keys = array_keys($_FILES);
    $i = 0;
    foreach ( $_FILES as $image ) {
    // if a files was upload
    if ($image['size']) {
    // if it is an image
    if ( preg_match(‘/(jpg|jpeg|png|gif)$/’, $image['type']) ) {
    $override = array(‘test_form’ => false);
    // save the file, and store an array, containing its location in $file
    $file = wp_handle_upload( $image, $override );
    $plugin_options[$keys[$i]] = $file['url'];
    } else {
    // Not an image.
    $options = get_option(‘plugin_options’);
    $plugin_options[$keys[$i]] = $options[$logo];
    // Die and let the user know that they made a mistake.
    wp_die(‘No image was uploaded.’);
    }
    }
    // Else, the user didn’t upload a file.
    // Retain the image that’s already on file.
    else {
    $options = get_option(‘plugin_options’);
    $plugin_options[$keys[$i]] = $options[$keys[$i]];
    }
    $i++;
    }
    return $plugin_options;
    }

  • http://thomasgbennett.com Thomas Bennett

    Good post. Extremely helpful mixed with the Custom Post Types.

  • Pingback: Best of Tuts+ in January 2012 |

  • Pingback: Best of Tuts+ in January 2012 | linuxin.ro

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

  • Pingback: Creating a Filterable Portfolio with WordPress and jQuery | Wptuts+

  • Pingback: My Stream » Creating a Filterable Portfolio with WordPress and jQuery

  • Pingback: Creating a Filterable Portfolio with WordPress and jQuery | Wordpress Webdesigner

  • Pingback: Creating a Filterable Portfolio with WordPress and jQuery | Shadowtek | Hosting and Design Solutions

  • Pingback: Creating a Filterable Portfolio with WordPress and jQuery | How to Web

  • Mohamed Said

    Amazing tutorial, I made a use of it in making theme options

    http://pastie.org/private/5fklv9qqlebj7rewbulw

    • Japh Thomson
      Staff

      Thanks for your comment! Please use something like pastie.org for showing code snippets though ;)

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

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

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

  • http://nasteriadis.gr nickast

    Hey Guys,

    This was a great tutorial. I learned many things however when you are about to save the post and you want to check the if the old value is the same to the new value the old value does not contain anything in it. It simply updates without actually checking.

    I am talking about this specifically:
    $old = get_post_meta($post_id, $field['id'], true);

    I cannot figure out why it is not returning anything. Can you please guys give me a hand here?

    Thanx again for the great tut.

    • Ignacio

      Nickast, I hope is not too late:

      I don’t know if there is a bug when you save your post meta.

      Try to do this:

      function save_custom_meta($post_id) {
      wp_die($post_id);
      }

      You’ll see that every time you try to save your post the post_id increments, so you’re trying to save meta box data in a post that doesn’t exist. Why? Who knows?

      I use a sentence that change $post_id:

      function save_custom_meta($post_id) {
      if (wp_is_post_revision($post_id)) {
      $post_id = wp_is_post_revision($post_id);
      }
      .
      .
      .

      Now, everytime you save or publish your post, $post_id takes the right value.

      For now is working, but if someone knows a better way to do the same thing, pleeeeease tell us. I don’t like this hack.

    • Ignacio

      Ok, here is another answer for the future visitants:

      Instead of defining the function save_custom_meta like this:

      function save_custom_meta($post_id) {
      .
      .
      .
      }

      Do it this way:

      function save_custom_meta() {
      global $post;
      $post_id = $post -> ID;

      }

      Much better!

      • OllieJ Design

        THANK YOU for clearing that up. I couldn’t get any of the information to actually save and update until I tried the second solution you just put there.

        Now that I have a working piece of code, I have so many other areas that I plan to implement it.

      • Greg Trujillo

        Thank you so much! You fixed my unable to save problem!

  • Pingback: XPro Creative » Best Blog Tools

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

  • Pingback: Custom Post Type Helper Class | Wptuts+

  • Pingback: Custom Post Type Helper Class | Wordpress Webdesigner

  • Pingback: Custom Post Type Helper Class | Shadowtek Hosting and Design Solutions

  • Pingback: My Stream | Custom Post Type Helper Class | My Stream

  • Pingback: Custom Post Type Helper Class | How to Web

  • sandra

    Hello!

    Great tutorial. I am a newbie and I am having a bit of trouble. I copied all the snippets of code and put them in my functions.php file. For some reason the “Case Snippets” get highlighted as invalid code in my functions.php file. When I take them out the meta box shows up in my posts but there are no input fields. Do the “Case” Snippets go somewhere else?

    Sorry if this is a totally stupid question… I just want to add one custom text field to my posts.

    Again… thanks for tutorial as it is the most thorough I have come across.

    Thx!
    Sandra :)

    • nucci

      Did you solve this in any way? I got the exact same problem… No input files :(

      • Rabin

        make $custom_meta_fields as global, just before storing all the array values in this variable. Hope this you solve your issue.

        • http://creativetree.rs Alex

          I have the same problem, however, i do not understand what you ment with “make $custom_meta_fields as global, just before storing all the array values in this variable. Hope this you solve your issue.”

    • Erik

      Can anyone help with this…I get an “Parse error: syntax error, unexpected T_CASE” starting at the line “case ‘text’: ” …When I remove all the Case lines the meta box renders without the input fields….with the Case lines I get the above error, what am I missing…any ideas?

      • Erik

        My bad…figured it out…reading sure helps! :-)

        • Alex

          Can you help us understand? :)

          • david

            Did anyone figure this out? I am still trying to get past this part of the tutorial? Anyone?

          • Dave

            Never mind, case items go in the callback function. Read through this code (from the above tutorial) to see where they go.

            // The Callback
            function show_custom_meta_box() {
            global $custom_meta_fields, $post;
            // Use nonce for verification
            echo ”;

            // Begin the field table and loop
            echo ”;
            foreach ($custom_meta_fields as $field) {
            // get value of this field if it exists for this post
            $meta = get_post_meta($post->ID, $field['id'], true);
            // begin a table row with
            echo ‘
            ‘.$field['label'].’
            ‘;
            switch($field['type']) {

            // case items will go here

            } //end switch
            echo ”;
            } // end foreach
            echo ”; // end table
            }

        • Daniel

          Can you tell me how you solved it?
          I think the case items should go where it says “// case items will go here”, but what piece of code should go there?

  • Pingback: Reusable Custom Meta Boxes Part 4: Using the Data | Wptuts+

  • Pingback: Reusable Custom Meta Boxes Part 4: Using the Data | Wordpress Webdesigner

  • Pingback: Reusable Custom Meta Boxes Part 4: Using the Data | Shadowtek Hosting and Design Solutions

  • Pingback: My Stream | Reusable Custom Meta Boxes Part 4: Using the Data | My Stream

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

  • http://www.olliejdesign.com OllieJ Design

    I’m in the process of redesigning my website and one of the first things that I need to do is move my Portfolio CPT over to a plugin. The CPT works perfectly well, but I’d like to add Custom Meta Boxes so I don’t have to bother with Custom Fields repeatedly. (This would also help me in the future when designing sites for clients to make it easier for them to input custom data.)

    Anyway, I’m stuck. Really stuck. If anyone could be kind enough to tell me what I’m missing or doing wrong, I’d be in your debt.

  • http://www.olliejdesign.com OllieJ Design

    I’m in the process of redesigning my website and one of the first things that I need to do is move my Portfolio CPT over to a plugin. The CPT works perfectly well, but I’d like to add Custom Meta Boxes so I don’t have to bother with Custom Fields repeatedly. (This would also help me in the future when designing sites for clients to make it easier for them to input custom data.)
    Anyway, I’m stuck. Really stuck. If anyone could be kind enough to tell me what I’m missing or doing wrong, I’d be in your debt.

    __(‘Portfolio’, ”),
    ‘singular_name’ => __(‘Project’, ‘post type singular name’),
    ‘add_new’ => __(‘Add New Project’, ”),
    ‘add_new_item’ => __(‘Add New Project’),
    ‘edit_item’ => __(‘Edit Projects’),
    ‘new_item’ => __(‘New Project’),
    ‘all_items’ => __(‘All Projects’),
    ‘view_item’ => __(‘View Portfolio’),
    ‘search_items’ => __(‘Search Portfolio’),
    ‘not_found’ => __(‘No projects found’),
    ‘not_found_in_trash’ => __(‘No projects found in Trash’),
    ‘parent_item_colon’ => ”,
    ‘menu_name’ => ‘Portfolio’

    );
    $args = array(
    ‘labels’ => $labels,
    ‘public’ => true,
    ‘publicly_queryable’ => true,
    ‘show_ui’ => true,
    ‘show_in_menu’ => true,
    ‘query_var’ => true,
    ‘rewrite’ => true,
    ‘capability_type’ => ‘post’,
    ‘has_archive’ => true,
    ‘hierarchical’ => false,
    ‘menu_position’ => null,
    ‘supports’ => array( ‘title’, ‘editor’, ‘author’, ‘thumbnail’, ‘excerpt’ )
    );
    register_post_type(‘Portfolio’,$args);
    }
    add_action( ‘init’, ‘olliejdesign_portfolio_init’ );

    // Add taxonomies
    add_action( ‘init’, ‘create_taxonomies’ );

    //create taxonomies
    function create_taxonomies() {

    // portfolio taxonomies
    $cat_labels = array(
    ‘name’ => __( ‘Project Categories’, ” ),
    ‘singular_name’ => __( ‘Project Category’, ” ),
    ‘search_items’ => __( ‘Search Project Categories’, ” ),
    ‘all_items’ => __( ‘All Project Categories’, ” ),
    ‘parent_item’ => __( ‘Parent Project Category’, ” ),
    ‘parent_item_colon’ => __( ‘Parent Project Category:’, ” ),
    ‘edit_item’ => __( ‘Edit Project Category’, ” ),
    ‘update_item’ => __( ‘Update Project Category’, ” ),
    ‘add_new_item’ => __( ‘Add New Project Category’, ” ),
    ‘new_item_name’ => __( ‘New Project Category Name’, ” ),
    ‘choose_from_most_used’ => __( ‘Choose from the most used project categories’, ” )
    );

    register_taxonomy(‘project_cats’,'portfolio’,array(
    ‘hierarchical’ => true,
    ‘labels’ => $cat_labels,
    ‘query_var’ => true,
    ‘rewrite’ => array( ‘slug’ => ‘project-category’ ),
    ));

    }

    // Fire our meta box setup function on the post editor screen
    add_action( ‘load-post.php’, ‘olliejdesign_post_meta_boxes_setup’ );
    add_action( ‘load-post-new.php’, ‘olliejdesign_post_meta_boxes_setup’ );

    // Meta box setup function
    function olliejdesign_post_meta_boxes_setup() {

    // Add meta boxes on the ‘add_meta_boxes’ hook
    add_action( ‘add_meta_boxes’, ‘olliejdesign_add_post_meta_boxes’ );

    // Save post meta on the ‘save_post’ hook
    add_action( ‘save_post’, ‘olliejdesign_save_project_description_meta’, 10, 2 );
    }

    function olliejdesign_add_post_meta_boxes() {

    add_meta_box(
    ‘olliejdesign-project-description’,
    esc_html__( ‘Project Description’ ),
    ‘olliejdesign_project_description_meta_box’,
    ‘portfolio’,
    ‘normal’,
    ‘high’
    );
    }

    function olliejdesign_project_description_meta_box($object, $box) { ?>

    <textarea name="olliejdesign-project-description" id="olliejdesign_project_description" value="ID, ‘olliejdesign-project-description’, true ) ); ?>” cols=”200″>

    post_type );

    // Check if the current user has permission to edit the post.
    if ( !current_user_can( $post_type->cap->edit_post, $post_id ) )
    return $post_id;

    // Get the posted data and sanitize it for use as an HTML class.
    $new_meta_value = ( isset( $_POST['olliejdesign-project-description'] ) ? sanitize_html_class( $_POST['olliejdesign-project-description'] ) : ” );

    // Get the meta key.
    $meta_key = ‘olliejdesign-project-description’;

    // Get the meta value of the custom field key.
    $meta_value = get_post_meta( $post_id, $meta_key, true );

    // If a new meta value was added and there was no previous value, add it.
    if ( $new_meta_value && ” == $meta_value )
    add_post_meta( $post_id, $meta_key, $new_meta_value, true );

    // If the new meta value does not match the old value, update it.
    elseif ( $new_meta_value && $new_meta_value != $meta_value )
    update_post_meta( $post_id, $meta_key, $new_meta_value );

    // If there is no new meta value but an old value exists, delete it.
    elseif ( ” == $new_meta_value && $meta_value )
    delete_post_meta( $post_id, $meta_key, $meta_value );
    }

    ?>

  • Andrew

    Great post. Will you be covering how to sanitize the fields at some point in this series?

  • Andrew

    I think there’s a missing curly brace or one extra (depending on how you look at it) under “save the data” section

    This bit looks off:

    // 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;
    }

    • Andrew

      I’m also getting a PHP Notice : Undefined index when using the exact code above. Can anybody see what the problem is?

      PHP Notice: Undefined index: custom_meta_box_nonce

      • http://www.netmechanics.co.nz Gwilym

        I get the same error..

        NOTICE Error: [8] Undefined index: custom_meta_box_nonce

        Something awry here

        // verify nonce
        if (!wp_verify_nonce($_POST['custom_meta_box_nonce'], basename(__FILE__)))
        return $post_id;

  • Emanuel

    Hi!

    I used this script in a Custum Post Type and it worked great.
    Then I tried to use it for another CPT. I copied the file and made some changes, but i got this error:

    Fatal error: Cannot redeclare add_custom_meta_box() (previously declared in D:\Trabalhos\Web Design\htdocs\OneClinic\wp-content\themes\oneclinic_wp\funcoes-wp\mb_equipa.php:5) in D:\Trabalhos\Web Design\htdocs\OneClinic\wp-content\themes\oneclinic_wp\funcoes-wp\mb_seguros.php on line 12

    If I can’t redeclare that function what can I do to use the script in more than one CPT?

  • kevin

    How would you go about using two different metaboxes for two different custom post types? Or is this even possible?

  • Scott Fennell

    I love this tutorial. Two things:

    1. One commentor mentioned that you need to sanitize the data. I believe update_post_meta automatically sanitizes data for you.

    2. I notice that I get a php error during quick edit mode: an undefined variable for the nonce variable. The only way I know to prevent this is to add a check for

    if(isset($_POST['custom_meta_box_nonce'])){

    • http://twitter.com/Smartik89 Smartik

      I have done it so:
      if (!wp_verify_nonce(isset($_POST['custom_meta_box_nonce']), basename(__FILE__))) ...

  • Pingback: 여러가지 사이트 모음 | talkpress

  • http://www.netz-gaenger.de Netzgänger

    Great, that works perfectly. Nice Job. But how to do this with a multiple select? Of course i can show one in the meta box. But how save and get the values out of it?

    • http://www.facebook.com/kriss.heibananas Kriss Heibananas

      I’d really like to know this too!
      The ability to associate posts with each other from a list is incredible but I need to add multiples.
      Any help?

  • godel

    Thanks for the great tutorial.

    if you do not mind I’d like to ask you some questions,
    how if we want to store the data in the new table?, for example save in the new table named new_metabox with column name: post_id, text_input, text_area, checkbox_input and select_box

    thank you.

  • RANS

    Amazing post, I learn a lot, but I need a help.

    I’m going crazy when I use two checkbox group if disable all checkbox still saving the old value, and if I disable all of then on one checkbox group and leave one of the checked in the other group it save the both meta_box with the last value checked, any can help me please???

    Thanks a lot

    • http://www.scottfennell.com Scott Fennell

      Ooh, man I still love this plugin, but major -1 for polluting the global namespace with “global $custom_meta_fields”.

      I’ve noticed that I get some chaos in my post edit screen if I have two plugins running this code, even with different values for “prefix”. Could be very dangerous.

      Basically, need to change every instance of $custom_meta_fields to $(your prefix here)_custom_meta_fields.

  • Pingback: Integrating Google Rich Snippets Into a WordPress Theme | Wptuts+

  • Pingback: My Stream | Integrating Google Rich Snippets Into a WordPress Theme | My Stream

  • Pingback: Integrating Google Rich Snippets Into a WordPress Theme | How to Web

  • Pingback: Integrating Google Rich Snippets Into a WordPress Theme « Tech Snippets

  • Pingback: Integrating Google Rich Snippets Into a WordPress Theme

  • http://www.scottfennell.com Scott Fennell

    Ah, man, this has gone from being one of my favorite tuts ever to really disappointing me.

    When outputting the form fields in admin area: esc_attr() anyone? If there’s a quotation mark in the text input, you just set up your own code injection vulnerability.

  • Pingback: Как правильно интегрировать сниппеты Google в тему WordPress | Wordpresso

  • http://www.brettadamsga.com BrettAdamsGA

    Thanks for this post I was able to use the info to help with one of the websites I am developing on WordPress. Thanks, Again

  • Dave

    How do you output the data? I tried using: ID, ‘custom_text’, true);?>

    but it only gives me the text field non of the other fields show. When I use: get_post_custom all I get for an output is Array. Any ideas or help?

  • Pingback: Formation Wordpress

  • Pingback: Reusable Custom Meta Boxes Part 4: Using the Data | 87studios.net

  • FilipeCarranoPacheco

    Hi, Could anyone help me? How can I add two different metaboxes?

  • Pingback: How to Display Metaboxes According to the Current Post Format | Wptuts+

  • Pingback: How to Display Metaboxes According to the Current Post Format | Wordpress Webdesigner

  • Pingback: Wordpress Leaks » How to Display Metaboxes According to the Current Post Format

  • Casper

    Can anyone help me out? I get an Notice of Undefined Index: custom_text and all the other fields we created in this tutorial. What do I wrong. I had just copy and past the code in a file…. Hope you can help me!

  • http://www.facebook.com/circuit.circus Circuit Circus

    call_user_func(…: When you get this error message it might be you have set different strings for the Callback. For that case, check line 6 at “Create a Meta Box” and line 2 at ”

    Outputting the Fields”! Though they match in this tutorial, changing all the strings to your needs might lead you to not give regard. This just as a small hint.

  • Jason

    Is it possible to have multiple meta boxes using this?

  • Chathuranga Arambewela

    Hi, some thing is wrong i guess. when i submitted the data a white screen appears. ! but data are saved.

    • Lawrence

      I’m having the same problem, but only only my server not xampp.

    • Ian Wilson

      if you go to your wp_config.php file and scroll down till you see “define(‘WP_DEBUG’, false);” change that to true. Once you’ve done that, try to update you meta again, if there’s a problem with your code wordpress will now throw error, notice, or warning messages on your screen to help you find your problem.

      Oh, and I have the same problem if anyone can help I just know that have a notice getting thrown at me!

      “Notice: Undefined index: custom_checkbox in /home5/desigoe6/public_html/wordpress-dev/wp-content/themes/Mom-Bomb/functions.php on line 213

      Notice: Undefined index: custom_checkbox in /home5/desigoe6/public_html/wordpress-dev/wp-content/themes/Mom-Bomb/functions.php on line 213

      Warning: Cannot modify header information – headers already sent by (output started at /home5/desigoe6/public_html/wordpress-dev/wp-content/themes/Mom-Bomb/functions.php:213) in/home5/desigoe6/public_html/wordpress-dev/wp-includes/pluggable.php on line 876″

      This is what I see when my meta box is deleting data. If anyone can help it’d be appreciated!

  • Ian Wilson

    Fix for “Notice: Undefined index” that gets thrown by “WP_DEBUG” while working with meta boxes …

    http://forr.st/~FYO

    Hope it helps someone ;)
    Enjoy!!!

  • Pingback: Nonce check causing issues when creating new post | Question and Answer

  • Greg Trujillo

    I have tried this and every time I try, it completely breaks my wordpress installation. I need to upload a backup of the functions.php in order to fix the issue.

    Any Idea what im doing wrong? I follow the directions (even though they are not very clear for each step).

    • http://www.facebook.com/petr.cibulka Petr Cibulka

      Hi Greg! It seems that hell of a lot commenters (including me) have the same issue – where should you put the case data? Should it be here?

      switch($field['type']) {
      // case items will go here
      } //end switch

      The tutorial is not very clear about that. Thank you!

  • http://twitter.com/idleberg idleberg

    i noticed that checked checkboxes are saved properly, but once i uncheck them and save again, wordpress will remember the checked status

  • Aquanat Holding

    Hi

    Beautiful tutorial!!!

    Can you help me? I don’t know why wordpress doesn’t save metabox fields…

    My code: http://pastebin.com/jezygsuL

    Thanks!!!

    p.s. i wrote echo add_action(‘save_post’, ‘save_restaurant_custom_meta’); only to see return value…i

  • Developer

    Will not save a ’0′ (zero) value as is. You must use if(isset($new) &&… instead of if($new &&… also do this with the $old.

    Great post though! very helpful. Thanks!