WordPress.org

Make WordPress Core

Opened 16 months ago

Last modified 3 months ago

#22921 new enhancement

Allow get_users() to return array of values via 'fields' parameter

Reported by: chipbennett Owned by:
Milestone: Future Release Priority: normal
Severity: normal Version: 3.5
Component: Users Keywords: has-patch needs-testing
Focuses: Cc:

Description

Currently, the 'fields' parameter in the arguments array for get_users() only accepts either an array of user data fields, or the string 'all'. Both of these options cause get_users() to return an array of object comprised of the specified user data. Passing any other string value to 'fields' causes get_users() to return an array of user IDs.

Per the Codex:

Array of objects, except when fields specifies a single field to be returned, then an array of values is returned. If fields is set to all_with_meta, it will return an array of WP_User objects.

This statement appears to be untrue, but would be incredibly useful if it were true.

Patch adds this functionality to get_users().

Potentially related: #18581

Attachments (1)

user.php.diff (652 bytes) - added by chipbennett 16 months ago.

Download all attachments as: .zip

Change History (14)

chipbennett16 months ago

comment:1 scribu16 months ago

Example usage?

comment:2 chipbennett16 months ago

Return an array of user email addresses, such as:

$user_emails = get_users( array( 'fields' => 'user_email' ) );

This usage eliminates the step of looping through the array of objects otherwise returned, to pluck out the email addresses.

comment:3 DavidAnderson16 months ago

-1 from me.

I also had to waste some time when dealing with this function, and the difference between Codex and the actual behaviour.

However, once I worked the actual behaviour out, I wrote my code to deal with that reality. If you change the behaviour, you'll break lots of existing code, and people will be confused/annoyed when their sites break and they have to re-write. Better solution is to change Codex to describe the current real behaviour.

comment:4 follow-up: dd3216 months ago

If you change the behaviour, you'll break lots of existing code

If you take a look at the patch, the only code that will break, are those passing the fields parameter as one of the following, and expecting back a list of user_id's, a broken assumption and code to start with..
array( 'ID', 'user_login', 'user_pass', 'user_nicename', 'user_email', 'user_url', 'user_registered', 'user_activation_key', 'user_status', 'display_name' )

Last edited 16 months ago by dd32 (previous) (diff)

comment:5 in reply to: ↑ 4 ; follow-up: DavidAnderson16 months ago

dd32: Yes, that's right - it'll break code that uses the existing function. I've written such code. The existing function does something useful, and works whilst doing it, and people are using it. There's a real-world cost to breaking that.

comment:6 in reply to: ↑ 5 ; follow-up: chipbennett16 months ago

Replying to DavidAnderson:

dd32: Yes, that's right - it'll break code that uses the existing function. I've written such code. The existing function does something useful, and works whilst doing it, and people are using it. There's a real-world cost to breaking that.

Let's consider the purpose of the 'fields' array parameter: to return only the fields specified, instead of all user data. The code provides two forms of output, based on the type of input:

  1. An array of objects comprised of one or more values, if 'fields' => array( $fields ) is passed
  2. An array of values, if 'fields' => $field is passed

Thus, the only way this patch would break existing code is if someone passed a field other than 'ID' for 'fields', e.g.:

$user_IDs = get_users( array( 'fields' => 'user_email' ) );

...and then used the output as if an array of IDs was the expected return value.

That just doesn't make logical sense. Why would someone pass 'user_email' as the value for 'fields', and then subsequently use the output as if 'ID' had been passed?

Any normal developer would look at that output and do one of two things:

  1. Change the function call to 'fields' => 'ID', if the desired return value is 'ID'
  2. Change the function call to pass 'fields' => array( 'user_email' ) if the desired return value is 'user_email'

I contend that if a developer leaves the code as-is, the user code is at fault, and such a use case shouldn't be something that keeps the core function itself from being improved.

comment:7 in reply to: ↑ 6 ; follow-up: DavidAnderson16 months ago

Aah - gotcha. Sorry, I was confusing myself before. You are completely right ...

... up to a point (unless I'm still confused!).

What you desire can already be done, using this syntax (which I use in the "Use Admin Password" plugin):

$desired_fields = get_users("fields[]=email");

So I think we just need to change Codex to give an accurate description, rather than re-add the same feature?

Last edited 16 months ago by DavidAnderson (previous) (diff)

comment:8 in reply to: ↑ 7 ; follow-ups: chipbennett16 months ago

Replying to DavidAnderson:

Aah - gotcha. Sorry, I was confusing myself before. You are completely right ...

... up to a point (unless I'm still confused!).

What you desire can already be done, using this syntax (which I use in the "Use Admin Password" plugin):

$desired_fields = get_users("fields[]=email");

So I think we just need to change Codex to give an accurate description, rather than re-add the same feature?

Is that any different than:

$desired_fields = get_users( array( 'fields' => array( 'user_email' ) ) );

If so, then that still doesn't return the desired output. That returns an array of objects, each of which contains one entity, 'user_email'.

So, when 'ID' is passed as the single field, the output is an array of user IDs; but if any other field is passed as the single field, an array of objects is returned, since the only possible way to pass a single field other than ID is by passing 'fields' as an array.

So, user IDs can be returned as a simple array, like so:

$user_IDs = get_users( array( 'fields' => 'ID' ) );

$user IDs = array(
    [0] => '1',
    [1] => '2',
    [2] => '3'
);

But to get a single-field value for any other field, you can only get an array of objects:

$user_emails = get_users( array( 'fields' => array( 'user_email' ) ) );

$user_emails = array(
    [0] => object( 'user_email' => 'email@...' ),
    [1] => object( 'user_email' => 'email@...' ),
    [2] => object( 'user_email' => 'email@...' )
);

The purpose of this ticket is to allow for consistent return for single-field values for fields other than 'ID'; e.g. so that the following return is possible:

$user_IDs = get_users( array( 'fields' => 'email' ) );

$user IDs = array(
    [0] => 'email@...',
    [1] => 'email@...',
    [2] => 'email@...'
);

Currently this return is not possible, requiring a wasteful, second step to loop through the array of objects to pluck the field values.

comment:9 in reply to: ↑ 8 DavidAnderson16 months ago

OK... but I'm still missing something... the original bug report spoke of adding something "incredibly useful"... but the difference is just that you can get back an array of strings instead of an array of objects (with each object containing the string as a property)? I feel entirely indifferent to that change and leave it to others better qualified to judge on what would be usual WP practice on such things.

comment:10 nacin16 months ago

  • Milestone changed from Awaiting Review to 3.6

3.6 for review.

comment:11 ryan11 months ago

  • Milestone changed from 3.6 to Future Release

comment:12 in reply to: ↑ 8 akforsyt5 months ago

Replying to chipbennett:

Replying to DavidAnderson:

Aah - gotcha. Sorry, I was confusing myself before. You are completely right ...

... up to a point (unless I'm still confused!).

What you desire can already be done, using this syntax (which I use in the "Use Admin Password" plugin):

$desired_fields = get_users("fields[]=email");

So I think we just need to change Codex to give an accurate description, rather than re-add the same feature?

Is that any different than:

$desired_fields = get_users( array( 'fields' => array( 'user_email' ) ) );

If so, then that still doesn't return the desired output. That returns an array of objects, each of which contains one entity, 'user_email'.

So, when 'ID' is passed as the single field, the output is an array of user IDs; but if any other field is passed as the single field, an array of objects is returned, since the only possible way to pass a single field other than ID is by passing 'fields' as an array.

So, user IDs can be returned as a simple array, like so:

$user_IDs = get_users( array( 'fields' => 'ID' ) );

$user IDs = array(
    [0] => '1',
    [1] => '2',
    [2] => '3'
);

But to get a single-field value for any other field, you can only get an array of objects:

$user_emails = get_users( array( 'fields' => array( 'user_email' ) ) );

$user_emails = array(
    [0] => object( 'user_email' => 'email@...' ),
    [1] => object( 'user_email' => 'email@...' ),
    [2] => object( 'user_email' => 'email@...' )
);

The purpose of this ticket is to allow for consistent return for single-field values for fields other than 'ID'; e.g. so that the following return is possible:

$user_IDs = get_users( array( 'fields' => 'email' ) );

$user IDs = array(
    [0] => 'email@...',
    [1] => 'email@...',
    [2] => 'email@...'
);

Currently this return is not possible, requiring a wasteful, second step to loop through the array of objects to pluck the field values.

Thank you for providing this fix. This was driving me crazy as the codex says it returns an array of values, but this is simply not true for any field except for user id. There is not much discussion on this, although I do agree, it is very useful.

comment:13 mbcreation3 months ago

Any update on this. (since the Codex is still wrong) ?
Thanks.

Note: See TracTickets for help on using tickets.