9

I created new custom field within my nav menu items as multiple select options i used update_post_meta() as below

function YPE_update_custom_fields($menu_id, $menu_item_db_id, $menu_item_data) {
    if (is_array($_REQUEST['menu-item-content-multiple'])) {
        update_post_meta($menu_item_db_id, '_menu_item_content_multiple', $_REQUEST['menu-item-content-multiple'][$menu_item_db_id]);
    }
}
add_action('wp_update_nav_menu_item', 'YPE_update_custom_fields', 10, 3);

function YPE_setup_custom_fields($item) {
    $item->content_multiple = get_post_meta($item->ID, '_menu_item_content_multiple', true);
    return $item;
}
add_filter('wp_setup_nav_menu_item', 'YPE_setup_custom_fields');

Then I add new field into Walker_Nav_Menu_Edit file as below

EDITED

<?php
$select_options = array (
    'key_1' => 'option1', 
    'key_2' => 'option2', 
    'key_3' => 'option3'
); 
?>
<p class="field-content-multiple description description-thin">
<label for="edit-menu-item-content-multiple-<?php echo $item_id; ?>">
    <?php _e( 'Multiple Content' ); ?><br />
    <select name="menu-item-content-multiple[<?php echo $item_id; ?>][]" id="edit-menu-item-content-multiple-<?php echo $item_id; ?>" class="widefat code edit-menu-item-content-multiple" multiple="multiple">
            <?php foreach ($select_options as $key => $value): ?>
                <option value="<?php echo $key; ?>"  <?php echo selected(in_array($key, $item->content_multiple)); ?>><?php echo $value;?></option>
            <?php endforeach ?>
    </select>
</label>
</p>

My code is work with the single select box without any problem but when I use in_array() in multiple select cases return this error

Warning: in_array() expects parameter 2 to be array, null given
3
  • The error messages is quite descriptive. What do you don't understand? Please, explain. in_array() requires the second parameter be an array, check the PHP docs. So, you just need to be sure that the second parameter you pass to in_array() is an array. Thats all about the error message. Also, note that this question, as iti is, is about a generic PHP error, which is out of the scope of this site.
    – cybmeta
    Commented Oct 19, 2016 at 9:50
  • @cybmeta after using your answer code and puting false in get_post_meta now the second parameter $item->content_multiple being array but when i select multiple options only save last option and don't save all selected options Commented Oct 19, 2016 at 12:13
  • Please, leave comments about the answer in the answer, otherwise it can confuse other user.
    – cybmeta
    Commented Oct 19, 2016 at 12:19

2 Answers 2

22

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] ) );
14
  • Thank you must I use false instead of true. But also you used true in get_post_meta !!! Commented Oct 19, 2016 at 10:28
  • As your code is, no, you must use the serialize and unserialize method. In order to use false in get_post_meta() you should also store each value from your select in a separate entry in database, with the same key but multiple times, that is, use update_post_meta() for each value but using always the same key; then you can use false in get_post_meta() to get all of them. I hope you understand what I mean.
    – cybmeta
    Commented Oct 19, 2016 at 10:50
  • I've updated the answer with, I hope, a better explanation.
    – cybmeta
    Commented Oct 19, 2016 at 10:59
  • 1
    Thanks your post solved error message, I edited my post added select box custom field as in my file. But the problem is that when I select multiple options after save setting only save the last option and not save all selected options why? is any error in using worpress selected(); function ? <?php echo selected(in_array($key, $item->content_multiple)); ?> (i used your second option code) Commented Oct 19, 2016 at 11:57
  • 1
    WordPress serializes/unserializes array data in single meta field automatically (as do the option functions), you should not serialize/unserialize yourself.
    – Milo
    Commented Oct 20, 2016 at 15:10
0

You don't use selected() function correctly. selected() need 1 required parameters and 2 optionals. In your case, it's better to use to $selected and $current.

You miss the underscore before your meta-field name in the select name.

For selected():

selected( $selected, $current, $echo);

you can read more about this from the codex function reference selected()

Your select must be like this:

<select name="_menu-item-content-multiple[]" multiple>
     <?php 
        foreach ($select_options as $key => $value) {
            echo '<option value="'.$key.'" '.selected(in_array($key, $item->content_multiple), $key).'>'.$value.'</option>';
        }
     ?>
</select>
6
  • I used your code but also show the error, I think the error in $item->content_multiple it must be saved as array because the $item->content_multiple also save one value and not save more than one value as array Commented Oct 19, 2016 at 9:20
  • Ok, verify that your meta-field name is always the same, it is currently not. If you want it to be with an underscore prefix, always use this underscore, and name your select with underscore or with dash. update_post_meta work but no value will be save.
    – Benoti
    Commented Oct 19, 2016 at 9:26
  • I added more than 10 fields as above field all works without any problem I say the error in $item->content_multiple because this field also save the single value and not save more than one value in the same time because it is not updated as the array. before foreach loop when i put $item->content_multiple = array(); it is work and don't show me any error but don't save values Commented Oct 19, 2016 at 9:38
  • Don't really sure, but verify $item type, is it an object or an array ? ok the content in it is an array, but try to convert it into an array for the in_array function, before the foreach loop (array)$item and in the selected() use it as an array like this : $item['content_multiple']
    – Benoti
    Commented Oct 19, 2016 at 9:50
  • $item it is an object not an array() Commented Oct 19, 2016 at 12:01

Your Answer

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

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