Save selected item from dropdown menu in a meta box as a metadata value for a custom post type

The question:

I have been beating my brains on this one for days now and my Google-fu is failing me.

I have created a custom meta box with a dropdown menu that lists all of the terms from a custom taxonomy. What I cannot figure out is how to save the selected option from the drop down menu when the post is saved. I’m a bit of a newb in PHP and though I have found plenty of tutorials and other questions that talk about how to do this, I always get baffled when they get to the part about saving the data.

Here’s my code to create the metabox:

function MC_Catalog_create() {
    add_meta_box( 'MC_Catalog_meta', 'Course Information', 'MC_Catalog_course_info','mc_course_post', 'normal', 'high' );

function MC_Catalog_course_info( $post ) {

$MC_Catalog_course_area = get_post_meta( $post->ID, '_MC_Catalog_course_area', true );
$MC_Catalog_course_num = get_post_meta( $post->ID, '_MC_Catalog_course_num', true );
$MC_Catalog_course_name = get_post_meta( $post->ID, '_MC_Catalog_course_name', true );
$MC_Catalog_course_desc = get_post_meta( $post->ID, '_MC_Catalog_course_desc', true );

<table class="form-table" style="width:auto;">
        <td valign="top">Course Area:</td>
        <td valign="top">
        <select name="MC_Catalog_course_area">
           $myterms = get_terms('course_areas', $args);
                $args = array('orderby'=>'name','order'=>'ASC','hide_empty'=>false);
            foreach($myterms as $term){
                echo "<option value='$term->term_id'" . selected( $term->term_id, $MC_Catalog_course_area, false) .">" . esc_html( $term->name ) . "</option>";
        <td valign="top">Course Number:</td>
        <td valign="top"><input name="MC_Catalog_course_num" type="text" value="<?php echo esc_attr( $MC_Catalog_course_num ); ?>" size="50" /></td>
        <td valign="top">Course Title:</td>
        <td valign="top"><input type="text" name="MC_Catalog_course_name" value="<?php echo esc_attr( $MC_Catalog_course_name ); ?>" size="50" /></td>
        <td valign="top">Course Description:</td>
        <td valign="top"><textarea name="MC_Catalog_course_desc" rows="8" cols="100"><?php echo esc_attr( $MC_Catalog_course_desc ); ?></textarea></td>
<?php } ?>

And here’s my code to save the metadata:

//hook to save the meta box data
add_action( 'save_post', 'MC_Catalog_save_meta' );

function MC_Catalog_save_meta( $post_id ) {

    //verify the meta data is set
    if ( isset( $_POST['MC_Catalog_course_num'] ) ) {

        //save the meta data
        update_post_meta( $post_id, '_MC_Catalog_course_area', strip_tags( $_POST['MC_Catalog_course_area'] ) );
    update_post_meta( $post_id, '_MC_Catalog_course_num', strip_tags( $_POST['MC_Catalog_course_num'] ) );
    update_post_meta( $post_id, '_MC_Catalog_course_name', strip_tags( $_POST['MC_Catalog_course_name'] ) );
    update_post_meta( $post_id, '_MC_Catalog_course_desc', strip_tags( $_POST['MC_Catalog_course_desc'] ) );

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

$myterms = get_terms($taxonomies, $args); returns an array of term objects. Use $term->term_id as option value …

"<option value='$term->term_id'>". esc_html( $term_name ) . "</option>"

… and store that ID, not the name. Names can change, the IDs will stay the same – unless someone deletes a term and creates a new one with the same name.

To select the correct option use selected():

"<option value='$term->term_id'" . selected( $term->term_id, $MC_Catalog_course_area, FALSE ) .">"

You can validate the value with absint() then.

Your save_post handler needs more checks.

All methods was sourced from or, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment