WP_User_Query order by meta_key that is an array

I have set a user metadata named achievements which is an array containing various numeric values. Using WP_User_Query, I want to order the list by a specific key within this array named points.

The following:

$args = array(
    'order' => 'DESC',
    'orderby' => 'meta_value_num',
    'meta_key' => 'achievements',
    'number' => $no,
    'offset' => $offset
);

…works if achievements would be a numeric value. How do I alter the $args array to target the key points within the metadata key achievements.

Running a print_r() of achievements for a user returns:

Array ( [x1] => 74 [x2] => 383 [x3] => 457 [x4] => 81 [points] => 301 [x5] => 382 [x6] => 12 )

2 Answers
2

You could save the values with the separate user meta keys:

x1, ..., x6, points

instead of the array:

achievements

to simplify your WP_User_Query() usage and not having to deal with serialized arrays as user meta values.

But I guess you’ve already considered this setup and wanted to avoid it 😉

A compromise would be to move only the points out of the achievements array into a separate meta key.

Update:

When the number of users is relatively small, we can use the following (untested) PHP sorting:

$users2points = array();

$args = array(
    'meta_key' => 'achievements',
    'number'   => $no,
    'offset'   => $offset
);

$users = get_users( $args );

foreach( (array) $users as $user )
{
    $meta = get_user_meta( 'achievements', $user->ID );
    if( isset( $meta['points'] )
        $users2points[$user->ID] = $meta['points'];
}

asort( $users2points, SORT_NUMERIC );

print_r( $users2points );

Update 2:

Here’s another more adventures PHP sorting that will work directly on the $users array of WP_User objects:

$args = array(
    'meta_key' => 'achievements',
    'number'   => $no,
    'offset'   => $offset
);

$users = get_users( $args );

foreach( (array) $users as $user )
{
    $meta = get_user_meta( 'achievements', $user->ID );

    // Here we assume the points values are greater or equal to 0:
    $user->points = ( isset( $meta['points'] ) ?  $meta['points'] : 0;
}

/*
usort( $users, function( $a, $b ) {
    return gmp_cmp( $a->points, $b->points );
});
*/

// The gmp_cmp() might suffer from a memory leak,
// according to some PHP bug reports,
// so let's use this instead:    

usort( $users, function( $a, $b ) {
    if( $a->points === $b->points )
        return 0;
    else
        return ( $a->points > $b->points ) ? 1 : -1;
});


print_r( $users );

Leave a Comment