WP_User_Query and non-unique usermeta data

We have an issue with a WP plugin that we wrote and maintain – Export User Data

A user has reported an issue that non-unique user meta data records are not being returned correctly – here

In the plugin, we export the usermeta data selected by the user – using get_users() which in turn uses WP_User_Query:

We pass a few simple arguments to get_users:

// build argument array ##
$args = array(
      'fields'    => 'all',
      'role'      => sanitize_text_field( $_POST['role'] )
);

If we inspect a WP_User object returned, the usermeta fields are not returned – for example ( object data reduced to save space ):

Array
(
[0] => WP_User Object
    (
        [data] => stdClass Object
            (
                [ID] => 1267
                [user_login] => [email protected]
                ...
            )

        [ID] => 1267
        ...
    )

[1]...

We have tried to change the get_users args for the “fields” parameter from “all” to “all_with_meta”, however this does not seem to change the originally returned data.

At the point at which we export these user metadata rows we firstly loop over that array of WP_User objects and then echo out the individual usermeta field data ( $field comes from an array of $fields which loops outside the $users loop ):

// build row values for each user ##
foreach ( $users as $user ) {

    // grab value from $user object ##
    $value = $user->{$field};

}

The field data is being magically added to the $user object, even though this is not shown in the originally returned object data – however, we have no control over if it returns a single or array of values for each usermeta field.

As the data is being returned automatically, we are not controlling the selected method, which we would be able to if we used get_user_meta directly ( but we’d still have the issue of not knowing the stored data is unique or not, without running extra queries – which would be costly on large exports ).

I’m writing this all out to try and explain to others the issue, while also to help us look for answers and resolve this issue.

Update

We’ve pushed a test fix to github using a method to check for non-unique usermeta keys and return an array in the case that there are more than one matching keys

1
1

The solution that we have gone with in the end uses a single call to get_user_meta passing just the $user_id – this way all user data is returned in a single query, reducing a heavy load on the DB during large user data exports.

We then run a series of checks against the returned data – including:

  • is_serialized( $value ) – to check if the data has been returned in a serialized form ( we then attempt to unserialize it – in some cases this fails where data has been stored in an incorrect form ).
  • is_array( $value ) – to check if the returned data is in fact an array

If we find that the data is returned in an array we recursively implode the array until we have a string of data to return to the export file.

I have not included specific code in this answer, but rather linked to the hosted github files ( I know this is not ideal for the future, but the parts that relate to this answer are spread out in the code ).

The exports run cleanly and do not choke-up – we’ll release the updated plugin next week.

Leave a Comment