Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I have a custom metabox in a custom post type that records system outages across the campus that I work at. One of the fields in the metabox is a multiselect box listing all the buildings on campus.

When I save the post, I am able to retrieve the array of buildings on the front-end. However, if I go back to edit the post, the multiselect does not highlight the list of buildings that were previously selected. Therefore, if I update the post, I have to remember to also re-highlight the buildings that are affected by the outage. All other (non-array) fields successfully retain their data.

Adding the custom MetaBox:

function add_custom_meta_box() {
    add_meta_box('system_outage','System Outage','show_system_outage','outage','normal','high');
    }
add_action('add_meta_boxes', 'add_custom_meta_box');

Create Field Array:

$prefix = 'sysout_';
$outage_meta_fields = array(
    array(
        'label' => 'Buildings Affected',
        'desc' => 'Select the buildings affected',
        'id' => $prefix.'buildings',
        'type' => 'multiselect',
        'options' => array(
            'building1' => array(
                'label' => 'Building 1',
                'value' => 'building1'
            ),
            'building2' => array(
                'label' => 'Building 2',
                'value' => 'building2' //This continues for a while
            )
        )
    );
);

The Callback:

function show_system_outage() {
    global $outage_meta_fields, $post;
    echo '<input type="hidden" name="custom_meta_box_nonce" value="'.wp_create_nonce(basename(__FILE__)).'" />';
    echo '<table class="form-table">';
        foreach ($outage_meta_fields as $field) {
            $meta = get_post_meta($post->ID, $field['id'], true);
            echo '<tr>';
                echo '<th><label for="'.$field['id'].'">'.$field['label'].'</label></th>';
                echo '<td>';
                    switch($field['type']) {

                        case 'multiselect':
                            echo '<select data-placeholder="Choose a building..." multiple="true" class="chosen" 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;

                    }
                echo '</td>';
            echo '</tr>';
        }
    echo '</table>';
}

And Then I Save the Data:

function save_custom_meta($post_id) {
    global $outage_meta_fields;

    if (!wp_verify_nonce($_POST['custom_meta_box_nonce'], basename(__FILE__)))
        return $post_id;
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
        return $post_id;
    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;
    }

    foreach ($outage_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);
        }
    }

}
add_action('save_post', 'save_custom_meta');

I hope I have formatted it so that it's vaguely readable.

Any guidance on this would be gratefully received. Thanks!

share|improve this question
add comment

2 Answers

up vote 0 down vote accepted

I tested your code and this ended up working for me:

case 'multiselect':  
  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; 


For the Field Array I just added another option with a blank value and a label of "Select".
Also, I removed an extra ";" on the second to last line.

$prefix = 'sysout_';
$outage_meta_fields = array(
    array(
        'label' => 'Buildings Affected',
        'desc' => 'Select the buildings affected',
        'id' => $prefix.'buildings',
        'type' => 'multiselect',
        'options' => array(
            'Select' => array(
                'label' => 'Select',
                'value' => ''
            ),
            'building1' => array(
                'label' => 'Building 1',
                'value' => 'building1'
            ),
            'building2' => array(
                'label' => 'Building 2',
                'value' => 'building2' //This continues for a while
            )
        )
    )
);
share|improve this answer
    
I just realized you would like to be able to select multiple options, instead of just one. –  keilowe Jul 13 '13 at 2:25
    
Check out an updated version of Reusable Custom Meta Boxes "Select and Chosen select with support for "multiple"" –  keilowe Jul 14 '13 at 20:04
    
Although I marked this as the answer because it really pointed me in the right direction, please see below for the actual answer. –  sqdge Jul 15 '13 at 16:50
    
I'm late...But thank you for accepting :) –  keilowe Jul 23 '13 at 16:21
add comment

I marked keihead's response as the answer, because they definitely pointed me in the right direction. However, the article at Reusable Custom Metaboxes still failed to retrieve the data from the array into the Edit Post section. Luckily, their process for adding checkboxes contained the part that was missing from the multiple select instructions.

$prefix = 'sysout_';
$outage_meta_fields = array(
    array(
        'label' => 'Buildings Affected',
        'desc' => 'Select the buildings affected',
        'id' => $prefix.'buildings',
        'type' => 'chosen', //This was only changed to match the instructions
        'multiple' => true, //This didn't have to be an option - I could have added multiple="multiple" in the HTML below
        'options' => array(
            'building1' => array(
                'label' => 'Building 1',
                'value' => 'building1'
            ),
            'building2' => array(
                'label' => 'Building 2',
                'value' => 'building2'
            )
        )
    )
);

The part that made all the difference was the is_array ( $meta )... part. This queries the database for an array, and if the value is present in the array, it marks the option as "selected" in the multiple selection box.

Please note: I am also using the JQuery Chosen plugin, so that option is also present in the code.

case 'chosen':
    echo '<select name="'.$field['id'].'[]" id="'.$field['id'].'"' , $field['type'] == 'chosen' ? ' class="chosen"' : '' , isset( $field['multiple'] ) && $field['multiple'] == true ? ' multiple="multiple"' : '' , '>';
    foreach ( $field['options'] as $option )
        echo '<option value="' . $option['value'] . '"' , is_array( $meta ) && in_array( $option['value'], $meta ) ? ' selected="selected"' : '' , ' >' . $option['label'] . '</option>';
    echo '</select><br />' . $field['desc'];
break;
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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