I set up two select boxes in one meta field by putting two arrays inside the 'options' array of my callback. The HTML is outputting fine, but the meta is not being saved to the database...

Here is a pic of the meta box setup (for whatever random reason that make me think it would be helpful):

...aaaaaaaaaaaaaaaaaaand here's my code:

add_action( 'add_meta_boxes', 'event_infobox_add' );                                                        
add_action( 'save_post', 'event_infobox_save' );
function event_infobox_add() {
'event_infobox', // $id 
'Event Date, Time, and Venue Info', // $title 
'event_infobox_call', // $callback
'events', // $page
'normal', // $context 
'high' // $priority   

// Time options for dropdowns in the HTML
$times = array(  'hour00' => '12AM' ,'hour01' => '1AM' ,'hour02' => '2AM' ,'hour03' => '3AM' ,'hour04' => '4AM' ,'hour05' => '5AM' ,'hour06' => '6AM' ,'hour07' => '7AM' ,'hour08' => '8AM' ,'hour09' => '9AM' ,'hour10' => '10AM' ,'hour11' => '11AM' ,'hour12' => '12PM' ,'hour13' => '1PM' ,'hour14' => '2PM' ,'hour15' => '3PM' ,'hour16' => '4PM' ,'hour17' => '5PM' ,'hour18' => '6PM' ,'hour19' => '7PM' ,'hour20' => '8PM' ,'hour21' => '9PM' ,'hour22' => '10PM' ,'hour23' => '11PM' );

// Meta Box fields HTML
$event_infobox_fields = array(
     'label' => 'Event Time Frame'
    ,'desc' => 'Enter time frame of the event here'
    ,'id' => 'event_timeframe'  //values stored with this key
    ,'class' => ''
    ,'type' => 'select'
    ,'options' => array(
        'timestart' => $times,
        'timeend' => $times

function event_infobox_call( $post ) {
global $event_infobox_fields, $post;  
// Use nonce for verification  
wp_nonce_field( plugin_basename( __FILE__ ), 'event_infobox_nonce' );
echo '<input type="hidden" name="event_infobox_box_nonce" value="'.wp_create_nonce(basename(__FILE__)).'" />';  

// Loop it up
echo '<table class="form-table">';

foreach ($event_infobox_fields as $field) {  
    $meta = get_post_meta($post->ID, $field['id'], true); 
    echo '<tr>
        <label for="'.$field['id'].'">'.$field['label'].'</label>
        <span class="meta-description">'.$field['desc'].'</span>
    switch($field['type']) {

        case 'select':

        // Event Timeframe Select Dropdowns
        if ( $field['id'] == 'event_timeframe') {
            foreach ($field['options'] as $key => $value ){
                echo $meta;
                $keyhead = str_replace('time','',$key);
                echo '<span>'.$keyhead.'</span>
                            <select style="width:200px; display:block;" name="'.$key.'" id="'.$key.'">';
                $total = count($field['options'][$key])-1;
                for ($i=0; $i<=$total; $i++){
                    if($i<10) {
                    echo '<option style="width:200px; display:block;" value="'.$field['options'][$key]['hour'.$i].'"', $meta == $field['options'][$key]['hour'.$i] ? 'selected="selected"' : '','>'.$field['options'][$key]['hour'.$i].'</option>';
                echo '</select>';



    } //end switch  
echo '</td></tr>';  
} // end foreach

echo '</table>'; // end table  

// $ave $ave $ave
function event_infobox_save( $post_id ) { 
global $event_infobox_fields;  

// verify nonce  
if (!wp_verify_nonce($_POST['event_infobox_box_nonce'], basename(__FILE__)))  
        return $post_id;  
// check 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 ($event_infobox_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  

1 Answer 1


In your save code, the value of $field['id'] is event_timeframe, which does not exist in $_POST, so your options will never save.

You need to dig down into your options array to get to timestart and timeend:

// loop through fields and save the data  
    foreach ( $event_infobox_fields as $field ) {
        foreach ( $field['options'] as $option_key => $option_value ) {
            $old = get_post_meta( $post_id, $option_key, true );
            $new = $_POST[$option_key];
            if ( $new && $new != $old ) {
                update_post_meta( $post_id, $option_key, $new );
            } elseif ( '' == $new && $old ) {
                delete_post_meta( $post_id, $option_key, $old );
        } // end foreach  

Bear in mind that you will also have to update the meta used in your dropdown code in order to pre-populate those.

  • Ah, yes, I kind of figured I just wasn't getting deep enough, but didn't want to sound any more n00bish than I already did. Plus I didn't know how exactly to go about delving deeper in the first place ... In the end this is more of a PHP question than a Wordpress question, too. Anyway, thank you, your answer worked like a charm. And, yea, I know I gotta readjust my check for the "selected" value in the option tags ;) Apr 25, 2013 at 19:30
  • If my answer was correct, please click the adjacent tick to indicate this for other users. Cheers.
    – vancoder
    Apr 25, 2013 at 19:32
  • So, another question regarding saving the meta, but now with multiple fields.. I had omitted it from my initial question as it seemed irrelevant, but I have another field in the metabox with its own select dropdown. It has been saving correctly all along, but of course your update function in place of the old one disabled this other dropdown as it doesnt have these second-level arrays. So, just now I tried using both your new update function along with my old one. It works fine as far as I can tell- database entries do get updated. My question is this: Is there anything "wrong" with doing so? Apr 25, 2013 at 19:37
  • I cant say how efficient it is without seeing it, but basically if you check the $field['id'] just inside the first loop, you can handle each field differently.
    – vancoder
    Apr 25, 2013 at 21:29
  • Ah, yes! Now why couldn't I have thought of that? Cheer's for the help ........................................... foreach ($event_infobox_fields as $field) { if($field['id'] == 'event_timeframe') { ...new update script...} else {...old update script...} } Apr 25, 2013 at 22:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.