0

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!

2 Answers 2

0

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
            )
        )
    )
);
4
  • I just realized you would like to be able to select multiple options, instead of just one.
    – keilowe
    Jul 13, 2013 at 2:25
  • Check out an updated version of Reusable Custom Meta Boxes "Select and Chosen select with support for "multiple""
    – keilowe
    Jul 14, 2013 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, 2013 at 16:50
  • I'm late...But thank you for accepting :)
    – keilowe
    Jul 23, 2013 at 16:21
2

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;

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.