Wordpress - How to update_post_meta value as array

You do this:

$item->content_multiple = get_post_meta($item->ID, '_menu_item_content_multiple', true);

Note how you set the third parameter of get_post_meta() to true, which means that only one value will be returned. If you read the docs, you will see that, if the third parameter is false, you will get an array with all the values for that meta field.

Remember that meta fields can be unique or can be multiple. Or it can be unique with a serialized data string.

As it is, your code seems to store all values from the select multiple into one single meta field. So, you get an array in the request and pass it as single value of the meta field. When the value of a meta field is an array, WordPress converts it to a serialized string before it is stored in the database; this is done internally with the function maybe_serialize(). Then, when you try to get the value of the meta field, if it is a serialized string, WordPress pass it through maybe_unserialize(), so the serialized string converts back to the array:

Let's explain with a generic example.

This will be the array of values to be stored in the database:

$values = [ 'red', 'yellow', 'blue', 'pink' ];

If your meta key is "color", the you have two options:

Multiple entries for the same meta key

$values = [ 'red', 'yellow', 'blue', 'pink' ];
foreach( $values as $value ) {
    // This method uses `add_post_meta()` instead of `update_post_meta()`
    add_post_meta( $item_id, 'color', $value );
}

Now, the item identified with $item_id will have several entries for the color meta key. Then, you can use get_post_meta() with the third parameter set to false and you will get an array with all the values:

// You don't really need the set the third parameter
// because it is false vay default
$colors = get_post_meta( $item_id, 'color' );

// $colors should an array with all the meta values for the color meta key
var_dump( $colors );

Store the array in a single meta entry

In this case, the array of values is serialized before it is sotred in database:

$values = [ 'red', 'yellow', 'blue', 'pink' ];
// WordPress does this automatically when an array is passed as meta value
// $values = maybe_serialize( $values );
update_post_meta( $item_id, 'color', $values );

Now, the item identified with $item_id will have only one entry for the color meta key; the value is a serialized string representing the original array. Then, you can use get_post_meta(), with the third parameter set to true, as you have only one entry, and then unserialize the string to get back the array:

$colors = get_post_meta( $item_id, 'color', true );
// WordPress does this automatically when the meta value is a serialized array
// $colors = maybe_unserialize( $colors );

// $colors should be an array
var_dump( $colors );

You can follow the same approach with the select multiple of your form.

With only one entry for the meta key:

if( ! empty( $_REQUEST['menu-item-content-multiple'][$menu_item_db_id] ) ) {
    $meta_field_value = $_REQUEST['menu-item-content-multiple'][$menu_item_db_id];
    // $meta_field_value will be serialized automatically by WordPress
    update_post_meta( $menu_item_db_id, '_menu_item_content_multiple', $meta_field_value );
}

Then, you can use the value as array:

 // The value returned by get_post_meta() is unserialized automatically by WordPress
 $item->content_multiple = get_post_meta( $item->ID, '_menu_item_content_multiple', true );

With multiple entries:

The concept here is a bit different; you will several entries in the database with the same meta key, so you need to use add_post_meta() instead of update_post_meta() in order to add a new entry for each value.

if( ! empty( $_REQUEST['menu-item-content-multiple'][$menu_item_db_id] ) ) {
    $values = $_REQUEST[ 'menu-item-content-multiple' . $menu_item_db_id ];
    foreach( $values as $value ) {
        add_post_meta( $menu_item_db_id, '_menu_item_content_multiple', $value );
    }
}

Now, you can use get_post_meta() with the third parameter set to false (it is the default value, so you can omit it):

$item->content_multiple = get_post_meta( $item->ID, '_menu_item_content_multiple', false );

Both options are OK, you must decide which one is better to organize the data within your project.

Side note: you should do some santization before using the input data, but I don't know the requirements for you, here a example:

array_map( 'sanitize_text_field', wp_unslash( $_REQUEST['menu-item-content-multiple'][$menu_item_db_id] ) );

Tags:

Post Meta