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.