I have a situation here. I'm writing a custom plugin for WordPress. I'm dealing with an issue:

I'v created a metabox for Custom Post Type with add_meta_box and with a callback function where I generate a multiselect box. All users showing up with a user ID. The point is: The Custom Post Type is a group and this group can have multiple members (users). The first thing what I tried was saving all the users, which are subscribed to this group, in one single row in the postmeta table but that's not a good solution.

What I want to do now is: Create a new row, for every single user, in the usermeta table with this key _enroll_user_value_key.

My field: echo '<select multiple name="enroll_user_field[]" id="enroll_user_field">'; this values, I want to pass this, for each single selected user, to a new database row in user_meta. Now I use only this function to save this data: update_user_meta( $enroll_user_data, '_enroll_user_value_key', $post->ID ); But when I select multiple users the row doesn't update or created because there a multiple values passed from the field enroll_user_field[].

How could I fix this? Should I create a foreach loop and repeat the update_user_meta every single time, for each selected user? And what if I remove a user from the group, should I use a seperate delete function or query for this?


    'Group members',

function group_members_callback( $post ){
    wp_nonce_field( 'group_members_save', 'group_members_nonce' );
    $values = get_post_meta($post->ID, '_group_members_value_key', true);
    $values = explode(',', $values);
    echo '<label for="group_members_field">Assign users to this group. If you want to assign multiple users to this module, hold CTRL while you are selecting</label><br /><br />';
    echo '<select multiple name="group_members_field[]" id="group_members_field">';
        $users = get_users();
        foreach( $users as $user ){
            if( in_array($user->ID, $values )){
                echo '<option selected value="' . $user->ID . '">' . esc_attr( $user->user_email ) . '</option>';
                echo '<option value="' . $user->ID . '">' . esc_attr( $user->user_email ) . '</option>';
    echo '</select>';

function group_members_save( $post_id ){
    if( ! isset( $_POST['group_members_nonce'] ) ){
    if( ! wp_verify_nonce( $_POST['group_members_nonce'], 'group_members_save') ){
    if( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ){
    if( ! current_user_can('edit_post', $post_id ) ){
    if( ! isset($_POST['group_members_field'] ) ){
    $group_members_data = sanitize_text_field( implode(',', $_POST['group_members_field'] ) );
    update_post_meta( $post_id, '_group_members_value_key', $group_members_data );

add_action('save_post', 'group_members_save');

This line update_post_meta( $post_id, '_group_members_value_key', $group_members_data ); should be update_user_meta, because I want to save it in the usermeta table, in seperated rows.

  • Examples of your code would be really useful to help, but yes, it sounds like you need to loop through the array of user ID's that you want to add to a group and add a new row for each userId+group pair.
    – mozboz
    Jun 29, 2020 at 10:28
  • Thanks for your comment. See my first post. Jun 29, 2020 at 10:38
  • Is it correct that one user could be in many groups, and one group will have many members in it? (This is a 'many to many' relationship)
    – mozboz
    Jun 29, 2020 at 13:36
  • Yes, correct! Is it possible to build this or should I try a different method? What is your advice? Jun 29, 2020 at 14:33
  • It is more complicated but if you care about how the data is structured it may be worth creating your own database table for your plugin. This is more work, but it will give you more control over the data. You could also carry on how you are with putting comma-delimited lists in post_meta. It makes it harder to query the data, but that might be ok, it depends what you want to do with the group-member ID's
    – mozboz
    Jun 29, 2020 at 14:48

1 Answer 1


So the problem with either post meta or user meta is that if your key is e.g. _group_members_value_key you only have one item of data per user or per post in which to store the data, and you need many items for each user and many items for each post. This is two columns of data, but in the meta tables you only have one.

Let's say you have this data:

User ID | Group Id
1 | 10
1 | 20 
1 | 30
2 | 10
2 | 40
3 | 30

To put this in e.g. usermeta for user 1 you have these choices:

user id | meta_key | value
1 | "_group_members_value_key" | "10,20,30"


user id | meta_key | value
1 | "_group_members_value_key_10" | "yes"
1 | "_group_members_value_key_10" | "yes"
1 | "_group_members_value_key_10" | "yes"

Note in the second case you have to put the group ID as part of the key.

So perhaps this second solution works for you - just add the group id to the key and use some extra logic like:

To put a user in a group:

update_user_meta($userId, "_group_members_value_key_" . $groupId, "yes")

To remove a user from a group:

update_user_meta($userId, "_group_members_value_key_" . $groupId, "no")

To check if a user is in a group:

if (get_user_meta($userId, "_group_members_value_key_" . $groupId) == "yes") {

Find all the users in a group:

$user_query = new WP_User_Query( array( 'meta_key' => "_group_members_value_key_" . $groupId, 'meta_value' => 'yes' ) );

I'm not sure if this works for what you want to do though. Let me know. These are code examples so you may have to edit them a bit for exactly what you need but this data structure should work for what you need.

It looks like $_POST['group_members_field'] will be an array, so if for example it was post ID's you need to do something like:

foreach($_POST['group_members_field'] as $postId) {
    update_user_meta($someUserId, '_group_members_value_key'.$postId, "yes");
  • Thanks for your answer. I will take a look to your second suggestion. Maybe I could remove the row when a user is not enrolled anymore instead of change it to: 'no'? It's less data in the table, or doesn't matter? Jun 29, 2020 at 19:57
  • yeah that's a good option too, I was just lazy with the way I wrote it so I didn't have to look up what the command to remove the row was ;-) probably a better option!
    – mozboz
    Jun 29, 2020 at 20:13
  • Great, thanks for your help! What is the best way to insert the data from a multiselect field to the database? How can I loop through each value I got back from this selectfield: name="enroll_user_field[]"? Any suggestions or do you have an example for me? Jun 29, 2020 at 20:24
  • see addition on end for how to look through an array - you'll need to adjust the example for how you're using user/posts though
    – mozboz
    Jun 29, 2020 at 20:32

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.