Adding multiselect custom field in Woocommerce product form

Here’s a quick tip if you are wondering of how to add multiselect fields in your Woocommerce product form.

Woocommerce has a great support for adding custom fields on a product page. There are some plugins available which help you to get things done, but it’s not really that complicated to write the code by yourself – and eliminate a need to install yet another plugin for your site. Here’s a great article of how to add fields: Mastering WooCommerce Products Custom Fields.

What if you want to add a multiselect field? It’s not that difficult either – create a function to populate multiselect field and save selection when product page is saved. The key difference with a single select field is that instead of saving single value to WordPress meta data, you save an array of values.

First, creating function to output and populate multiselect field, we can simply copy Woocommerce function for single select field and modify that to our needs. You can find it in woocommerce/includes/admin/wc-mate-box-function.php file. To save your time, here’s a modified function. Include it to your functions.php file:

function woocommerce_wp_select_multiple( $field ) {
    global $thepostid, $post;

    $thepostid              = empty( $thepostid ) ? $post->ID : $thepostid;
    $field['class']         = isset( $field['class'] ) ? $field['class'] : 'select short';
    $field['wrapper_class'] = isset( $field['wrapper_class'] ) ? $field['wrapper_class'] : '';
    $field['name']          = isset( $field['name'] ) ? $field['name'] : $field['id'];
    $field['value']         = isset( $field['value'] ) ? $field['value'] : ( get_post_meta( $thepostid, $field['id'], true ) ? get_post_meta( $thepostid, $field['id'], true ) : array() );

    echo '<p class="form-field ' . esc_attr( $field['id'] ) . '_field ' . esc_attr( $field['wrapper_class'] ) . '"><label for="' . esc_attr( $field['id'] ) . '">' . wp_kses_post( $field['label'] ) . '</label><select id="' . esc_attr( $field['id'] ) . '" name="' . esc_attr( $field['name'] ) . '" class="' . esc_attr( $field['class'] ) . '" multiple="multiple">';

    foreach ( $field['options'] as $key => $value ) {
        echo '<option value="' . esc_attr( $key ) . '" ' . ( in_array( $key, $field['value'] ) ? 'selected="selected"' : '' ) . '>' . esc_html( $value ) . '</option>';
    }

    echo '</select> ';

    if ( ! empty( $field['description'] ) ) {
        if ( isset( $field['desc_tip'] ) && false !== $field['desc_tip'] ) {
            echo '<img class="help_tip" data-tip="' . esc_attr( $field['description'] ) . '" src="' . esc_url( WC()->plugin_url() ) . '/assets/images/help.png" height="16" width="16" />';
        } else {
            echo '<span class="description">' . wp_kses_post( $field['description'] ) . '</span>';
        }
    }
    echo '</p>';
}

At this point you probably have a function in functions.php that handles adding your custom fields to the product form. Place the following call there:

woocommerce_wp_select_multiple(
    array(
        'id' => '_myfield',
        'name' => '_myfield[]',
        'label' => 'My Multiselect Field',
        'options' => ['key1' => 'First Item', 'key2' => 'Second Item', 'key3' => 'Third Item']
    )
);

Last but not least, place the following line to a function where you save your fields:

update_post_meta($post_id, '_myfield', $_POST['_myfield']);

See, you don’t even have to serialize the array data, good old WordPress does that for you inside update_post_meta function.

That should be enough. This was a very simplified example and you may need to add some validation logic and other stuff based on your needs.