0

I have more than 3000 users with role 'subscriber', and now i want to fetch all users with role 'subscriber'.

$user_query = new WP_User_Query( array( 'role' => 'Subscriber' ) );
$users = $user_query->get_results();

foreach( $users as $user)
{
     // getting user data
}

Now when i tried with above code, then my page is not working, it gives me 500 HTTP ERROR saying that "unable to handle request" So what i need to change in my code so that it gives me all users at once.

But when i tried with below code, then it works very well.

$user_query = new WP_User_Query( array( 'role' => 'Subscriber','number' => 200 ) );

but everytime it will return first 20 user with 'subscriber' role.

Thanks in advance

  • Look into your log file if there are any messages about this error. If there are, please show them to us. You can find your log file at wp-content/debug.log If the file is emtpy or doesn't exist, check if WP_DEBUG and WP_DEBUG_LOG are set to true in your wp-config.php. – ahendwh2 Sep 27 '17 at 11:39
  • You're probably running out of memory. – Milo Sep 27 '17 at 12:59
  • Do you have anything in your error log from when this runs? How do you know it only fetched 20? Do you do a count of how many users were processed and save that? Or do you look at the user query results and count the returned number? Are you sure you're not fetching 3000 but only have time to process 20? – Tom J Nowell Sep 28 '17 at 12:27
1

The problem here is that this query has pagination by default, and what you're asking for is not scalable.

For example, this query fetches 5 posts at a time, and displays the 6th page of users:

$user_query = new WP_User_Query( array(
    'number' => 5,
    'offset' => 25
) );

You can pass -1 to fetch unlimited users, but this will lead to other problems.

There is also the paged parameter which you can use instead of offset to save some calculation

Why You Should Never Ask For All The Posts Users

Displaying 3000 users at once is going to be an expensive operation, both to fetch the data, and to display it. This is the kind of operation that should be done in WP CLI, and should be done in steps rather than all at once

It'll be much more efficient to fetch 100 users 30 times than to fetch 3000 users once. Similarly, pagination was added for a reason, I strongly recommend you use it

You can have as many users as you want, just don't try to display them all at the same time, be reasonable. The same goes for comments, pages, posts, and anything else that there's 3000 of. A good number is 50 as a max. Always set a maximum, even if it's a silly high maximum you never expect to hit, and always opt for pagination or incremental loading when possible

Other factors include running out of available memory, the query taking too long and running into the max execution time, or lots of people visiting that page at the same time.

You're Double Querying

This is a standard user query:

$args = array( ... );
// The Query
$user_query = new WP_User_Query( $args );

// User Loop
if ( ! empty( $user_query->results ) ) {
    foreach ( $user_query->results as $user ) {
        echo '<p>' . $user->display_name . '</p>';
    }
} else {
    echo 'No users found.';
}

Notice that as soon as you create the $user_query object it runs the query. But your code then calls $users = $user_query->get_results();, making it go back to the database, and fetch the result a second time. You don't need to call get_results

Memory and Time Limits

As indicated, this is being ran on WP Cron, but this leads to a problem. Nowhere do you actually test that 20 users or 3000 are returned in a reliable way.

For example, it may be returning all the users you expected, but you only have time to process 20 before the time limit hits, so it only appears as if 20 were returned. Similarly, Processing each user may take too long, and 20 is all you have time for.

To find this out, use the $user_query->get_total() method and store it somewhere.

https://developer.wordpress.org/reference/classes/wp_user_query/get_total/

I would recommend switching to a WP CLI command ran by a real cron job so that time limits no longer apply, as well as only processing 50 at a time to avoid memory limits, and having an incremental process rather than doing them all at once.

  • The Efficient part is not on point. It hides a lot of information to be considered as a valid point. For example, you can choose to retrieve 3000 entries and after that, you can choose to display it as a chank or directly. From Db and Network point of view, it is far better to retrieve this small number than making multiple requests. – Drupalizeme Sep 27 '17 at 12:30
  • The displaying part is more to do with WP making subsequent requests for things like user meta as the page gets rendered to HTML. Displaying 3k of anything at a time should be possible if you're the only visitor to the site and the sole occupant of the server, but if you want things to be fast, limit how much you're showing, and be smarter about it. – Tom J Nowell Sep 27 '17 at 12:46
  • As for the network, yeah sending all 3k at once is more efficient, but the difference is negligible, micro-optimising, it's the heavy lifting fetching those 3k that's costlier and the latency involved. Sure you might do a little more work fetching them bit by bit, but the users waiting at the other end. It's faster and more scalable to have smaller faster queries than a single larger query – Tom J Nowell Sep 27 '17 at 12:47
  • Under certain criteria can be different outcomes and this is my point. Telling something is not efficient can be misleading and for that was my comment not to start what and when. Also, my comment was targeted the DB and Network were because at the display part you can choose something like lazy rendering and not actual waiting to the Browser to render everything. – Drupalizeme Sep 27 '17 at 12:59
  • Actually my concept is, i have to set cron which will execute weekly every monday morning and will send email to users whose role is 'subscriber'. Now in-order to do so, i have to fetch users with 'subscriber' role. Now as you told that, i have to use parameter like 'number' and 'offset', then also it doesn't work for me. Moreover i had also used "-1" as paged parameter, but then also it is not working for me – Vishal Tanna Sep 28 '17 at 4:46
0

This will return and loop though all of your subscribers.

$users = get_users( array(
    'role' => 'subscriber',
) );

if ( ! empty( $users ) ) {
    foreach( $users as $user ) {
        // getting user data
    }
}

https://codex.wordpress.org/Function_Reference/get_users

  • I'm sorry to say but this also don't work for me. It gives me HTTP 500 Error – Vishal Tanna Sep 27 '17 at 11:32
  • Have you enabled WP_DEBUG in your config file? If so, could you share the errors it logs? Also have you tried adding offset to your query, since you're trying to get a large amount of data? – Kuliraj Sep 27 '17 at 11:41
  • This uses WP_User_Query internally – Tom J Nowell Sep 27 '17 at 12:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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