0
|
1 |
<?php |
|
2 |
/** |
|
3 |
* WordPress User API |
|
4 |
* |
|
5 |
* @package WordPress |
5
|
6 |
* @subpackage Users |
0
|
7 |
*/ |
|
8 |
|
|
9 |
/** |
|
10 |
* Authenticate user with remember capability. |
|
11 |
* |
|
12 |
* The credentials is an array that has 'user_login', 'user_password', and |
|
13 |
* 'remember' indices. If the credentials is not given, then the log in form |
|
14 |
* will be assumed and used if set. |
|
15 |
* |
|
16 |
* The various authentication cookies will be set by this function and will be |
|
17 |
* set for a longer period depending on if the 'remember' credential is set to |
|
18 |
* true. |
|
19 |
* |
|
20 |
* @since 2.5.0 |
|
21 |
* |
5
|
22 |
* @param array $credentials Optional. User info in order to sign on. |
|
23 |
* @param string|bool $secure_cookie Optional. Whether to use secure cookie. |
|
24 |
* @return WP_User|WP_Error WP_User on success, WP_Error on failure. |
0
|
25 |
*/ |
5
|
26 |
function wp_signon( $credentials = array(), $secure_cookie = '' ) { |
0
|
27 |
if ( empty($credentials) ) { |
|
28 |
if ( ! empty($_POST['log']) ) |
|
29 |
$credentials['user_login'] = $_POST['log']; |
|
30 |
if ( ! empty($_POST['pwd']) ) |
|
31 |
$credentials['user_password'] = $_POST['pwd']; |
|
32 |
if ( ! empty($_POST['rememberme']) ) |
|
33 |
$credentials['remember'] = $_POST['rememberme']; |
|
34 |
} |
|
35 |
|
|
36 |
if ( !empty($credentials['remember']) ) |
|
37 |
$credentials['remember'] = true; |
|
38 |
else |
|
39 |
$credentials['remember'] = false; |
|
40 |
|
5
|
41 |
/** |
|
42 |
* Fires before the user is authenticated. |
|
43 |
* |
|
44 |
* The variables passed to the callbacks are passed by reference, |
|
45 |
* and can be modified by callback functions. |
|
46 |
* |
|
47 |
* @since 1.5.1 |
|
48 |
* |
|
49 |
* @todo Decide whether to deprecate the wp_authenticate action. |
|
50 |
* |
|
51 |
* @param string $user_login Username, passed by reference. |
|
52 |
* @param string $user_password User password, passed by reference. |
|
53 |
*/ |
|
54 |
do_action_ref_array( 'wp_authenticate', array( &$credentials['user_login'], &$credentials['user_password'] ) ); |
0
|
55 |
|
|
56 |
if ( '' === $secure_cookie ) |
|
57 |
$secure_cookie = is_ssl(); |
|
58 |
|
5
|
59 |
/** |
|
60 |
* Filter whether to use a secure sign-on cookie. |
|
61 |
* |
|
62 |
* @since 3.1.0 |
|
63 |
* |
|
64 |
* @param bool $secure_cookie Whether to use a secure sign-on cookie. |
|
65 |
* @param array $credentials { |
|
66 |
* Array of entered sign-on data. |
|
67 |
* |
|
68 |
* @type string $user_login Username. |
|
69 |
* @type string $user_password Password entered. |
|
70 |
* @type bool $remember Whether to 'remember' the user. Increases the time |
|
71 |
* that the cookie will be kept. Default false. |
|
72 |
* } |
|
73 |
*/ |
|
74 |
$secure_cookie = apply_filters( 'secure_signon_cookie', $secure_cookie, $credentials ); |
0
|
75 |
|
|
76 |
global $auth_secure_cookie; // XXX ugly hack to pass this to wp_authenticate_cookie |
|
77 |
$auth_secure_cookie = $secure_cookie; |
|
78 |
|
|
79 |
add_filter('authenticate', 'wp_authenticate_cookie', 30, 3); |
|
80 |
|
|
81 |
$user = wp_authenticate($credentials['user_login'], $credentials['user_password']); |
|
82 |
|
|
83 |
if ( is_wp_error($user) ) { |
|
84 |
if ( $user->get_error_codes() == array('empty_username', 'empty_password') ) { |
|
85 |
$user = new WP_Error('', ''); |
|
86 |
} |
|
87 |
|
|
88 |
return $user; |
|
89 |
} |
|
90 |
|
|
91 |
wp_set_auth_cookie($user->ID, $credentials['remember'], $secure_cookie); |
5
|
92 |
/** |
|
93 |
* Fires after the user has successfully logged in. |
|
94 |
* |
|
95 |
* @since 1.5.0 |
|
96 |
* |
|
97 |
* @param string $user_login Username. |
|
98 |
* @param WP_User $user WP_User object of the logged-in user. |
|
99 |
*/ |
|
100 |
do_action( 'wp_login', $user->user_login, $user ); |
0
|
101 |
return $user; |
|
102 |
} |
|
103 |
|
|
104 |
/** |
|
105 |
* Authenticate the user using the username and password. |
5
|
106 |
* |
|
107 |
* @since 2.8.0 |
|
108 |
* |
|
109 |
* @param WP_User|WP_Error|null $user WP_User or WP_Error object from a previous callback. Default null. |
|
110 |
* @param string $username Username for authentication. |
|
111 |
* @param string $password Password for authentication. |
|
112 |
* @return WP_User|WP_Error WP_User on success, WP_Error on failure. |
0
|
113 |
*/ |
|
114 |
function wp_authenticate_username_password($user, $username, $password) { |
5
|
115 |
if ( $user instanceof WP_User ) { |
|
116 |
return $user; |
|
117 |
} |
0
|
118 |
|
|
119 |
if ( empty($username) || empty($password) ) { |
|
120 |
if ( is_wp_error( $user ) ) |
|
121 |
return $user; |
|
122 |
|
|
123 |
$error = new WP_Error(); |
|
124 |
|
|
125 |
if ( empty($username) ) |
|
126 |
$error->add('empty_username', __('<strong>ERROR</strong>: The username field is empty.')); |
|
127 |
|
|
128 |
if ( empty($password) ) |
|
129 |
$error->add('empty_password', __('<strong>ERROR</strong>: The password field is empty.')); |
|
130 |
|
|
131 |
return $error; |
|
132 |
} |
|
133 |
|
|
134 |
$user = get_user_by('login', $username); |
|
135 |
|
|
136 |
if ( !$user ) |
5
|
137 |
return new WP_Error( 'invalid_username', sprintf( __( '<strong>ERROR</strong>: Invalid username. <a href="%s">Lost your password?</a>' ), wp_lostpassword_url() ) ); |
0
|
138 |
|
5
|
139 |
/** |
|
140 |
* Filter whether the given user can be authenticated with the provided $password. |
|
141 |
* |
|
142 |
* @since 2.5.0 |
|
143 |
* |
|
144 |
* @param WP_User|WP_Error $user WP_User or WP_Error object if a previous |
|
145 |
* callback failed authentication. |
|
146 |
* @param string $password Password to check against the user. |
|
147 |
*/ |
|
148 |
$user = apply_filters( 'wp_authenticate_user', $user, $password ); |
0
|
149 |
if ( is_wp_error($user) ) |
|
150 |
return $user; |
|
151 |
|
|
152 |
if ( !wp_check_password($password, $user->user_pass, $user->ID) ) |
5
|
153 |
return new WP_Error( 'incorrect_password', sprintf( __( '<strong>ERROR</strong>: The password you entered for the username <strong>%1$s</strong> is incorrect. <a href="%2$s">Lost your password?</a>' ), |
0
|
154 |
$username, wp_lostpassword_url() ) ); |
|
155 |
|
|
156 |
return $user; |
|
157 |
} |
|
158 |
|
|
159 |
/** |
|
160 |
* Authenticate the user using the WordPress auth cookie. |
5
|
161 |
* |
|
162 |
* @since 2.8.0 |
|
163 |
* |
|
164 |
* @param WP_User|WP_Error|null $user WP_User or WP_Error object from a previous callback. Default null. |
|
165 |
* @param string $username Username. If not empty, cancels the cookie authentication. |
|
166 |
* @param string $password Password. If not empty, cancels the cookie authentication. |
|
167 |
* @return WP_User|WP_Error WP_User on success, WP_Error on failure. |
0
|
168 |
*/ |
|
169 |
function wp_authenticate_cookie($user, $username, $password) { |
5
|
170 |
if ( $user instanceof WP_User ) { |
|
171 |
return $user; |
|
172 |
} |
0
|
173 |
|
|
174 |
if ( empty($username) && empty($password) ) { |
|
175 |
$user_id = wp_validate_auth_cookie(); |
|
176 |
if ( $user_id ) |
|
177 |
return new WP_User($user_id); |
|
178 |
|
|
179 |
global $auth_secure_cookie; |
|
180 |
|
|
181 |
if ( $auth_secure_cookie ) |
|
182 |
$auth_cookie = SECURE_AUTH_COOKIE; |
|
183 |
else |
|
184 |
$auth_cookie = AUTH_COOKIE; |
|
185 |
|
|
186 |
if ( !empty($_COOKIE[$auth_cookie]) ) |
|
187 |
return new WP_Error('expired_session', __('Please log in again.')); |
|
188 |
|
|
189 |
// If the cookie is not set, be silent. |
|
190 |
} |
|
191 |
|
|
192 |
return $user; |
|
193 |
} |
|
194 |
|
|
195 |
/** |
5
|
196 |
* For Multisite blogs, check if the authenticated user has been marked as a |
0
|
197 |
* spammer, or if the user's primary blog has been marked as spam. |
|
198 |
* |
|
199 |
* @since 3.7.0 |
5
|
200 |
* |
|
201 |
* @param WP_User|WP_Error|null $user WP_User or WP_Error object from a previous callback. Default null. |
|
202 |
* @return WP_User|WP_Error WP_User on success, WP_Error if the user is considered a spammer. |
0
|
203 |
*/ |
|
204 |
function wp_authenticate_spam_check( $user ) { |
5
|
205 |
if ( $user instanceof WP_User && is_multisite() ) { |
|
206 |
/** |
|
207 |
* Filter whether the user has been marked as a spammer. |
|
208 |
* |
|
209 |
* @since 3.7.0 |
|
210 |
* |
|
211 |
* @param bool $spammed Whether the user is considered a spammer. |
|
212 |
* @param WP_User $user User to check against. |
|
213 |
*/ |
0
|
214 |
$spammed = apply_filters( 'check_is_user_spammed', is_user_spammy(), $user ); |
|
215 |
|
|
216 |
if ( $spammed ) |
|
217 |
return new WP_Error( 'spammer_account', __( '<strong>ERROR</strong>: Your account has been marked as a spammer.' ) ); |
|
218 |
} |
|
219 |
return $user; |
|
220 |
} |
|
221 |
|
|
222 |
/** |
5
|
223 |
* Validate the logged-in cookie. |
|
224 |
* |
|
225 |
* Checks the logged-in cookie if the previous auth cookie could not be |
|
226 |
* validated and parsed. |
|
227 |
* |
|
228 |
* This is a callback for the determine_current_user filter, rather than API. |
|
229 |
* |
|
230 |
* @since 3.9.0 |
|
231 |
* |
|
232 |
* @param int|bool $user_id The user ID (or false) as received from the |
|
233 |
* determine_current_user filter. |
|
234 |
* @return int|bool User ID if validated, false otherwise. If a user ID from |
|
235 |
* an earlier filter callback is received, that value is returned. |
|
236 |
*/ |
|
237 |
function wp_validate_logged_in_cookie( $user_id ) { |
|
238 |
if ( $user_id ) { |
|
239 |
return $user_id; |
|
240 |
} |
|
241 |
|
|
242 |
if ( is_blog_admin() || is_network_admin() || empty( $_COOKIE[LOGGED_IN_COOKIE] ) ) { |
|
243 |
return false; |
|
244 |
} |
|
245 |
|
|
246 |
return wp_validate_auth_cookie( $_COOKIE[LOGGED_IN_COOKIE], 'logged_in' ); |
|
247 |
} |
|
248 |
|
|
249 |
/** |
0
|
250 |
* Number of posts user has written. |
|
251 |
* |
|
252 |
* @since 3.0.0 |
5
|
253 |
* @since 4.1.0 Added `$post_type` argument. |
|
254 |
* |
|
255 |
* @global wpdb $wpdb WordPress database object for queries. |
0
|
256 |
* |
5
|
257 |
* @param int $userid User ID. |
|
258 |
* @param string $post_type Optional. Post type to count the number of posts for. Default 'post'. |
|
259 |
* @return int Number of posts the user has written in this post type. |
0
|
260 |
*/ |
5
|
261 |
function count_user_posts( $userid, $post_type = 'post' ) { |
0
|
262 |
global $wpdb; |
|
263 |
|
5
|
264 |
$where = get_posts_by_author_sql( $post_type, true, $userid ); |
0
|
265 |
|
|
266 |
$count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->posts $where" ); |
|
267 |
|
5
|
268 |
/** |
|
269 |
* Filter the number of posts a user has written. |
|
270 |
* |
|
271 |
* @since 2.7.0 |
|
272 |
* @since 4.1.0 Added `$post_type` argument. |
|
273 |
* |
|
274 |
* @param int $count The user's post count. |
|
275 |
* @param int $userid User ID. |
|
276 |
* @param string $post_type Post type to count the number of posts for. |
|
277 |
*/ |
|
278 |
return apply_filters( 'get_usernumposts', $count, $userid, $post_type ); |
0
|
279 |
} |
|
280 |
|
|
281 |
/** |
|
282 |
* Number of posts written by a list of users. |
|
283 |
* |
|
284 |
* @since 3.0.0 |
|
285 |
* |
|
286 |
* @param array $users Array of user IDs. |
|
287 |
* @param string $post_type Optional. Post type to check. Defaults to post. |
|
288 |
* @param bool $public_only Optional. Only return counts for public posts. Defaults to false. |
|
289 |
* @return array Amount of posts each user has written. |
|
290 |
*/ |
|
291 |
function count_many_users_posts( $users, $post_type = 'post', $public_only = false ) { |
|
292 |
global $wpdb; |
|
293 |
|
|
294 |
$count = array(); |
|
295 |
if ( empty( $users ) || ! is_array( $users ) ) |
|
296 |
return $count; |
|
297 |
|
|
298 |
$userlist = implode( ',', array_map( 'absint', $users ) ); |
|
299 |
$where = get_posts_by_author_sql( $post_type, true, null, $public_only ); |
|
300 |
|
|
301 |
$result = $wpdb->get_results( "SELECT post_author, COUNT(*) FROM $wpdb->posts $where AND post_author IN ($userlist) GROUP BY post_author", ARRAY_N ); |
|
302 |
foreach ( $result as $row ) { |
|
303 |
$count[ $row[0] ] = $row[1]; |
|
304 |
} |
|
305 |
|
|
306 |
foreach ( $users as $id ) { |
|
307 |
if ( ! isset( $count[ $id ] ) ) |
|
308 |
$count[ $id ] = 0; |
|
309 |
} |
|
310 |
|
|
311 |
return $count; |
|
312 |
} |
|
313 |
|
|
314 |
// |
|
315 |
// User option functions |
|
316 |
// |
|
317 |
|
|
318 |
/** |
|
319 |
* Get the current user's ID |
|
320 |
* |
|
321 |
* @since MU |
|
322 |
* |
|
323 |
* @return int The current user's ID |
|
324 |
*/ |
|
325 |
function get_current_user_id() { |
|
326 |
if ( ! function_exists( 'wp_get_current_user' ) ) |
|
327 |
return 0; |
|
328 |
$user = wp_get_current_user(); |
|
329 |
return ( isset( $user->ID ) ? (int) $user->ID : 0 ); |
|
330 |
} |
|
331 |
|
|
332 |
/** |
|
333 |
* Retrieve user option that can be either per Site or per Network. |
|
334 |
* |
|
335 |
* If the user ID is not given, then the current user will be used instead. If |
|
336 |
* the user ID is given, then the user data will be retrieved. The filter for |
|
337 |
* the result, will also pass the original option name and finally the user data |
|
338 |
* object as the third parameter. |
|
339 |
* |
|
340 |
* The option will first check for the per site name and then the per Network name. |
|
341 |
* |
|
342 |
* @since 2.0.0 |
5
|
343 |
* |
|
344 |
* @global wpdb $wpdb WordPress database object for queries. |
0
|
345 |
* |
5
|
346 |
* @param string $option User option name. |
|
347 |
* @param int $user Optional. User ID. |
|
348 |
* @param string $deprecated Use get_option() to check for an option in the options table. |
|
349 |
* @return mixed User option value on success, false on failure. |
0
|
350 |
*/ |
|
351 |
function get_user_option( $option, $user = 0, $deprecated = '' ) { |
|
352 |
global $wpdb; |
|
353 |
|
|
354 |
if ( !empty( $deprecated ) ) |
|
355 |
_deprecated_argument( __FUNCTION__, '3.0' ); |
|
356 |
|
|
357 |
if ( empty( $user ) ) |
|
358 |
$user = get_current_user_id(); |
|
359 |
|
|
360 |
if ( ! $user = get_userdata( $user ) ) |
|
361 |
return false; |
|
362 |
|
|
363 |
$prefix = $wpdb->get_blog_prefix(); |
|
364 |
if ( $user->has_prop( $prefix . $option ) ) // Blog specific |
|
365 |
$result = $user->get( $prefix . $option ); |
|
366 |
elseif ( $user->has_prop( $option ) ) // User specific and cross-blog |
|
367 |
$result = $user->get( $option ); |
|
368 |
else |
|
369 |
$result = false; |
|
370 |
|
5
|
371 |
/** |
|
372 |
* Filter a specific user option value. |
|
373 |
* |
|
374 |
* The dynamic portion of the hook name, `$option`, refers to the user option name. |
|
375 |
* |
|
376 |
* @since 2.5.0 |
|
377 |
* |
|
378 |
* @param mixed $result Value for the user's option. |
|
379 |
* @param string $option Name of the option being retrieved. |
|
380 |
* @param WP_User $user WP_User object of the user whose option is being retrieved. |
|
381 |
*/ |
|
382 |
return apply_filters( "get_user_option_{$option}", $result, $option, $user ); |
0
|
383 |
} |
|
384 |
|
|
385 |
/** |
|
386 |
* Update user option with global blog capability. |
|
387 |
* |
|
388 |
* User options are just like user metadata except that they have support for |
|
389 |
* global blog options. If the 'global' parameter is false, which it is by default |
|
390 |
* it will prepend the WordPress table prefix to the option name. |
|
391 |
* |
|
392 |
* Deletes the user option if $newvalue is empty. |
|
393 |
* |
|
394 |
* @since 2.0.0 |
|
395 |
* |
5
|
396 |
* @global wpdb $wpdb WordPress database object for queries. |
|
397 |
* |
|
398 |
* @param int $user_id User ID. |
0
|
399 |
* @param string $option_name User option name. |
5
|
400 |
* @param mixed $newvalue User option value. |
|
401 |
* @param bool $global Optional. Whether option name is global or blog specific. |
|
402 |
* Default false (blog specific). |
|
403 |
* @return int|bool User meta ID if the option didn't exist, true on successful update, |
|
404 |
* false on failure. |
0
|
405 |
*/ |
|
406 |
function update_user_option( $user_id, $option_name, $newvalue, $global = false ) { |
|
407 |
global $wpdb; |
|
408 |
|
|
409 |
if ( !$global ) |
|
410 |
$option_name = $wpdb->get_blog_prefix() . $option_name; |
|
411 |
|
|
412 |
return update_user_meta( $user_id, $option_name, $newvalue ); |
|
413 |
} |
|
414 |
|
|
415 |
/** |
|
416 |
* Delete user option with global blog capability. |
|
417 |
* |
|
418 |
* User options are just like user metadata except that they have support for |
|
419 |
* global blog options. If the 'global' parameter is false, which it is by default |
|
420 |
* it will prepend the WordPress table prefix to the option name. |
|
421 |
* |
|
422 |
* @since 3.0.0 |
5
|
423 |
* |
|
424 |
* @global wpdb $wpdb WordPress database object for queries. |
0
|
425 |
* |
5
|
426 |
* @param int $user_id User ID |
0
|
427 |
* @param string $option_name User option name. |
5
|
428 |
* @param bool $global Optional. Whether option name is global or blog specific. |
|
429 |
* Default false (blog specific). |
|
430 |
* @return bool True on success, false on failure. |
0
|
431 |
*/ |
|
432 |
function delete_user_option( $user_id, $option_name, $global = false ) { |
|
433 |
global $wpdb; |
|
434 |
|
|
435 |
if ( !$global ) |
|
436 |
$option_name = $wpdb->get_blog_prefix() . $option_name; |
|
437 |
return delete_user_meta( $user_id, $option_name ); |
|
438 |
} |
|
439 |
|
|
440 |
/** |
|
441 |
* WordPress User Query class. |
|
442 |
* |
|
443 |
* @since 3.1.0 |
5
|
444 |
* |
|
445 |
* @see WP_User_Query::prepare_query() for information on accepted arguments. |
0
|
446 |
*/ |
|
447 |
class WP_User_Query { |
|
448 |
|
|
449 |
/** |
|
450 |
* Query vars, after parsing |
|
451 |
* |
|
452 |
* @since 3.5.0 |
|
453 |
* @access public |
|
454 |
* @var array |
|
455 |
*/ |
5
|
456 |
public $query_vars = array(); |
0
|
457 |
|
|
458 |
/** |
|
459 |
* List of found user ids |
|
460 |
* |
|
461 |
* @since 3.1.0 |
|
462 |
* @access private |
|
463 |
* @var array |
|
464 |
*/ |
5
|
465 |
private $results; |
0
|
466 |
|
|
467 |
/** |
|
468 |
* Total number of found users for the current query |
|
469 |
* |
|
470 |
* @since 3.1.0 |
|
471 |
* @access private |
|
472 |
* @var int |
|
473 |
*/ |
5
|
474 |
private $total_users = 0; |
|
475 |
|
|
476 |
/** |
|
477 |
* Metadata query container. |
|
478 |
* |
|
479 |
* @since 4.2.0 |
|
480 |
* @access public |
|
481 |
* @var object WP_Meta_Query |
|
482 |
*/ |
|
483 |
public $meta_query = false; |
|
484 |
|
|
485 |
private $compat_fields = array( 'results', 'total_users' ); |
0
|
486 |
|
|
487 |
// SQL clauses |
5
|
488 |
public $query_fields; |
|
489 |
public $query_from; |
|
490 |
public $query_where; |
|
491 |
public $query_orderby; |
|
492 |
public $query_limit; |
0
|
493 |
|
|
494 |
/** |
5
|
495 |
* PHP5 constructor. |
0
|
496 |
* |
|
497 |
* @since 3.1.0 |
|
498 |
* |
5
|
499 |
* @param null|string|array $args Optional. The query variables. |
0
|
500 |
*/ |
5
|
501 |
public function __construct( $query = null ) { |
|
502 |
if ( ! empty( $query ) ) { |
|
503 |
$this->prepare_query( $query ); |
|
504 |
$this->query(); |
|
505 |
} |
|
506 |
} |
|
507 |
|
|
508 |
/** |
|
509 |
* Prepare the query variables. |
|
510 |
* |
|
511 |
* @since 3.1.0 |
|
512 |
* @since 4.2.0 Added 'meta_value_num' support for `$orderby` parameter. Added multi-dimensional array syntax |
|
513 |
* for `$orderby` parameter. |
|
514 |
* @access public |
|
515 |
* |
|
516 |
* @param string|array $query { |
|
517 |
* Optional. Array or string of Query parameters. |
|
518 |
* |
|
519 |
* @type int $blog_id The site ID. Default is the global blog id. |
|
520 |
* @type string $role Role name. Default empty. |
|
521 |
* @type string $meta_key User meta key. Default empty. |
|
522 |
* @type string $meta_value User meta value. Default empty. |
|
523 |
* @type string $meta_compare Comparison operator to test the `$meta_value`. Accepts '=', '!=', |
|
524 |
* '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', |
|
525 |
* 'NOT BETWEEN', 'EXISTS', 'NOT EXISTS', 'REGEXP', 'NOT REGEXP', |
|
526 |
* or 'RLIKE'. Default '='. |
|
527 |
* @type array $include An array of user IDs to include. Default empty array. |
|
528 |
* @type array $exclude An array of user IDs to exclude. Default empty array. |
|
529 |
* @type string $search Search keyword. Searches for possible string matches on columns. |
|
530 |
* When `$search_columns` is left empty, it tries to determine which |
|
531 |
* column to search in based on search string. Default empty. |
|
532 |
* @type array $search_columns Array of column names to be searched. Accepts 'ID', 'login', |
|
533 |
* 'nicename', 'email', 'url'. Default empty array. |
|
534 |
* @type string|array $orderby Field(s) to sort the retrieved users by. May be a single value, |
|
535 |
* an array of values, or a multi-dimensional array with fields as keys |
|
536 |
* and orders ('ASC' or 'DESC') as values. Accepted values are'ID', |
|
537 |
* 'display_name' (or 'name'), 'user_login' (or 'login'), |
|
538 |
* 'user_nicename' (or 'nicename'), 'user_email' (or 'email'), |
|
539 |
* 'user_url' (or 'url'), 'user_registered' (or 'registered'), |
|
540 |
* 'post_count', 'meta_value', 'meta_value_num', the value of |
|
541 |
* `$meta_key`, or an array key of `$meta_query`. To use 'meta_value' |
|
542 |
* or 'meta_value_num', `$meta_key` must be also be defined. |
|
543 |
* Default 'user_login'. |
|
544 |
* @type string $order Designates ascending or descending order of users. Order values |
|
545 |
* passed as part of an `$orderby` array take precedence over this |
|
546 |
* parameter. Accepts 'ASC', 'DESC'. Default 'ASC'. |
|
547 |
* @type int $offset Number of users to offset in retrieved results. Can be used in |
|
548 |
* conjunction with pagination. Default 0. |
|
549 |
* @type int $number Number of users to limit the query for. Can be used in conjunction |
|
550 |
* with pagination. Value -1 (all) is not supported. |
|
551 |
* Default empty (all users). |
|
552 |
* @type bool $count_total Whether to count the total number of users found. If pagination is not |
|
553 |
* needed, setting this to false can improve performance. Default true. |
|
554 |
* @type string|array $fields Which fields to return. Single or all fields (string), or array |
|
555 |
* of fields. Accepts 'ID', 'display_name', 'login', 'nicename', 'email', |
|
556 |
* 'url', 'registered'. Use 'all' for all fields and 'all_with_meta' to |
|
557 |
* include meta fields. Default 'all'. |
|
558 |
* @type string $who Type of users to query. Accepts 'authors'. Default empty (all users). |
|
559 |
* } |
|
560 |
*/ |
|
561 |
public function prepare_query( $query = array() ) { |
|
562 |
global $wpdb; |
|
563 |
|
|
564 |
if ( empty( $this->query_vars ) || ! empty( $query ) ) { |
|
565 |
$this->query_limit = null; |
0
|
566 |
$this->query_vars = wp_parse_args( $query, array( |
|
567 |
'blog_id' => $GLOBALS['blog_id'], |
|
568 |
'role' => '', |
|
569 |
'meta_key' => '', |
|
570 |
'meta_value' => '', |
|
571 |
'meta_compare' => '', |
|
572 |
'include' => array(), |
|
573 |
'exclude' => array(), |
|
574 |
'search' => '', |
|
575 |
'search_columns' => array(), |
|
576 |
'orderby' => 'login', |
|
577 |
'order' => 'ASC', |
|
578 |
'offset' => '', |
|
579 |
'number' => '', |
|
580 |
'count_total' => true, |
|
581 |
'fields' => 'all', |
|
582 |
'who' => '' |
|
583 |
) ); |
|
584 |
} |
|
585 |
|
5
|
586 |
/** |
|
587 |
* Fires before the WP_User_Query has been parsed. |
|
588 |
* |
|
589 |
* The passed WP_User_Query object contains the query variables, not |
|
590 |
* yet passed into SQL. |
|
591 |
* |
|
592 |
* @since 4.0.0 |
|
593 |
* |
|
594 |
* @param WP_User_Query $this The current WP_User_Query instance, |
|
595 |
* passed by reference. |
|
596 |
*/ |
|
597 |
do_action( 'pre_get_users', $this ); |
0
|
598 |
|
|
599 |
$qv =& $this->query_vars; |
|
600 |
|
|
601 |
if ( is_array( $qv['fields'] ) ) { |
|
602 |
$qv['fields'] = array_unique( $qv['fields'] ); |
|
603 |
|
|
604 |
$this->query_fields = array(); |
|
605 |
foreach ( $qv['fields'] as $field ) { |
|
606 |
$field = 'ID' === $field ? 'ID' : sanitize_key( $field ); |
|
607 |
$this->query_fields[] = "$wpdb->users.$field"; |
|
608 |
} |
|
609 |
$this->query_fields = implode( ',', $this->query_fields ); |
|
610 |
} elseif ( 'all' == $qv['fields'] ) { |
|
611 |
$this->query_fields = "$wpdb->users.*"; |
|
612 |
} else { |
|
613 |
$this->query_fields = "$wpdb->users.ID"; |
|
614 |
} |
|
615 |
|
|
616 |
if ( isset( $qv['count_total'] ) && $qv['count_total'] ) |
|
617 |
$this->query_fields = 'SQL_CALC_FOUND_ROWS ' . $this->query_fields; |
|
618 |
|
|
619 |
$this->query_from = "FROM $wpdb->users"; |
|
620 |
$this->query_where = "WHERE 1=1"; |
|
621 |
|
5
|
622 |
// Parse and sanitize 'include', for use by 'orderby' as well as 'include' below. |
|
623 |
if ( ! empty( $qv['include'] ) ) { |
|
624 |
$include = wp_parse_id_list( $qv['include'] ); |
|
625 |
} else { |
|
626 |
$include = false; |
|
627 |
} |
|
628 |
|
|
629 |
$blog_id = 0; |
|
630 |
if ( isset( $qv['blog_id'] ) ) { |
|
631 |
$blog_id = absint( $qv['blog_id'] ); |
|
632 |
} |
|
633 |
|
|
634 |
if ( isset( $qv['who'] ) && 'authors' == $qv['who'] && $blog_id ) { |
|
635 |
$qv['meta_key'] = $wpdb->get_blog_prefix( $blog_id ) . 'user_level'; |
|
636 |
$qv['meta_value'] = 0; |
|
637 |
$qv['meta_compare'] = '!='; |
|
638 |
$qv['blog_id'] = $blog_id = 0; // Prevent extra meta query |
|
639 |
} |
|
640 |
|
|
641 |
// Meta query. |
|
642 |
$this->meta_query = new WP_Meta_Query(); |
|
643 |
$this->meta_query->parse_query_vars( $qv ); |
|
644 |
|
|
645 |
$role = ''; |
|
646 |
if ( isset( $qv['role'] ) ) { |
|
647 |
$role = trim( $qv['role'] ); |
|
648 |
} |
|
649 |
|
|
650 |
if ( $blog_id && ( $role || is_multisite() ) ) { |
|
651 |
$cap_meta_query = array(); |
|
652 |
$cap_meta_query['key'] = $wpdb->get_blog_prefix( $blog_id ) . 'capabilities'; |
|
653 |
|
|
654 |
if ( $role ) { |
|
655 |
$cap_meta_query['value'] = '"' . $role . '"'; |
|
656 |
$cap_meta_query['compare'] = 'like'; |
|
657 |
} |
|
658 |
|
|
659 |
if ( empty( $this->meta_query->queries ) ) { |
|
660 |
$this->meta_query->queries = array( $cap_meta_query ); |
|
661 |
} elseif ( ! in_array( $cap_meta_query, $this->meta_query->queries, true ) ) { |
|
662 |
// Append the cap query to the original queries and reparse the query. |
|
663 |
$this->meta_query->queries = array( |
|
664 |
'relation' => 'AND', |
|
665 |
array( $this->meta_query->queries, $cap_meta_query ), |
|
666 |
); |
|
667 |
} |
|
668 |
|
|
669 |
$this->meta_query->parse_query_vars( $this->meta_query->queries ); |
|
670 |
} |
|
671 |
|
|
672 |
if ( ! empty( $this->meta_query->queries ) ) { |
|
673 |
$clauses = $this->meta_query->get_sql( 'user', $wpdb->users, 'ID', $this ); |
|
674 |
$this->query_from .= $clauses['join']; |
|
675 |
$this->query_where .= $clauses['where']; |
|
676 |
|
|
677 |
if ( 'OR' == $this->meta_query->relation ) { |
|
678 |
$this->query_fields = 'DISTINCT ' . $this->query_fields; |
0
|
679 |
} |
|
680 |
} |
|
681 |
|
5
|
682 |
// sorting |
0
|
683 |
$qv['order'] = isset( $qv['order'] ) ? strtoupper( $qv['order'] ) : ''; |
5
|
684 |
$order = $this->parse_order( $qv['order'] ); |
|
685 |
|
|
686 |
if ( empty( $qv['orderby'] ) ) { |
|
687 |
// Default order is by 'user_login'. |
|
688 |
$ordersby = array( 'user_login' => $order ); |
|
689 |
} else if ( is_array( $qv['orderby'] ) ) { |
|
690 |
$ordersby = $qv['orderby']; |
|
691 |
} else { |
|
692 |
// 'orderby' values may be a comma- or space-separated list. |
|
693 |
$ordersby = preg_split( '/[,\s]+/', $qv['orderby'] ); |
|
694 |
} |
|
695 |
|
|
696 |
$orderby_array = array(); |
|
697 |
foreach ( $ordersby as $_key => $_value ) { |
|
698 |
if ( ! $_value ) { |
|
699 |
continue; |
|
700 |
} |
|
701 |
|
|
702 |
if ( is_int( $_key ) ) { |
|
703 |
// Integer key means this is a flat array of 'orderby' fields. |
|
704 |
$_orderby = $_value; |
|
705 |
$_order = $order; |
|
706 |
} else { |
|
707 |
// Non-integer key means this the key is the field and the value is ASC/DESC. |
|
708 |
$_orderby = $_key; |
|
709 |
$_order = $_value; |
|
710 |
} |
|
711 |
|
|
712 |
$parsed = $this->parse_orderby( $_orderby ); |
|
713 |
|
|
714 |
if ( ! $parsed ) { |
|
715 |
continue; |
|
716 |
} |
|
717 |
|
|
718 |
$orderby_array[] = $parsed . ' ' . $this->parse_order( $_order ); |
|
719 |
} |
|
720 |
|
|
721 |
// If no valid clauses were found, order by user_login. |
|
722 |
if ( empty( $orderby_array ) ) { |
|
723 |
$orderby_array[] = "user_login $order"; |
|
724 |
} |
|
725 |
|
|
726 |
$this->query_orderby = 'ORDER BY ' . implode( ', ', $orderby_array ); |
0
|
727 |
|
|
728 |
// limit |
|
729 |
if ( isset( $qv['number'] ) && $qv['number'] ) { |
|
730 |
if ( $qv['offset'] ) |
|
731 |
$this->query_limit = $wpdb->prepare("LIMIT %d, %d", $qv['offset'], $qv['number']); |
|
732 |
else |
|
733 |
$this->query_limit = $wpdb->prepare("LIMIT %d", $qv['number']); |
|
734 |
} |
|
735 |
|
|
736 |
$search = ''; |
|
737 |
if ( isset( $qv['search'] ) ) |
|
738 |
$search = trim( $qv['search'] ); |
|
739 |
|
|
740 |
if ( $search ) { |
|
741 |
$leading_wild = ( ltrim($search, '*') != $search ); |
|
742 |
$trailing_wild = ( rtrim($search, '*') != $search ); |
|
743 |
if ( $leading_wild && $trailing_wild ) |
|
744 |
$wild = 'both'; |
|
745 |
elseif ( $leading_wild ) |
|
746 |
$wild = 'leading'; |
|
747 |
elseif ( $trailing_wild ) |
|
748 |
$wild = 'trailing'; |
|
749 |
else |
|
750 |
$wild = false; |
|
751 |
if ( $wild ) |
|
752 |
$search = trim($search, '*'); |
|
753 |
|
|
754 |
$search_columns = array(); |
|
755 |
if ( $qv['search_columns'] ) |
|
756 |
$search_columns = array_intersect( $qv['search_columns'], array( 'ID', 'user_login', 'user_email', 'user_url', 'user_nicename' ) ); |
|
757 |
if ( ! $search_columns ) { |
|
758 |
if ( false !== strpos( $search, '@') ) |
|
759 |
$search_columns = array('user_email'); |
|
760 |
elseif ( is_numeric($search) ) |
|
761 |
$search_columns = array('user_login', 'ID'); |
|
762 |
elseif ( preg_match('|^https?://|', $search) && ! ( is_multisite() && wp_is_large_network( 'users' ) ) ) |
|
763 |
$search_columns = array('user_url'); |
|
764 |
else |
|
765 |
$search_columns = array('user_login', 'user_nicename'); |
|
766 |
} |
|
767 |
|
5
|
768 |
/** |
|
769 |
* Filter the columns to search in a WP_User_Query search. |
|
770 |
* |
|
771 |
* The default columns depend on the search term, and include 'user_email', |
|
772 |
* 'user_login', 'ID', 'user_url', and 'user_nicename'. |
|
773 |
* |
|
774 |
* @since 3.6.0 |
|
775 |
* |
|
776 |
* @param array $search_columns Array of column names to be searched. |
|
777 |
* @param string $search Text being searched. |
|
778 |
* @param WP_User_Query $this The current WP_User_Query instance. |
|
779 |
*/ |
0
|
780 |
$search_columns = apply_filters( 'user_search_columns', $search_columns, $search, $this ); |
|
781 |
|
|
782 |
$this->query_where .= $this->get_search_sql( $search, $search_columns, $wild ); |
|
783 |
} |
|
784 |
|
5
|
785 |
if ( ! empty( $include ) ) { |
|
786 |
// Sanitized earlier. |
|
787 |
$ids = implode( ',', $include ); |
0
|
788 |
$this->query_where .= " AND $wpdb->users.ID IN ($ids)"; |
|
789 |
} elseif ( ! empty( $qv['exclude'] ) ) { |
|
790 |
$ids = implode( ',', wp_parse_id_list( $qv['exclude'] ) ); |
|
791 |
$this->query_where .= " AND $wpdb->users.ID NOT IN ($ids)"; |
|
792 |
} |
|
793 |
|
5
|
794 |
// Date queries are allowed for the user_registered field. |
|
795 |
if ( ! empty( $qv['date_query'] ) && is_array( $qv['date_query'] ) ) { |
|
796 |
$date_query = new WP_Date_Query( $qv['date_query'], 'user_registered' ); |
|
797 |
$this->query_where .= $date_query->get_sql(); |
|
798 |
} |
|
799 |
|
|
800 |
/** |
|
801 |
* Fires after the WP_User_Query has been parsed, and before |
|
802 |
* the query is executed. |
|
803 |
* |
|
804 |
* The passed WP_User_Query object contains SQL parts formed |
|
805 |
* from parsing the given query. |
|
806 |
* |
|
807 |
* @since 3.1.0 |
|
808 |
* |
|
809 |
* @param WP_User_Query $this The current WP_User_Query instance, |
|
810 |
* passed by reference. |
|
811 |
*/ |
0
|
812 |
do_action_ref_array( 'pre_user_query', array( &$this ) ); |
|
813 |
} |
|
814 |
|
|
815 |
/** |
5
|
816 |
* Execute the query, with the current variables. |
0
|
817 |
* |
|
818 |
* @since 3.1.0 |
5
|
819 |
* |
|
820 |
* @global wpdb $wpdb WordPress database object for queries. |
0
|
821 |
*/ |
5
|
822 |
public function query() { |
0
|
823 |
global $wpdb; |
|
824 |
|
|
825 |
$qv =& $this->query_vars; |
|
826 |
|
5
|
827 |
$query = "SELECT $this->query_fields $this->query_from $this->query_where $this->query_orderby $this->query_limit"; |
|
828 |
|
0
|
829 |
if ( is_array( $qv['fields'] ) || 'all' == $qv['fields'] ) { |
5
|
830 |
$this->results = $wpdb->get_results( $query ); |
0
|
831 |
} else { |
5
|
832 |
$this->results = $wpdb->get_col( $query ); |
0
|
833 |
} |
|
834 |
|
5
|
835 |
/** |
|
836 |
* Filter SELECT FOUND_ROWS() query for the current WP_User_Query instance. |
|
837 |
* |
|
838 |
* @since 3.2.0 |
|
839 |
* |
|
840 |
* @global wpdb $wpdb WordPress database abstraction object. |
|
841 |
* |
|
842 |
* @param string $sql The SELECT FOUND_ROWS() query for the current WP_User_Query. |
|
843 |
*/ |
0
|
844 |
if ( isset( $qv['count_total'] ) && $qv['count_total'] ) |
|
845 |
$this->total_users = $wpdb->get_var( apply_filters( 'found_users_query', 'SELECT FOUND_ROWS()' ) ); |
|
846 |
|
|
847 |
if ( !$this->results ) |
|
848 |
return; |
|
849 |
|
|
850 |
if ( 'all_with_meta' == $qv['fields'] ) { |
|
851 |
cache_users( $this->results ); |
|
852 |
|
|
853 |
$r = array(); |
|
854 |
foreach ( $this->results as $userid ) |
|
855 |
$r[ $userid ] = new WP_User( $userid, '', $qv['blog_id'] ); |
|
856 |
|
|
857 |
$this->results = $r; |
|
858 |
} elseif ( 'all' == $qv['fields'] ) { |
|
859 |
foreach ( $this->results as $key => $user ) { |
5
|
860 |
$this->results[ $key ] = new WP_User( $user, '', $qv['blog_id'] ); |
0
|
861 |
} |
|
862 |
} |
|
863 |
} |
|
864 |
|
|
865 |
/** |
|
866 |
* Retrieve query variable. |
|
867 |
* |
|
868 |
* @since 3.5.0 |
|
869 |
* @access public |
|
870 |
* |
|
871 |
* @param string $query_var Query variable key. |
|
872 |
* @return mixed |
|
873 |
*/ |
5
|
874 |
public function get( $query_var ) { |
0
|
875 |
if ( isset( $this->query_vars[$query_var] ) ) |
|
876 |
return $this->query_vars[$query_var]; |
|
877 |
|
|
878 |
return null; |
|
879 |
} |
|
880 |
|
|
881 |
/** |
|
882 |
* Set query variable. |
|
883 |
* |
|
884 |
* @since 3.5.0 |
|
885 |
* @access public |
|
886 |
* |
|
887 |
* @param string $query_var Query variable key. |
|
888 |
* @param mixed $value Query variable value. |
|
889 |
*/ |
5
|
890 |
public function set( $query_var, $value ) { |
0
|
891 |
$this->query_vars[$query_var] = $value; |
|
892 |
} |
|
893 |
|
5
|
894 |
/** |
0
|
895 |
* Used internally to generate an SQL string for searching across multiple columns |
|
896 |
* |
|
897 |
* @access protected |
|
898 |
* @since 3.1.0 |
|
899 |
* |
|
900 |
* @param string $string |
|
901 |
* @param array $cols |
|
902 |
* @param bool $wild Whether to allow wildcard searches. Default is false for Network Admin, true for |
|
903 |
* single site. Single site allows leading and trailing wildcards, Network Admin only trailing. |
|
904 |
* @return string |
|
905 |
*/ |
5
|
906 |
protected function get_search_sql( $string, $cols, $wild = false ) { |
|
907 |
global $wpdb; |
0
|
908 |
|
|
909 |
$searches = array(); |
|
910 |
$leading_wild = ( 'leading' == $wild || 'both' == $wild ) ? '%' : ''; |
|
911 |
$trailing_wild = ( 'trailing' == $wild || 'both' == $wild ) ? '%' : ''; |
5
|
912 |
$like = $leading_wild . $wpdb->esc_like( $string ) . $trailing_wild; |
|
913 |
|
0
|
914 |
foreach ( $cols as $col ) { |
5
|
915 |
if ( 'ID' == $col ) { |
|
916 |
$searches[] = $wpdb->prepare( "$col = %s", $string ); |
|
917 |
} else { |
|
918 |
$searches[] = $wpdb->prepare( "$col LIKE %s", $like ); |
|
919 |
} |
0
|
920 |
} |
|
921 |
|
|
922 |
return ' AND (' . implode(' OR ', $searches) . ')'; |
|
923 |
} |
|
924 |
|
|
925 |
/** |
5
|
926 |
* Return the list of users. |
|
927 |
* |
|
928 |
* @since 3.1.0 |
|
929 |
* @access public |
|
930 |
* |
|
931 |
* @return array Array of results. |
|
932 |
*/ |
|
933 |
public function get_results() { |
|
934 |
return $this->results; |
|
935 |
} |
|
936 |
|
|
937 |
/** |
|
938 |
* Return the total number of users for the current query. |
0
|
939 |
* |
|
940 |
* @since 3.1.0 |
|
941 |
* @access public |
|
942 |
* |
5
|
943 |
* @return int Number of total users. |
|
944 |
*/ |
|
945 |
public function get_total() { |
|
946 |
return $this->total_users; |
|
947 |
} |
|
948 |
|
|
949 |
/** |
|
950 |
* Parse and sanitize 'orderby' keys passed to the user query. |
|
951 |
* |
|
952 |
* @since 4.2.0 |
|
953 |
* @access protected |
|
954 |
* |
|
955 |
* @global wpdb $wpdb WordPress database abstraction object. |
|
956 |
* |
|
957 |
* @param string $orderby Alias for the field to order by. |
|
958 |
* @return string|bool Value to used in the ORDER clause, if `$orderby` is valid. False otherwise. |
0
|
959 |
*/ |
5
|
960 |
protected function parse_orderby( $orderby ) { |
|
961 |
global $wpdb; |
|
962 |
|
|
963 |
$meta_query_clauses = $this->meta_query->get_clauses(); |
|
964 |
|
|
965 |
$_orderby = ''; |
|
966 |
if ( in_array( $orderby, array( 'login', 'nicename', 'email', 'url', 'registered' ) ) ) { |
|
967 |
$_orderby = 'user_' . $orderby; |
|
968 |
} elseif ( in_array( $orderby, array( 'user_login', 'user_nicename', 'user_email', 'user_url', 'user_registered' ) ) ) { |
|
969 |
$_orderby = $orderby; |
|
970 |
} elseif ( 'name' == $orderby || 'display_name' == $orderby ) { |
|
971 |
$_orderby = 'display_name'; |
|
972 |
} elseif ( 'post_count' == $orderby ) { |
|
973 |
// todo: avoid the JOIN |
|
974 |
$where = get_posts_by_author_sql( 'post' ); |
|
975 |
$this->query_from .= " LEFT OUTER JOIN ( |
|
976 |
SELECT post_author, COUNT(*) as post_count |
|
977 |
FROM $wpdb->posts |
|
978 |
$where |
|
979 |
GROUP BY post_author |
|
980 |
) p ON ({$wpdb->users}.ID = p.post_author) |
|
981 |
"; |
|
982 |
$_orderby = 'post_count'; |
|
983 |
} elseif ( 'ID' == $orderby || 'id' == $orderby ) { |
|
984 |
$_orderby = 'ID'; |
|
985 |
} elseif ( 'meta_value' == $orderby || $this->get( 'meta_key' ) == $orderby ) { |
|
986 |
$_orderby = "$wpdb->usermeta.meta_value"; |
|
987 |
} elseif ( 'meta_value_num' == $orderby ) { |
|
988 |
$_orderby = "$wpdb->usermeta.meta_value+0"; |
|
989 |
} elseif ( 'include' === $orderby && ! empty( $this->query_vars['include'] ) ) { |
|
990 |
$include = wp_parse_id_list( $this->query_vars['include'] ); |
|
991 |
$include_sql = implode( ',', $include ); |
|
992 |
$_orderby = "FIELD( $wpdb->users.ID, $include_sql )"; |
|
993 |
} elseif ( isset( $meta_query_clauses[ $orderby ] ) ) { |
|
994 |
$meta_clause = $meta_query_clauses[ $orderby ]; |
|
995 |
$_orderby = sprintf( "CAST(%s.meta_value AS %s)", esc_sql( $meta_clause['alias'] ), esc_sql( $meta_clause['cast'] ) ); |
|
996 |
} |
|
997 |
|
|
998 |
return $_orderby; |
0
|
999 |
} |
|
1000 |
|
|
1001 |
/** |
5
|
1002 |
* Parse an 'order' query variable and cast it to ASC or DESC as necessary. |
|
1003 |
* |
|
1004 |
* @since 4.2.0 |
|
1005 |
* @access protected |
0
|
1006 |
* |
5
|
1007 |
* @param string $order The 'order' query variable. |
|
1008 |
* @return string The sanitized 'order' query variable. |
|
1009 |
*/ |
|
1010 |
protected function parse_order( $order ) { |
|
1011 |
if ( ! is_string( $order ) || empty( $order ) ) { |
|
1012 |
return 'DESC'; |
|
1013 |
} |
|
1014 |
|
|
1015 |
if ( 'ASC' === strtoupper( $order ) ) { |
|
1016 |
return 'ASC'; |
|
1017 |
} else { |
|
1018 |
return 'DESC'; |
|
1019 |
} |
|
1020 |
} |
|
1021 |
|
|
1022 |
/** |
|
1023 |
* Make private properties readable for backwards compatibility. |
|
1024 |
* |
|
1025 |
* @since 4.0.0 |
|
1026 |
* @access public |
|
1027 |
* |
|
1028 |
* @param string $name Property to get. |
|
1029 |
* @return mixed Property. |
|
1030 |
*/ |
|
1031 |
public function __get( $name ) { |
|
1032 |
if ( in_array( $name, $this->compat_fields ) ) { |
|
1033 |
return $this->$name; |
|
1034 |
} |
|
1035 |
} |
|
1036 |
|
|
1037 |
/** |
|
1038 |
* Make private properties settable for backwards compatibility. |
|
1039 |
* |
|
1040 |
* @since 4.0.0 |
0
|
1041 |
* @access public |
|
1042 |
* |
5
|
1043 |
* @param string $name Property to check if set. |
|
1044 |
* @param mixed $value Property value. |
|
1045 |
* @return mixed Newly-set property. |
|
1046 |
*/ |
|
1047 |
public function __set( $name, $value ) { |
|
1048 |
if ( in_array( $name, $this->compat_fields ) ) { |
|
1049 |
return $this->$name = $value; |
|
1050 |
} |
|
1051 |
} |
|
1052 |
|
|
1053 |
/** |
|
1054 |
* Make private properties checkable for backwards compatibility. |
|
1055 |
* |
|
1056 |
* @since 4.0.0 |
|
1057 |
* @access public |
|
1058 |
* |
|
1059 |
* @param string $name Property to check if set. |
|
1060 |
* @return bool Whether the property is set. |
0
|
1061 |
*/ |
5
|
1062 |
public function __isset( $name ) { |
|
1063 |
if ( in_array( $name, $this->compat_fields ) ) { |
|
1064 |
return isset( $this->$name ); |
|
1065 |
} |
|
1066 |
} |
|
1067 |
|
|
1068 |
/** |
|
1069 |
* Make private properties un-settable for backwards compatibility. |
|
1070 |
* |
|
1071 |
* @since 4.0.0 |
|
1072 |
* @access public |
|
1073 |
* |
|
1074 |
* @param string $name Property to unset. |
|
1075 |
*/ |
|
1076 |
public function __unset( $name ) { |
|
1077 |
if ( in_array( $name, $this->compat_fields ) ) { |
|
1078 |
unset( $this->$name ); |
|
1079 |
} |
|
1080 |
} |
|
1081 |
|
|
1082 |
/** |
|
1083 |
* Make private/protected methods readable for backwards compatibility. |
|
1084 |
* |
|
1085 |
* @since 4.0.0 |
|
1086 |
* @access public |
|
1087 |
* |
|
1088 |
* @param callable $name Method to call. |
|
1089 |
* @param array $arguments Arguments to pass when calling. |
|
1090 |
* @return mixed|bool Return value of the callback, false otherwise. |
|
1091 |
*/ |
|
1092 |
public function __call( $name, $arguments ) { |
|
1093 |
if ( 'get_search_sql' === $name ) { |
|
1094 |
return call_user_func_array( array( $this, $name ), $arguments ); |
|
1095 |
} |
|
1096 |
return false; |
0
|
1097 |
} |
|
1098 |
} |
|
1099 |
|
|
1100 |
/** |
|
1101 |
* Retrieve list of users matching criteria. |
|
1102 |
* |
|
1103 |
* @since 3.1.0 |
5
|
1104 |
* |
|
1105 |
* @see WP_User_Query |
0
|
1106 |
* |
5
|
1107 |
* @param array $args Optional. Arguments to retrieve users. See {@see WP_User_Query::prepare_query()} |
|
1108 |
* for more information on accepted arguments. |
0
|
1109 |
* @return array List of users. |
|
1110 |
*/ |
|
1111 |
function get_users( $args = array() ) { |
|
1112 |
|
|
1113 |
$args = wp_parse_args( $args ); |
|
1114 |
$args['count_total'] = false; |
|
1115 |
|
|
1116 |
$user_search = new WP_User_Query($args); |
|
1117 |
|
|
1118 |
return (array) $user_search->get_results(); |
|
1119 |
} |
|
1120 |
|
|
1121 |
/** |
|
1122 |
* Get the blogs a user belongs to. |
|
1123 |
* |
|
1124 |
* @since 3.0.0 |
|
1125 |
* |
5
|
1126 |
* @global wpdb $wpdb WordPress database object for queries. |
|
1127 |
* |
|
1128 |
* @param int $user_id User ID |
|
1129 |
* @param bool $all Whether to retrieve all blogs, or only blogs that are not |
|
1130 |
* marked as deleted, archived, or spam. |
|
1131 |
* @return array A list of the user's blogs. An empty array if the user doesn't exist |
|
1132 |
* or belongs to no blogs. |
0
|
1133 |
*/ |
|
1134 |
function get_blogs_of_user( $user_id, $all = false ) { |
|
1135 |
global $wpdb; |
|
1136 |
|
|
1137 |
$user_id = (int) $user_id; |
|
1138 |
|
|
1139 |
// Logged out users can't have blogs |
|
1140 |
if ( empty( $user_id ) ) |
|
1141 |
return array(); |
|
1142 |
|
|
1143 |
$keys = get_user_meta( $user_id ); |
|
1144 |
if ( empty( $keys ) ) |
|
1145 |
return array(); |
|
1146 |
|
|
1147 |
if ( ! is_multisite() ) { |
|
1148 |
$blog_id = get_current_blog_id(); |
|
1149 |
$blogs = array( $blog_id => new stdClass ); |
|
1150 |
$blogs[ $blog_id ]->userblog_id = $blog_id; |
|
1151 |
$blogs[ $blog_id ]->blogname = get_option('blogname'); |
|
1152 |
$blogs[ $blog_id ]->domain = ''; |
|
1153 |
$blogs[ $blog_id ]->path = ''; |
|
1154 |
$blogs[ $blog_id ]->site_id = 1; |
|
1155 |
$blogs[ $blog_id ]->siteurl = get_option('siteurl'); |
|
1156 |
$blogs[ $blog_id ]->archived = 0; |
|
1157 |
$blogs[ $blog_id ]->spam = 0; |
|
1158 |
$blogs[ $blog_id ]->deleted = 0; |
|
1159 |
return $blogs; |
|
1160 |
} |
|
1161 |
|
|
1162 |
$blogs = array(); |
|
1163 |
|
|
1164 |
if ( isset( $keys[ $wpdb->base_prefix . 'capabilities' ] ) && defined( 'MULTISITE' ) ) { |
|
1165 |
$blog = get_blog_details( 1 ); |
|
1166 |
if ( $blog && isset( $blog->domain ) && ( $all || ( ! $blog->archived && ! $blog->spam && ! $blog->deleted ) ) ) { |
|
1167 |
$blogs[ 1 ] = (object) array( |
|
1168 |
'userblog_id' => 1, |
|
1169 |
'blogname' => $blog->blogname, |
|
1170 |
'domain' => $blog->domain, |
|
1171 |
'path' => $blog->path, |
|
1172 |
'site_id' => $blog->site_id, |
|
1173 |
'siteurl' => $blog->siteurl, |
|
1174 |
'archived' => 0, |
|
1175 |
'spam' => 0, |
|
1176 |
'deleted' => 0 |
|
1177 |
); |
|
1178 |
} |
|
1179 |
unset( $keys[ $wpdb->base_prefix . 'capabilities' ] ); |
|
1180 |
} |
|
1181 |
|
|
1182 |
$keys = array_keys( $keys ); |
|
1183 |
|
|
1184 |
foreach ( $keys as $key ) { |
|
1185 |
if ( 'capabilities' !== substr( $key, -12 ) ) |
|
1186 |
continue; |
|
1187 |
if ( $wpdb->base_prefix && 0 !== strpos( $key, $wpdb->base_prefix ) ) |
|
1188 |
continue; |
|
1189 |
$blog_id = str_replace( array( $wpdb->base_prefix, '_capabilities' ), '', $key ); |
|
1190 |
if ( ! is_numeric( $blog_id ) ) |
|
1191 |
continue; |
|
1192 |
|
|
1193 |
$blog_id = (int) $blog_id; |
|
1194 |
$blog = get_blog_details( $blog_id ); |
|
1195 |
if ( $blog && isset( $blog->domain ) && ( $all || ( ! $blog->archived && ! $blog->spam && ! $blog->deleted ) ) ) { |
|
1196 |
$blogs[ $blog_id ] = (object) array( |
|
1197 |
'userblog_id' => $blog_id, |
|
1198 |
'blogname' => $blog->blogname, |
|
1199 |
'domain' => $blog->domain, |
|
1200 |
'path' => $blog->path, |
|
1201 |
'site_id' => $blog->site_id, |
|
1202 |
'siteurl' => $blog->siteurl, |
|
1203 |
'archived' => 0, |
|
1204 |
'spam' => 0, |
|
1205 |
'deleted' => 0 |
|
1206 |
); |
|
1207 |
} |
|
1208 |
} |
|
1209 |
|
5
|
1210 |
/** |
|
1211 |
* Filter the list of blogs a user belongs to. |
|
1212 |
* |
|
1213 |
* @since MU |
|
1214 |
* |
|
1215 |
* @param array $blogs An array of blog objects belonging to the user. |
|
1216 |
* @param int $user_id User ID. |
|
1217 |
* @param bool $all Whether the returned blogs array should contain all blogs, including |
|
1218 |
* those marked 'deleted', 'archived', or 'spam'. Default false. |
|
1219 |
*/ |
0
|
1220 |
return apply_filters( 'get_blogs_of_user', $blogs, $user_id, $all ); |
|
1221 |
} |
|
1222 |
|
|
1223 |
/** |
|
1224 |
* Find out whether a user is a member of a given blog. |
|
1225 |
* |
|
1226 |
* @since MU 1.1 |
|
1227 |
* |
|
1228 |
* @param int $user_id Optional. The unique ID of the user. Defaults to the current user. |
|
1229 |
* @param int $blog_id Optional. ID of the blog to check. Defaults to the current site. |
|
1230 |
* @return bool |
|
1231 |
*/ |
|
1232 |
function is_user_member_of_blog( $user_id = 0, $blog_id = 0 ) { |
|
1233 |
$user_id = (int) $user_id; |
|
1234 |
$blog_id = (int) $blog_id; |
|
1235 |
|
|
1236 |
if ( empty( $user_id ) ) |
|
1237 |
$user_id = get_current_user_id(); |
|
1238 |
|
|
1239 |
if ( empty( $blog_id ) ) |
|
1240 |
$blog_id = get_current_blog_id(); |
|
1241 |
|
|
1242 |
$blogs = get_blogs_of_user( $user_id ); |
|
1243 |
return array_key_exists( $blog_id, $blogs ); |
|
1244 |
} |
|
1245 |
|
|
1246 |
/** |
|
1247 |
* Add meta data field to a user. |
|
1248 |
* |
|
1249 |
* Post meta data is called "Custom Fields" on the Administration Screens. |
|
1250 |
* |
|
1251 |
* @since 3.0.0 |
5
|
1252 |
* @link https://codex.wordpress.org/Function_Reference/add_user_meta |
0
|
1253 |
* |
5
|
1254 |
* @param int $user_id User ID. |
0
|
1255 |
* @param string $meta_key Metadata name. |
|
1256 |
* @param mixed $meta_value Metadata value. |
|
1257 |
* @param bool $unique Optional, default is false. Whether the same key should not be added. |
|
1258 |
* @return int|bool Meta ID on success, false on failure. |
|
1259 |
*/ |
|
1260 |
function add_user_meta($user_id, $meta_key, $meta_value, $unique = false) { |
|
1261 |
return add_metadata('user', $user_id, $meta_key, $meta_value, $unique); |
|
1262 |
} |
|
1263 |
|
|
1264 |
/** |
|
1265 |
* Remove metadata matching criteria from a user. |
|
1266 |
* |
|
1267 |
* You can match based on the key, or key and value. Removing based on key and |
|
1268 |
* value, will keep from removing duplicate metadata with the same key. It also |
|
1269 |
* allows removing all metadata matching key, if needed. |
|
1270 |
* |
|
1271 |
* @since 3.0.0 |
5
|
1272 |
* @link https://codex.wordpress.org/Function_Reference/delete_user_meta |
0
|
1273 |
* |
|
1274 |
* @param int $user_id user ID |
|
1275 |
* @param string $meta_key Metadata name. |
|
1276 |
* @param mixed $meta_value Optional. Metadata value. |
|
1277 |
* @return bool True on success, false on failure. |
|
1278 |
*/ |
|
1279 |
function delete_user_meta($user_id, $meta_key, $meta_value = '') { |
|
1280 |
return delete_metadata('user', $user_id, $meta_key, $meta_value); |
|
1281 |
} |
|
1282 |
|
|
1283 |
/** |
|
1284 |
* Retrieve user meta field for a user. |
|
1285 |
* |
|
1286 |
* @since 3.0.0 |
5
|
1287 |
* @link https://codex.wordpress.org/Function_Reference/get_user_meta |
0
|
1288 |
* |
5
|
1289 |
* @param int $user_id User ID. |
0
|
1290 |
* @param string $key Optional. The meta key to retrieve. By default, returns data for all keys. |
|
1291 |
* @param bool $single Whether to return a single value. |
|
1292 |
* @return mixed Will be an array if $single is false. Will be value of meta data field if $single |
|
1293 |
* is true. |
|
1294 |
*/ |
|
1295 |
function get_user_meta($user_id, $key = '', $single = false) { |
|
1296 |
return get_metadata('user', $user_id, $key, $single); |
|
1297 |
} |
|
1298 |
|
|
1299 |
/** |
|
1300 |
* Update user meta field based on user ID. |
|
1301 |
* |
|
1302 |
* Use the $prev_value parameter to differentiate between meta fields with the |
|
1303 |
* same key and user ID. |
|
1304 |
* |
|
1305 |
* If the meta field for the user does not exist, it will be added. |
|
1306 |
* |
|
1307 |
* @since 3.0.0 |
5
|
1308 |
* @link https://codex.wordpress.org/Function_Reference/update_user_meta |
0
|
1309 |
* |
5
|
1310 |
* @param int $user_id User ID. |
0
|
1311 |
* @param string $meta_key Metadata key. |
|
1312 |
* @param mixed $meta_value Metadata value. |
|
1313 |
* @param mixed $prev_value Optional. Previous value to check before removing. |
5
|
1314 |
* @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure. |
0
|
1315 |
*/ |
|
1316 |
function update_user_meta($user_id, $meta_key, $meta_value, $prev_value = '') { |
|
1317 |
return update_metadata('user', $user_id, $meta_key, $meta_value, $prev_value); |
|
1318 |
} |
|
1319 |
|
|
1320 |
/** |
|
1321 |
* Count number of users who have each of the user roles. |
|
1322 |
* |
|
1323 |
* Assumes there are neither duplicated nor orphaned capabilities meta_values. |
|
1324 |
* Assumes role names are unique phrases. Same assumption made by WP_User_Query::prepare_query() |
|
1325 |
* Using $strategy = 'time' this is CPU-intensive and should handle around 10^7 users. |
|
1326 |
* Using $strategy = 'memory' this is memory-intensive and should handle around 10^5 users, but see WP Bug #12257. |
|
1327 |
* |
|
1328 |
* @since 3.0.0 |
|
1329 |
* @param string $strategy 'time' or 'memory' |
|
1330 |
* @return array Includes a grand total and an array of counts indexed by role strings. |
|
1331 |
*/ |
|
1332 |
function count_users($strategy = 'time') { |
|
1333 |
global $wpdb, $wp_roles; |
|
1334 |
|
|
1335 |
// Initialize |
|
1336 |
$id = get_current_blog_id(); |
|
1337 |
$blog_prefix = $wpdb->get_blog_prefix($id); |
|
1338 |
$result = array(); |
|
1339 |
|
|
1340 |
if ( 'time' == $strategy ) { |
|
1341 |
global $wp_roles; |
|
1342 |
|
|
1343 |
if ( ! isset( $wp_roles ) ) |
|
1344 |
$wp_roles = new WP_Roles(); |
|
1345 |
|
|
1346 |
$avail_roles = $wp_roles->get_names(); |
|
1347 |
|
|
1348 |
// Build a CPU-intensive query that will return concise information. |
|
1349 |
$select_count = array(); |
|
1350 |
foreach ( $avail_roles as $this_role => $name ) { |
5
|
1351 |
$select_count[] = $wpdb->prepare( "COUNT(NULLIF(`meta_value` LIKE %s, false))", '%' . $wpdb->esc_like( '"' . $this_role . '"' ) . '%'); |
0
|
1352 |
} |
|
1353 |
$select_count = implode(', ', $select_count); |
|
1354 |
|
|
1355 |
// Add the meta_value index to the selection list, then run the query. |
|
1356 |
$row = $wpdb->get_row( "SELECT $select_count, COUNT(*) FROM $wpdb->usermeta WHERE meta_key = '{$blog_prefix}capabilities'", ARRAY_N ); |
|
1357 |
|
|
1358 |
// Run the previous loop again to associate results with role names. |
|
1359 |
$col = 0; |
|
1360 |
$role_counts = array(); |
|
1361 |
foreach ( $avail_roles as $this_role => $name ) { |
|
1362 |
$count = (int) $row[$col++]; |
|
1363 |
if ($count > 0) { |
|
1364 |
$role_counts[$this_role] = $count; |
|
1365 |
} |
|
1366 |
} |
|
1367 |
|
|
1368 |
// Get the meta_value index from the end of the result set. |
|
1369 |
$total_users = (int) $row[$col]; |
|
1370 |
|
|
1371 |
$result['total_users'] = $total_users; |
|
1372 |
$result['avail_roles'] =& $role_counts; |
|
1373 |
} else { |
|
1374 |
$avail_roles = array(); |
|
1375 |
|
|
1376 |
$users_of_blog = $wpdb->get_col( "SELECT meta_value FROM $wpdb->usermeta WHERE meta_key = '{$blog_prefix}capabilities'" ); |
|
1377 |
|
|
1378 |
foreach ( $users_of_blog as $caps_meta ) { |
|
1379 |
$b_roles = maybe_unserialize($caps_meta); |
|
1380 |
if ( ! is_array( $b_roles ) ) |
|
1381 |
continue; |
|
1382 |
foreach ( $b_roles as $b_role => $val ) { |
|
1383 |
if ( isset($avail_roles[$b_role]) ) { |
|
1384 |
$avail_roles[$b_role]++; |
|
1385 |
} else { |
|
1386 |
$avail_roles[$b_role] = 1; |
|
1387 |
} |
|
1388 |
} |
|
1389 |
} |
|
1390 |
|
|
1391 |
$result['total_users'] = count( $users_of_blog ); |
|
1392 |
$result['avail_roles'] =& $avail_roles; |
|
1393 |
} |
|
1394 |
|
|
1395 |
return $result; |
|
1396 |
} |
|
1397 |
|
|
1398 |
// |
|
1399 |
// Private helper functions |
|
1400 |
// |
|
1401 |
|
|
1402 |
/** |
|
1403 |
* Set up global user vars. |
|
1404 |
* |
|
1405 |
* Used by wp_set_current_user() for back compat. Might be deprecated in the future. |
|
1406 |
* |
|
1407 |
* @since 2.0.4 |
|
1408 |
* @global string $userdata User description. |
|
1409 |
* @global string $user_login The user username for logging in |
|
1410 |
* @global int $user_level The level of the user |
|
1411 |
* @global int $user_ID The ID of the user |
|
1412 |
* @global string $user_email The email address of the user |
|
1413 |
* @global string $user_url The url in the user's profile |
|
1414 |
* @global string $user_identity The display name of the user |
|
1415 |
* |
|
1416 |
* @param int $for_user_id Optional. User ID to set up global data. |
|
1417 |
*/ |
|
1418 |
function setup_userdata($for_user_id = '') { |
|
1419 |
global $user_login, $userdata, $user_level, $user_ID, $user_email, $user_url, $user_identity; |
|
1420 |
|
|
1421 |
if ( '' == $for_user_id ) |
|
1422 |
$for_user_id = get_current_user_id(); |
|
1423 |
$user = get_userdata( $for_user_id ); |
|
1424 |
|
|
1425 |
if ( ! $user ) { |
|
1426 |
$user_ID = 0; |
|
1427 |
$user_level = 0; |
|
1428 |
$userdata = null; |
|
1429 |
$user_login = $user_email = $user_url = $user_identity = ''; |
|
1430 |
return; |
|
1431 |
} |
|
1432 |
|
|
1433 |
$user_ID = (int) $user->ID; |
|
1434 |
$user_level = (int) $user->user_level; |
|
1435 |
$userdata = $user; |
|
1436 |
$user_login = $user->user_login; |
|
1437 |
$user_email = $user->user_email; |
|
1438 |
$user_url = $user->user_url; |
|
1439 |
$user_identity = $user->display_name; |
|
1440 |
} |
|
1441 |
|
|
1442 |
/** |
|
1443 |
* Create dropdown HTML content of users. |
|
1444 |
* |
|
1445 |
* The content can either be displayed, which it is by default or retrieved by |
|
1446 |
* setting the 'echo' argument. The 'include' and 'exclude' arguments do not |
|
1447 |
* need to be used; all users will be displayed in that case. Only one can be |
|
1448 |
* used, either 'include' or 'exclude', but not both. |
|
1449 |
* |
|
1450 |
* The available arguments are as follows: |
|
1451 |
* |
|
1452 |
* @since 2.3.0 |
5
|
1453 |
* |
|
1454 |
* @global wpdb $wpdb WordPress database object for queries. |
|
1455 |
* |
|
1456 |
* @param array|string $args { |
|
1457 |
* Optional. Array or string of arguments to generate a drop-down of users. |
|
1458 |
* {@see WP_User_Query::prepare_query() for additional available arguments. |
0
|
1459 |
* |
5
|
1460 |
* @type string $show_option_all Text to show as the drop-down default (all). |
|
1461 |
* Default empty. |
|
1462 |
* @type string $show_option_none Text to show as the drop-down default when no |
|
1463 |
* users were found. Default empty. |
|
1464 |
* @type int|string $option_none_value Value to use for $show_option_non when no users |
|
1465 |
* were found. Default -1. |
|
1466 |
* @type string $hide_if_only_one_author Whether to skip generating the drop-down |
|
1467 |
* if only one user was found. Default empty. |
|
1468 |
* @type string $orderby Field to order found users by. Accepts user fields. |
|
1469 |
* Default 'display_name'. |
|
1470 |
* @type string $order Whether to order users in ascending or descending |
|
1471 |
* order. Accepts 'ASC' (ascending) or 'DESC' (descending). |
|
1472 |
* Default 'ASC'. |
|
1473 |
* @type array|string $include Array or comma-separated list of user IDs to include. |
|
1474 |
* Default empty. |
|
1475 |
* @type array|string $exclude Array or comma-separated list of user IDs to exclude. |
|
1476 |
* Default empty. |
|
1477 |
* @type bool|int $multi Whether to skip the ID attribute on the 'select' element. |
|
1478 |
* Accepts 1|true or 0|false. Default 0|false. |
|
1479 |
* @type string $show User table column to display. If the selected item is empty |
|
1480 |
* then the 'user_login' will be displayed in parentheses. |
|
1481 |
* Accepts user fields. Default 'display_name'. |
|
1482 |
* @type int|bool $echo Whether to echo or return the drop-down. Accepts 1|true (echo) |
|
1483 |
* or 0|false (return). Default 1|true. |
|
1484 |
* @type int $selected Which user ID should be selected. Default 0. |
|
1485 |
* @type bool $include_selected Whether to always include the selected user ID in the drop- |
|
1486 |
* down. Default false. |
|
1487 |
* @type string $name Name attribute of select element. Default 'user'. |
|
1488 |
* @type string $id ID attribute of the select element. Default is the value of $name. |
|
1489 |
* @type string $class Class attribute of the select element. Default empty. |
|
1490 |
* @type int $blog_id ID of blog (Multisite only). Default is ID of the current blog. |
|
1491 |
* @type string $who Which type of users to query. Accepts only an empty string or |
|
1492 |
* 'authors'. Default empty. |
|
1493 |
* } |
0
|
1494 |
* @return string|null Null on display. String of HTML content on retrieve. |
|
1495 |
*/ |
|
1496 |
function wp_dropdown_users( $args = '' ) { |
|
1497 |
$defaults = array( |
|
1498 |
'show_option_all' => '', 'show_option_none' => '', 'hide_if_only_one_author' => '', |
|
1499 |
'orderby' => 'display_name', 'order' => 'ASC', |
|
1500 |
'include' => '', 'exclude' => '', 'multi' => 0, |
|
1501 |
'show' => 'display_name', 'echo' => 1, |
|
1502 |
'selected' => 0, 'name' => 'user', 'class' => '', 'id' => '', |
5
|
1503 |
'blog_id' => $GLOBALS['blog_id'], 'who' => '', 'include_selected' => false, |
|
1504 |
'option_none_value' => -1 |
0
|
1505 |
); |
|
1506 |
|
|
1507 |
$defaults['selected'] = is_author() ? get_query_var( 'author' ) : 0; |
|
1508 |
|
|
1509 |
$r = wp_parse_args( $args, $defaults ); |
5
|
1510 |
$show = $r['show']; |
|
1511 |
$show_option_all = $r['show_option_all']; |
|
1512 |
$show_option_none = $r['show_option_none']; |
|
1513 |
$option_none_value = $r['option_none_value']; |
0
|
1514 |
|
|
1515 |
$query_args = wp_array_slice_assoc( $r, array( 'blog_id', 'include', 'exclude', 'orderby', 'order', 'who' ) ); |
|
1516 |
$query_args['fields'] = array( 'ID', 'user_login', $show ); |
|
1517 |
$users = get_users( $query_args ); |
|
1518 |
|
|
1519 |
$output = ''; |
5
|
1520 |
if ( ! empty( $users ) && ( empty( $r['hide_if_only_one_author'] ) || count( $users ) > 1 ) ) { |
|
1521 |
$name = esc_attr( $r['name'] ); |
|
1522 |
if ( $r['multi'] && ! $r['id'] ) { |
0
|
1523 |
$id = ''; |
5
|
1524 |
} else { |
|
1525 |
$id = $r['id'] ? " id='" . esc_attr( $r['id'] ) . "'" : " id='$name'"; |
|
1526 |
} |
|
1527 |
$output = "<select name='{$name}'{$id} class='" . $r['class'] . "'>\n"; |
0
|
1528 |
|
5
|
1529 |
if ( $show_option_all ) { |
0
|
1530 |
$output .= "\t<option value='0'>$show_option_all</option>\n"; |
5
|
1531 |
} |
0
|
1532 |
|
|
1533 |
if ( $show_option_none ) { |
5
|
1534 |
$_selected = selected( $option_none_value, $r['selected'], false ); |
|
1535 |
$output .= "\t<option value='" . esc_attr( $option_none_value ) . "'$_selected>$show_option_none</option>\n"; |
0
|
1536 |
} |
|
1537 |
|
|
1538 |
$found_selected = false; |
|
1539 |
foreach ( (array) $users as $user ) { |
|
1540 |
$user->ID = (int) $user->ID; |
5
|
1541 |
$_selected = selected( $user->ID, $r['selected'], false ); |
|
1542 |
if ( $_selected ) { |
0
|
1543 |
$found_selected = true; |
5
|
1544 |
} |
|
1545 |
$display = ! empty( $user->$show ) ? $user->$show : '('. $user->user_login . ')'; |
|
1546 |
$output .= "\t<option value='$user->ID'$_selected>" . esc_html( $display ) . "</option>\n"; |
0
|
1547 |
} |
|
1548 |
|
5
|
1549 |
if ( $r['include_selected'] && ! $found_selected && ( $r['selected'] > 0 ) ) { |
|
1550 |
$user = get_userdata( $r['selected'] ); |
|
1551 |
$_selected = selected( $user->ID, $r['selected'], false ); |
|
1552 |
$display = ! empty( $user->$show ) ? $user->$show : '('. $user->user_login . ')'; |
|
1553 |
$output .= "\t<option value='$user->ID'$_selected>" . esc_html( $display ) . "</option>\n"; |
0
|
1554 |
} |
|
1555 |
|
|
1556 |
$output .= "</select>"; |
|
1557 |
} |
|
1558 |
|
5
|
1559 |
/** |
|
1560 |
* Filter the wp_dropdown_users() HTML output. |
|
1561 |
* |
|
1562 |
* @since 2.3.0 |
|
1563 |
* |
|
1564 |
* @param string $output HTML output generated by wp_dropdown_users(). |
|
1565 |
*/ |
|
1566 |
$html = apply_filters( 'wp_dropdown_users', $output ); |
0
|
1567 |
|
5
|
1568 |
if ( $r['echo'] ) { |
|
1569 |
echo $html; |
|
1570 |
} |
|
1571 |
return $html; |
0
|
1572 |
} |
|
1573 |
|
|
1574 |
/** |
|
1575 |
* Sanitize user field based on context. |
|
1576 |
* |
|
1577 |
* Possible context values are: 'raw', 'edit', 'db', 'display', 'attribute' and 'js'. The |
|
1578 |
* 'display' context is used by default. 'attribute' and 'js' contexts are treated like 'display' |
|
1579 |
* when calling filters. |
|
1580 |
* |
|
1581 |
* @since 2.3.0 |
|
1582 |
* |
|
1583 |
* @param string $field The user Object field name. |
|
1584 |
* @param mixed $value The user Object value. |
|
1585 |
* @param int $user_id user ID. |
|
1586 |
* @param string $context How to sanitize user fields. Looks for 'raw', 'edit', 'db', 'display', |
|
1587 |
* 'attribute' and 'js'. |
|
1588 |
* @return mixed Sanitized value. |
|
1589 |
*/ |
|
1590 |
function sanitize_user_field($field, $value, $user_id, $context) { |
|
1591 |
$int_fields = array('ID'); |
|
1592 |
if ( in_array($field, $int_fields) ) |
|
1593 |
$value = (int) $value; |
|
1594 |
|
|
1595 |
if ( 'raw' == $context ) |
|
1596 |
return $value; |
|
1597 |
|
|
1598 |
if ( !is_string($value) && !is_numeric($value) ) |
|
1599 |
return $value; |
|
1600 |
|
|
1601 |
$prefixed = false !== strpos( $field, 'user_' ); |
|
1602 |
|
|
1603 |
if ( 'edit' == $context ) { |
|
1604 |
if ( $prefixed ) { |
5
|
1605 |
|
|
1606 |
/** This filter is documented in wp-includes/post.php */ |
|
1607 |
$value = apply_filters( "edit_{$field}", $value, $user_id ); |
0
|
1608 |
} else { |
5
|
1609 |
|
|
1610 |
/** |
|
1611 |
* Filter a user field value in the 'edit' context. |
|
1612 |
* |
|
1613 |
* The dynamic portion of the hook name, `$field`, refers to the prefixed user |
|
1614 |
* field being filtered, such as 'user_login', 'user_email', 'first_name', etc. |
|
1615 |
* |
|
1616 |
* @since 2.9.0 |
|
1617 |
* |
|
1618 |
* @param mixed $value Value of the prefixed user field. |
|
1619 |
* @param int $user_id User ID. |
|
1620 |
*/ |
|
1621 |
$value = apply_filters( "edit_user_{$field}", $value, $user_id ); |
0
|
1622 |
} |
|
1623 |
|
|
1624 |
if ( 'description' == $field ) |
|
1625 |
$value = esc_html( $value ); // textarea_escaped? |
|
1626 |
else |
|
1627 |
$value = esc_attr($value); |
5
|
1628 |
} elseif ( 'db' == $context ) { |
0
|
1629 |
if ( $prefixed ) { |
5
|
1630 |
/** This filter is documented in wp-includes/post.php */ |
|
1631 |
$value = apply_filters( "pre_{$field}", $value ); |
0
|
1632 |
} else { |
5
|
1633 |
|
|
1634 |
/** |
|
1635 |
* Filter the value of a user field in the 'db' context. |
|
1636 |
* |
|
1637 |
* The dynamic portion of the hook name, `$field`, refers to the prefixed user |
|
1638 |
* field being filtered, such as 'user_login', 'user_email', 'first_name', etc. |
|
1639 |
* |
|
1640 |
* @since 2.9.0 |
|
1641 |
* |
|
1642 |
* @param mixed $value Value of the prefixed user field. |
|
1643 |
*/ |
|
1644 |
$value = apply_filters( "pre_user_{$field}", $value ); |
0
|
1645 |
} |
|
1646 |
} else { |
|
1647 |
// Use display filters by default. |
5
|
1648 |
if ( $prefixed ) { |
|
1649 |
|
|
1650 |
/** This filter is documented in wp-includes/post.php */ |
|
1651 |
$value = apply_filters( $field, $value, $user_id, $context ); |
|
1652 |
} else { |
|
1653 |
|
|
1654 |
/** |
|
1655 |
* Filter the value of a user field in a standard context. |
|
1656 |
* |
|
1657 |
* The dynamic portion of the hook name, `$field`, refers to the prefixed user |
|
1658 |
* field being filtered, such as 'user_login', 'user_email', 'first_name', etc. |
|
1659 |
* |
|
1660 |
* @since 2.9.0 |
|
1661 |
* |
|
1662 |
* @param mixed $value The user object value to sanitize. |
|
1663 |
* @param int $user_id User ID. |
|
1664 |
* @param string $context The context to filter within. |
|
1665 |
*/ |
|
1666 |
$value = apply_filters( "user_{$field}", $value, $user_id, $context ); |
|
1667 |
} |
0
|
1668 |
} |
|
1669 |
|
|
1670 |
if ( 'user_url' == $field ) |
|
1671 |
$value = esc_url($value); |
|
1672 |
|
5
|
1673 |
if ( 'attribute' == $context ) { |
|
1674 |
$value = esc_attr( $value ); |
|
1675 |
} elseif ( 'js' == $context ) { |
|
1676 |
$value = esc_js( $value ); |
|
1677 |
} |
0
|
1678 |
return $value; |
|
1679 |
} |
|
1680 |
|
|
1681 |
/** |
|
1682 |
* Update all user caches |
|
1683 |
* |
|
1684 |
* @since 3.0.0 |
|
1685 |
* |
|
1686 |
* @param object $user User object to be cached |
|
1687 |
*/ |
|
1688 |
function update_user_caches($user) { |
|
1689 |
wp_cache_add($user->ID, $user, 'users'); |
|
1690 |
wp_cache_add($user->user_login, $user->ID, 'userlogins'); |
|
1691 |
wp_cache_add($user->user_email, $user->ID, 'useremail'); |
|
1692 |
wp_cache_add($user->user_nicename, $user->ID, 'userslugs'); |
|
1693 |
} |
|
1694 |
|
|
1695 |
/** |
|
1696 |
* Clean all user caches |
|
1697 |
* |
|
1698 |
* @since 3.0.0 |
|
1699 |
* |
|
1700 |
* @param WP_User|int $user User object or ID to be cleaned from the cache |
|
1701 |
*/ |
|
1702 |
function clean_user_cache( $user ) { |
|
1703 |
if ( is_numeric( $user ) ) |
|
1704 |
$user = new WP_User( $user ); |
|
1705 |
|
|
1706 |
if ( ! $user->exists() ) |
|
1707 |
return; |
|
1708 |
|
|
1709 |
wp_cache_delete( $user->ID, 'users' ); |
|
1710 |
wp_cache_delete( $user->user_login, 'userlogins' ); |
|
1711 |
wp_cache_delete( $user->user_email, 'useremail' ); |
|
1712 |
wp_cache_delete( $user->user_nicename, 'userslugs' ); |
|
1713 |
} |
|
1714 |
|
|
1715 |
/** |
|
1716 |
* Checks whether the given username exists. |
|
1717 |
* |
|
1718 |
* @since 2.0.0 |
|
1719 |
* |
|
1720 |
* @param string $username Username. |
|
1721 |
* @return null|int The user's ID on success, and null on failure. |
|
1722 |
*/ |
|
1723 |
function username_exists( $username ) { |
|
1724 |
if ( $user = get_user_by('login', $username ) ) { |
|
1725 |
return $user->ID; |
|
1726 |
} else { |
|
1727 |
return null; |
|
1728 |
} |
|
1729 |
} |
|
1730 |
|
|
1731 |
/** |
|
1732 |
* Checks whether the given email exists. |
|
1733 |
* |
|
1734 |
* @since 2.1.0 |
|
1735 |
* |
|
1736 |
* @param string $email Email. |
|
1737 |
* @return bool|int The user's ID on success, and false on failure. |
|
1738 |
*/ |
|
1739 |
function email_exists( $email ) { |
|
1740 |
if ( $user = get_user_by('email', $email) ) |
|
1741 |
return $user->ID; |
|
1742 |
|
|
1743 |
return false; |
|
1744 |
} |
|
1745 |
|
|
1746 |
/** |
5
|
1747 |
* Checks whether a username is valid. |
0
|
1748 |
* |
|
1749 |
* @since 2.0.1 |
|
1750 |
* |
|
1751 |
* @param string $username Username. |
|
1752 |
* @return bool Whether username given is valid |
|
1753 |
*/ |
|
1754 |
function validate_username( $username ) { |
|
1755 |
$sanitized = sanitize_user( $username, true ); |
|
1756 |
$valid = ( $sanitized == $username ); |
5
|
1757 |
/** |
|
1758 |
* Filter whether the provided username is valid or not. |
|
1759 |
* |
|
1760 |
* @since 2.0.1 |
|
1761 |
* |
|
1762 |
* @param bool $valid Whether given username is valid. |
|
1763 |
* @param string $username Username to check. |
|
1764 |
*/ |
0
|
1765 |
return apply_filters( 'validate_username', $valid, $username ); |
|
1766 |
} |
|
1767 |
|
|
1768 |
/** |
5
|
1769 |
* Insert a user into the database. |
0
|
1770 |
* |
|
1771 |
* Most of the $userdata array fields have filters associated with the values. |
|
1772 |
* The exceptions are 'rich_editing', 'role', 'jabber', 'aim', 'yim', |
|
1773 |
* 'user_registered', and 'ID'. The filters have the prefix 'pre_user_' followed |
|
1774 |
* by the field name. An example using 'description' would have the filter |
|
1775 |
* called, 'pre_user_description' that can be hooked into. |
|
1776 |
* |
5
|
1777 |
* @since 2.0.0 |
|
1778 |
* |
|
1779 |
* @global wpdb $wpdb WordPress database object for queries. |
|
1780 |
* |
|
1781 |
* @param array $userdata { |
|
1782 |
* An array, object, or WP_User object of user data arguments. |
0
|
1783 |
* |
5
|
1784 |
* @type int $ID User ID. If supplied, the user will be updated. |
|
1785 |
* @type string $user_pass The plain-text user password. |
|
1786 |
* @type string $user_login The user's login username. |
|
1787 |
* @type string $user_nicename The URL-friendly user name. |
|
1788 |
* @type string $user_url The user URL. |
|
1789 |
* @type string $user_email The user email address. |
|
1790 |
* @type string $display_name The user's display name. |
|
1791 |
* Default is the the user's username. |
|
1792 |
* @type string $nickname The user's nickname. Default |
|
1793 |
* Default is the the user's username. |
|
1794 |
* @type string $first_name The user's first name. For new users, will be used |
|
1795 |
* to build $display_name if unspecified. |
|
1796 |
* @type stirng $last_name The user's last name. For new users, will be used |
|
1797 |
* to build $display_name if unspecified. |
|
1798 |
* @type string|bool $rich_editing Whether to enable the rich-editor for the user. False |
|
1799 |
* if not empty. |
|
1800 |
* @type string $user_registered Date the user registered. Format is 'Y-m-d H:i:s'. |
|
1801 |
* @type string $role User's role. |
|
1802 |
* @type string $jabber User's Jabber account username. |
|
1803 |
* @type string $aim User's AIM account username. |
|
1804 |
* @type string $yim User's Yahoo! messenger username. |
|
1805 |
* } |
|
1806 |
* @return int|WP_Error The newly created user's ID or a WP_Error object if the user could not |
|
1807 |
* be created. |
0
|
1808 |
*/ |
|
1809 |
function wp_insert_user( $userdata ) { |
|
1810 |
global $wpdb; |
|
1811 |
|
5
|
1812 |
if ( $userdata instanceof stdClass ) { |
0
|
1813 |
$userdata = get_object_vars( $userdata ); |
5
|
1814 |
} elseif ( $userdata instanceof WP_User ) { |
0
|
1815 |
$userdata = $userdata->to_array(); |
5
|
1816 |
} |
0
|
1817 |
// Are we updating or creating? |
5
|
1818 |
if ( ! empty( $userdata['ID'] ) ) { |
|
1819 |
$ID = (int) $userdata['ID']; |
0
|
1820 |
$update = true; |
|
1821 |
$old_user_data = WP_User::get_data_by( 'id', $ID ); |
5
|
1822 |
// hashed in wp_update_user(), plaintext if called directly |
|
1823 |
$user_pass = $userdata['user_pass']; |
0
|
1824 |
} else { |
|
1825 |
$update = false; |
|
1826 |
// Hash the password |
5
|
1827 |
$user_pass = wp_hash_password( $userdata['user_pass'] ); |
0
|
1828 |
} |
|
1829 |
|
5
|
1830 |
$sanitized_user_login = sanitize_user( $userdata['user_login'], true ); |
|
1831 |
|
|
1832 |
/** |
|
1833 |
* Filter a username after it has been sanitized. |
|
1834 |
* |
|
1835 |
* This filter is called before the user is created or updated. |
|
1836 |
* |
|
1837 |
* @since 2.0.3 |
|
1838 |
* |
|
1839 |
* @param string $sanitized_user_login Username after it has been sanitized. |
|
1840 |
*/ |
|
1841 |
$pre_user_login = apply_filters( 'pre_user_login', $sanitized_user_login ); |
0
|
1842 |
|
|
1843 |
//Remove any non-printable chars from the login string to see if we have ended up with an empty username |
5
|
1844 |
$user_login = trim( $pre_user_login ); |
0
|
1845 |
|
5
|
1846 |
if ( empty( $user_login ) ) { |
0
|
1847 |
return new WP_Error('empty_user_login', __('Cannot create a user with an empty login name.') ); |
5
|
1848 |
} |
|
1849 |
if ( ! $update && username_exists( $user_login ) ) { |
|
1850 |
return new WP_Error( 'existing_user_login', __( 'Sorry, that username already exists!' ) ); |
|
1851 |
} |
0
|
1852 |
|
5
|
1853 |
// If a nicename is provided, remove unsafe user characters before |
|
1854 |
// using it. Otherwise build a nicename from the user_login. |
|
1855 |
if ( ! empty( $userdata['user_nicename'] ) ) { |
|
1856 |
$user_nicename = sanitize_user( $userdata['user_nicename'], true ); |
|
1857 |
} else { |
|
1858 |
$user_nicename = $user_login; |
|
1859 |
} |
|
1860 |
|
|
1861 |
$user_nicename = sanitize_title( $user_nicename ); |
|
1862 |
|
|
1863 |
// Store values to save in user meta. |
|
1864 |
$meta = array(); |
0
|
1865 |
|
5
|
1866 |
/** |
|
1867 |
* Filter a user's nicename before the user is created or updated. |
|
1868 |
* |
|
1869 |
* @since 2.0.3 |
|
1870 |
* |
|
1871 |
* @param string $user_nicename The user's nicename. |
|
1872 |
*/ |
|
1873 |
$user_nicename = apply_filters( 'pre_user_nicename', $user_nicename ); |
|
1874 |
|
|
1875 |
$raw_user_url = empty( $userdata['user_url'] ) ? '' : $userdata['user_url']; |
0
|
1876 |
|
5
|
1877 |
/** |
|
1878 |
* Filter a user's URL before the user is created or updated. |
|
1879 |
* |
|
1880 |
* @since 2.0.3 |
|
1881 |
* |
|
1882 |
* @param string $raw_user_url The user's URL. |
|
1883 |
*/ |
|
1884 |
$user_url = apply_filters( 'pre_user_url', $raw_user_url ); |
0
|
1885 |
|
5
|
1886 |
$raw_user_email = empty( $userdata['user_email'] ) ? '' : $userdata['user_email']; |
0
|
1887 |
|
5
|
1888 |
/** |
|
1889 |
* Filter a user's email before the user is created or updated. |
|
1890 |
* |
|
1891 |
* @since 2.0.3 |
|
1892 |
* |
|
1893 |
* @param string $raw_user_email The user's email. |
|
1894 |
*/ |
|
1895 |
$user_email = apply_filters( 'pre_user_email', $raw_user_email ); |
0
|
1896 |
|
5
|
1897 |
/* |
|
1898 |
* If there is no update, just check for `email_exists`. If there is an update, |
|
1899 |
* check if current email and new email are the same, or not, and check `email_exists` |
|
1900 |
* accordingly. |
|
1901 |
*/ |
|
1902 |
if ( ( ! $update || ( ! empty( $old_user_data ) && $user_email !== $old_user_data->user_email ) ) |
|
1903 |
&& ! defined( 'WP_IMPORTING' ) |
|
1904 |
&& email_exists( $user_email ) |
|
1905 |
) { |
|
1906 |
return new WP_Error( 'existing_user_email', __( 'Sorry, that email address is already used!' ) ); |
|
1907 |
} |
|
1908 |
$nickname = empty( $userdata['nickname'] ) ? $user_login : $userdata['nickname']; |
0
|
1909 |
|
5
|
1910 |
/** |
|
1911 |
* Filter a user's nickname before the user is created or updated. |
|
1912 |
* |
|
1913 |
* @since 2.0.3 |
|
1914 |
* |
|
1915 |
* @param string $nickname The user's nickname. |
|
1916 |
*/ |
|
1917 |
$meta['nickname'] = apply_filters( 'pre_user_nickname', $nickname ); |
0
|
1918 |
|
5
|
1919 |
$first_name = empty( $userdata['first_name'] ) ? '' : $userdata['first_name']; |
|
1920 |
|
|
1921 |
/** |
|
1922 |
* Filter a user's first name before the user is created or updated. |
|
1923 |
* |
|
1924 |
* @since 2.0.3 |
|
1925 |
* |
|
1926 |
* @param string $first_name The user's first name. |
|
1927 |
*/ |
|
1928 |
$meta['first_name'] = apply_filters( 'pre_user_first_name', $first_name ); |
0
|
1929 |
|
5
|
1930 |
$last_name = empty( $userdata['last_name'] ) ? '' : $userdata['last_name']; |
|
1931 |
|
|
1932 |
/** |
|
1933 |
* Filter a user's last name before the user is created or updated. |
|
1934 |
* |
|
1935 |
* @since 2.0.3 |
|
1936 |
* |
|
1937 |
* @param string $last_name The user's last name. |
|
1938 |
*/ |
|
1939 |
$meta['last_name'] = apply_filters( 'pre_user_last_name', $last_name ); |
|
1940 |
|
|
1941 |
if ( empty( $userdata['display_name'] ) ) { |
|
1942 |
if ( $update ) { |
0
|
1943 |
$display_name = $user_login; |
5
|
1944 |
} elseif ( $meta['first_name'] && $meta['last_name'] ) { |
0
|
1945 |
/* translators: 1: first name, 2: last name */ |
5
|
1946 |
$display_name = sprintf( _x( '%1$s %2$s', 'Display name based on first name and last name' ), $meta['first_name'], $meta['last_name'] ); |
|
1947 |
} elseif ( $meta['first_name'] ) { |
|
1948 |
$display_name = $meta['first_name']; |
|
1949 |
} elseif ( $meta['last_name'] ) { |
|
1950 |
$display_name = $meta['last_name']; |
|
1951 |
} else { |
0
|
1952 |
$display_name = $user_login; |
5
|
1953 |
} |
|
1954 |
} else { |
|
1955 |
$display_name = $userdata['display_name']; |
0
|
1956 |
} |
5
|
1957 |
|
|
1958 |
/** |
|
1959 |
* Filter a user's display name before the user is created or updated. |
|
1960 |
* |
|
1961 |
* @since 2.0.3 |
|
1962 |
* |
|
1963 |
* @param string $display_name The user's display name. |
|
1964 |
*/ |
0
|
1965 |
$display_name = apply_filters( 'pre_user_display_name', $display_name ); |
|
1966 |
|
5
|
1967 |
$description = empty( $userdata['description'] ) ? '' : $userdata['description']; |
0
|
1968 |
|
5
|
1969 |
/** |
|
1970 |
* Filter a user's description before the user is created or updated. |
|
1971 |
* |
|
1972 |
* @since 2.0.3 |
|
1973 |
* |
|
1974 |
* @param string $description The user's description. |
|
1975 |
*/ |
|
1976 |
$meta['description'] = apply_filters( 'pre_user_description', $description ); |
0
|
1977 |
|
5
|
1978 |
$meta['rich_editing'] = empty( $userdata['rich_editing'] ) ? 'true' : $userdata['rich_editing']; |
|
1979 |
|
|
1980 |
$meta['comment_shortcuts'] = empty( $userdata['comment_shortcuts'] ) ? 'false' : $userdata['comment_shortcuts']; |
0
|
1981 |
|
5
|
1982 |
$admin_color = empty( $userdata['admin_color'] ) ? 'fresh' : $userdata['admin_color']; |
|
1983 |
$meta['admin_color'] = preg_replace( '|[^a-z0-9 _.\-@]|i', '', $admin_color ); |
0
|
1984 |
|
5
|
1985 |
$meta['use_ssl'] = empty( $userdata['use_ssl'] ) ? 0 : $userdata['use_ssl']; |
0
|
1986 |
|
5
|
1987 |
$user_registered = empty( $userdata['user_registered'] ) ? gmdate( 'Y-m-d H:i:s' ) : $userdata['user_registered']; |
|
1988 |
|
|
1989 |
$meta['show_admin_bar_front'] = empty( $userdata['show_admin_bar_front'] ) ? 'true' : $userdata['show_admin_bar_front']; |
0
|
1990 |
|
|
1991 |
$user_nicename_check = $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1" , $user_nicename, $user_login)); |
|
1992 |
|
|
1993 |
if ( $user_nicename_check ) { |
|
1994 |
$suffix = 2; |
|
1995 |
while ($user_nicename_check) { |
|
1996 |
$alt_user_nicename = $user_nicename . "-$suffix"; |
|
1997 |
$user_nicename_check = $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1" , $alt_user_nicename, $user_login)); |
|
1998 |
$suffix++; |
|
1999 |
} |
|
2000 |
$user_nicename = $alt_user_nicename; |
|
2001 |
} |
|
2002 |
|
5
|
2003 |
$compacted = compact( 'user_pass', 'user_email', 'user_url', 'user_nicename', 'display_name', 'user_registered' ); |
|
2004 |
$data = wp_unslash( $compacted ); |
0
|
2005 |
|
|
2006 |
if ( $update ) { |
5
|
2007 |
if ( $user_email !== $old_user_data->user_email ) { |
|
2008 |
$data['user_activation_key'] = ''; |
|
2009 |
} |
0
|
2010 |
$wpdb->update( $wpdb->users, $data, compact( 'ID' ) ); |
|
2011 |
$user_id = (int) $ID; |
|
2012 |
} else { |
|
2013 |
$wpdb->insert( $wpdb->users, $data + compact( 'user_login' ) ); |
|
2014 |
$user_id = (int) $wpdb->insert_id; |
|
2015 |
} |
|
2016 |
|
|
2017 |
$user = new WP_User( $user_id ); |
|
2018 |
|
5
|
2019 |
// Update user meta. |
|
2020 |
foreach ( $meta as $key => $value ) { |
|
2021 |
update_user_meta( $user_id, $key, $value ); |
|
2022 |
} |
|
2023 |
|
|
2024 |
foreach ( wp_get_user_contact_methods( $user ) as $key => $value ) { |
|
2025 |
if ( isset( $userdata[ $key ] ) ) { |
|
2026 |
update_user_meta( $user_id, $key, $userdata[ $key ] ); |
|
2027 |
} |
0
|
2028 |
} |
|
2029 |
|
5
|
2030 |
if ( isset( $userdata['role'] ) ) { |
|
2031 |
$user->set_role( $userdata['role'] ); |
|
2032 |
} elseif ( ! $update ) { |
0
|
2033 |
$user->set_role(get_option('default_role')); |
5
|
2034 |
} |
|
2035 |
wp_cache_delete( $user_id, 'users' ); |
|
2036 |
wp_cache_delete( $user_login, 'userlogins' ); |
0
|
2037 |
|
5
|
2038 |
if ( $update ) { |
|
2039 |
/** |
|
2040 |
* Fires immediately after an existing user is updated. |
|
2041 |
* |
|
2042 |
* @since 2.0.0 |
|
2043 |
* |
|
2044 |
* @param int $user_id User ID. |
|
2045 |
* @param object $old_user_data Object containing user's data prior to update. |
|
2046 |
*/ |
|
2047 |
do_action( 'profile_update', $user_id, $old_user_data ); |
|
2048 |
} else { |
|
2049 |
/** |
|
2050 |
* Fires immediately after a new user is registered. |
|
2051 |
* |
|
2052 |
* @since 1.5.0 |
|
2053 |
* |
|
2054 |
* @param int $user_id User ID. |
|
2055 |
*/ |
|
2056 |
do_action( 'user_register', $user_id ); |
|
2057 |
} |
0
|
2058 |
|
|
2059 |
return $user_id; |
|
2060 |
} |
|
2061 |
|
|
2062 |
/** |
5
|
2063 |
* Update a user in the database. |
0
|
2064 |
* |
|
2065 |
* It is possible to update a user's password by specifying the 'user_pass' |
|
2066 |
* value in the $userdata parameter array. |
|
2067 |
* |
|
2068 |
* If current user's password is being updated, then the cookies will be |
|
2069 |
* cleared. |
|
2070 |
* |
|
2071 |
* @since 2.0.0 |
5
|
2072 |
* |
|
2073 |
* @see wp_insert_user() For what fields can be set in $userdata. |
0
|
2074 |
* |
|
2075 |
* @param mixed $userdata An array of user data or a user object of type stdClass or WP_User. |
|
2076 |
* @return int|WP_Error The updated user's ID or a WP_Error object if the user could not be updated. |
|
2077 |
*/ |
|
2078 |
function wp_update_user($userdata) { |
5
|
2079 |
if ( $userdata instanceof stdClass ) { |
0
|
2080 |
$userdata = get_object_vars( $userdata ); |
5
|
2081 |
} elseif ( $userdata instanceof WP_User ) { |
0
|
2082 |
$userdata = $userdata->to_array(); |
5
|
2083 |
} |
0
|
2084 |
|
5
|
2085 |
$ID = isset( $userdata['ID'] ) ? (int) $userdata['ID'] : 0; |
|
2086 |
if ( ! $ID ) { |
|
2087 |
return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) ); |
|
2088 |
} |
0
|
2089 |
|
|
2090 |
// First, get all of the original fields |
|
2091 |
$user_obj = get_userdata( $ID ); |
5
|
2092 |
if ( ! $user_obj ) { |
0
|
2093 |
return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) ); |
5
|
2094 |
} |
0
|
2095 |
|
|
2096 |
$user = $user_obj->to_array(); |
|
2097 |
|
|
2098 |
// Add additional custom fields |
|
2099 |
foreach ( _get_additional_user_keys( $user_obj ) as $key ) { |
|
2100 |
$user[ $key ] = get_user_meta( $ID, $key, true ); |
|
2101 |
} |
|
2102 |
|
|
2103 |
// Escape data pulled from DB. |
|
2104 |
$user = add_magic_quotes( $user ); |
|
2105 |
|
|
2106 |
// If password is changing, hash it now. |
|
2107 |
if ( ! empty($userdata['user_pass']) ) { |
|
2108 |
$plaintext_pass = $userdata['user_pass']; |
|
2109 |
$userdata['user_pass'] = wp_hash_password($userdata['user_pass']); |
|
2110 |
} |
|
2111 |
|
|
2112 |
wp_cache_delete($user[ 'user_email' ], 'useremail'); |
|
2113 |
|
|
2114 |
// Merge old and new fields with new fields overwriting old ones. |
|
2115 |
$userdata = array_merge($user, $userdata); |
|
2116 |
$user_id = wp_insert_user($userdata); |
|
2117 |
|
|
2118 |
// Update the cookies if the password changed. |
|
2119 |
$current_user = wp_get_current_user(); |
|
2120 |
if ( $current_user->ID == $ID ) { |
|
2121 |
if ( isset($plaintext_pass) ) { |
|
2122 |
wp_clear_auth_cookie(); |
5
|
2123 |
|
|
2124 |
// Here we calculate the expiration length of the current auth cookie and compare it to the default expiration. |
|
2125 |
// If it's greater than this, then we know the user checked 'Remember Me' when they logged in. |
|
2126 |
$logged_in_cookie = wp_parse_auth_cookie( '', 'logged_in' ); |
|
2127 |
/** This filter is documented in wp-includes/pluggable.php */ |
|
2128 |
$default_cookie_life = apply_filters( 'auth_cookie_expiration', ( 2 * DAY_IN_SECONDS ), $ID, false ); |
|
2129 |
$remember = ( ( $logged_in_cookie['expiration'] - time() ) > $default_cookie_life ); |
|
2130 |
|
|
2131 |
wp_set_auth_cookie( $ID, $remember ); |
0
|
2132 |
} |
|
2133 |
} |
|
2134 |
|
|
2135 |
return $user_id; |
|
2136 |
} |
|
2137 |
|
|
2138 |
/** |
5
|
2139 |
* A simpler way of inserting a user into the database. |
0
|
2140 |
* |
|
2141 |
* Creates a new user with just the username, password, and email. For more |
5
|
2142 |
* complex user creation use {@see wp_insert_user()} to specify more information. |
0
|
2143 |
* |
|
2144 |
* @since 2.0.0 |
|
2145 |
* @see wp_insert_user() More complete way to create a new user |
|
2146 |
* |
|
2147 |
* @param string $username The user's username. |
|
2148 |
* @param string $password The user's password. |
5
|
2149 |
* @param string $email Optional. The user's email. Default empty. |
0
|
2150 |
* @return int The new user's ID. |
|
2151 |
*/ |
|
2152 |
function wp_create_user($username, $password, $email = '') { |
|
2153 |
$user_login = wp_slash( $username ); |
|
2154 |
$user_email = wp_slash( $email ); |
|
2155 |
$user_pass = $password; |
|
2156 |
|
|
2157 |
$userdata = compact('user_login', 'user_email', 'user_pass'); |
|
2158 |
return wp_insert_user($userdata); |
|
2159 |
} |
|
2160 |
|
|
2161 |
/** |
|
2162 |
* Return a list of meta keys that wp_insert_user() is supposed to set. |
|
2163 |
* |
|
2164 |
* @since 3.3.0 |
|
2165 |
* @access private |
|
2166 |
* |
5
|
2167 |
* @param WP_User $user WP_User instance. |
0
|
2168 |
* @return array |
|
2169 |
*/ |
|
2170 |
function _get_additional_user_keys( $user ) { |
|
2171 |
$keys = array( 'first_name', 'last_name', 'nickname', 'description', 'rich_editing', 'comment_shortcuts', 'admin_color', 'use_ssl', 'show_admin_bar_front' ); |
|
2172 |
return array_merge( $keys, array_keys( wp_get_user_contact_methods( $user ) ) ); |
|
2173 |
} |
|
2174 |
|
|
2175 |
/** |
|
2176 |
* Set up the user contact methods. |
|
2177 |
* |
|
2178 |
* Default contact methods were removed in 3.6. A filter dictates contact methods. |
|
2179 |
* |
|
2180 |
* @since 3.7.0 |
|
2181 |
* |
|
2182 |
* @param WP_User $user Optional. WP_User object. |
|
2183 |
* @return array Array of contact methods and their labels. |
|
2184 |
*/ |
|
2185 |
function wp_get_user_contact_methods( $user = null ) { |
|
2186 |
$methods = array(); |
|
2187 |
if ( get_site_option( 'initial_db_version' ) < 23588 ) { |
|
2188 |
$methods = array( |
|
2189 |
'aim' => __( 'AIM' ), |
|
2190 |
'yim' => __( 'Yahoo IM' ), |
|
2191 |
'jabber' => __( 'Jabber / Google Talk' ) |
|
2192 |
); |
|
2193 |
} |
|
2194 |
|
|
2195 |
/** |
|
2196 |
* Filter the user contact methods. |
|
2197 |
* |
|
2198 |
* @since 2.9.0 |
|
2199 |
* |
|
2200 |
* @param array $methods Array of contact methods and their labels. |
5
|
2201 |
* @param WP_User $user WP_User object. |
0
|
2202 |
*/ |
|
2203 |
return apply_filters( 'user_contactmethods', $methods, $user ); |
|
2204 |
} |
|
2205 |
|
|
2206 |
/** |
|
2207 |
* The old private function for setting up user contact methods. |
|
2208 |
* |
|
2209 |
* @since 2.9.0 |
|
2210 |
* @access private |
|
2211 |
*/ |
|
2212 |
function _wp_get_user_contactmethods( $user = null ) { |
|
2213 |
return wp_get_user_contact_methods( $user ); |
|
2214 |
} |
|
2215 |
|
|
2216 |
/** |
5
|
2217 |
* Gets the text suggesting how to create strong passwords. |
|
2218 |
* |
|
2219 |
* @since 4.1.0 |
|
2220 |
* |
|
2221 |
* @return string The password hint text. |
|
2222 |
*/ |
|
2223 |
function wp_get_password_hint() { |
|
2224 |
$hint = __( 'Hint: The password should be at least seven characters long. To make it stronger, use upper and lower case letters, numbers, and symbols like ! " ? $ % ^ & ).' ); |
|
2225 |
|
|
2226 |
/** |
|
2227 |
* Filter the text describing the site's password complexity policy. |
|
2228 |
* |
|
2229 |
* @since 4.1.0 |
|
2230 |
* |
|
2231 |
* @param string $hint The password hint text. |
|
2232 |
*/ |
|
2233 |
return apply_filters( 'password_hint', $hint ); |
|
2234 |
} |
|
2235 |
|
|
2236 |
/** |
0
|
2237 |
* Retrieves a user row based on password reset key and login |
|
2238 |
* |
|
2239 |
* A key is considered 'expired' if it exactly matches the value of the |
|
2240 |
* user_activation_key field, rather than being matched after going through the |
|
2241 |
* hashing process. This field is now hashed; old values are no longer accepted |
|
2242 |
* but have a different WP_Error code so good user feedback can be provided. |
|
2243 |
* |
5
|
2244 |
* @global wpdb $wpdb WordPress database object for queries. |
|
2245 |
* @global PasswordHash $wp_hasher Portable PHP password hashing framework instance. |
0
|
2246 |
* |
|
2247 |
* @param string $key Hash to validate sending user's password. |
|
2248 |
* @param string $login The user login. |
|
2249 |
* @return WP_User|WP_Error WP_User object on success, WP_Error object for invalid or expired keys. |
|
2250 |
*/ |
|
2251 |
function check_password_reset_key($key, $login) { |
|
2252 |
global $wpdb, $wp_hasher; |
|
2253 |
|
|
2254 |
$key = preg_replace('/[^a-z0-9]/i', '', $key); |
|
2255 |
|
|
2256 |
if ( empty( $key ) || !is_string( $key ) ) |
|
2257 |
return new WP_Error('invalid_key', __('Invalid key')); |
|
2258 |
|
|
2259 |
if ( empty($login) || !is_string($login) ) |
|
2260 |
return new WP_Error('invalid_key', __('Invalid key')); |
|
2261 |
|
|
2262 |
$row = $wpdb->get_row( $wpdb->prepare( "SELECT ID, user_activation_key FROM $wpdb->users WHERE user_login = %s", $login ) ); |
|
2263 |
if ( ! $row ) |
|
2264 |
return new WP_Error('invalid_key', __('Invalid key')); |
|
2265 |
|
|
2266 |
if ( empty( $wp_hasher ) ) { |
5
|
2267 |
require_once ABSPATH . WPINC . '/class-phpass.php'; |
0
|
2268 |
$wp_hasher = new PasswordHash( 8, true ); |
|
2269 |
} |
|
2270 |
|
|
2271 |
if ( $wp_hasher->CheckPassword( $key, $row->user_activation_key ) ) |
|
2272 |
return get_userdata( $row->ID ); |
|
2273 |
|
|
2274 |
if ( $key === $row->user_activation_key ) { |
|
2275 |
$return = new WP_Error( 'expired_key', __( 'Invalid key' ) ); |
|
2276 |
$user_id = $row->ID; |
|
2277 |
|
|
2278 |
/** |
|
2279 |
* Filter the return value of check_password_reset_key() when an |
|
2280 |
* old-style key is used (plain-text key was stored in the database). |
|
2281 |
* |
|
2282 |
* @since 3.7.0 |
|
2283 |
* |
|
2284 |
* @param WP_Error $return A WP_Error object denoting an expired key. |
|
2285 |
* Return a WP_User object to validate the key. |
|
2286 |
* @param int $user_id The matched user ID. |
|
2287 |
*/ |
|
2288 |
return apply_filters( 'password_reset_key_expired', $return, $user_id ); |
|
2289 |
} |
|
2290 |
|
|
2291 |
return new WP_Error( 'invalid_key', __( 'Invalid key' ) ); |
|
2292 |
} |
|
2293 |
|
|
2294 |
/** |
|
2295 |
* Handles resetting the user's password. |
|
2296 |
* |
|
2297 |
* @param object $user The user |
|
2298 |
* @param string $new_pass New password for the user in plaintext |
|
2299 |
*/ |
|
2300 |
function reset_password( $user, $new_pass ) { |
5
|
2301 |
/** |
|
2302 |
* Fires before the user's password is reset. |
|
2303 |
* |
|
2304 |
* @since 1.5.0 |
|
2305 |
* |
|
2306 |
* @param object $user The user. |
|
2307 |
* @param string $new_pass New user password. |
|
2308 |
*/ |
0
|
2309 |
do_action( 'password_reset', $user, $new_pass ); |
|
2310 |
|
|
2311 |
wp_set_password( $new_pass, $user->ID ); |
|
2312 |
update_user_option( $user->ID, 'default_password_nag', false, true ); |
|
2313 |
|
|
2314 |
wp_password_change_notification( $user ); |
|
2315 |
} |
|
2316 |
|
|
2317 |
/** |
|
2318 |
* Handles registering a new user. |
|
2319 |
* |
|
2320 |
* @param string $user_login User's username for logging in |
|
2321 |
* @param string $user_email User's email address to send password and add |
|
2322 |
* @return int|WP_Error Either user's ID or error on failure. |
|
2323 |
*/ |
|
2324 |
function register_new_user( $user_login, $user_email ) { |
|
2325 |
$errors = new WP_Error(); |
|
2326 |
|
|
2327 |
$sanitized_user_login = sanitize_user( $user_login ); |
5
|
2328 |
/** |
|
2329 |
* Filter the email address of a user being registered. |
|
2330 |
* |
|
2331 |
* @since 2.1.0 |
|
2332 |
* |
|
2333 |
* @param string $user_email The email address of the new user. |
|
2334 |
*/ |
0
|
2335 |
$user_email = apply_filters( 'user_registration_email', $user_email ); |
|
2336 |
|
|
2337 |
// Check the username |
|
2338 |
if ( $sanitized_user_login == '' ) { |
|
2339 |
$errors->add( 'empty_username', __( '<strong>ERROR</strong>: Please enter a username.' ) ); |
|
2340 |
} elseif ( ! validate_username( $user_login ) ) { |
|
2341 |
$errors->add( 'invalid_username', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' ) ); |
|
2342 |
$sanitized_user_login = ''; |
|
2343 |
} elseif ( username_exists( $sanitized_user_login ) ) { |
|
2344 |
$errors->add( 'username_exists', __( '<strong>ERROR</strong>: This username is already registered. Please choose another one.' ) ); |
|
2345 |
} |
|
2346 |
|
|
2347 |
// Check the e-mail address |
|
2348 |
if ( $user_email == '' ) { |
|
2349 |
$errors->add( 'empty_email', __( '<strong>ERROR</strong>: Please type your e-mail address.' ) ); |
|
2350 |
} elseif ( ! is_email( $user_email ) ) { |
|
2351 |
$errors->add( 'invalid_email', __( '<strong>ERROR</strong>: The email address isn’t correct.' ) ); |
|
2352 |
$user_email = ''; |
|
2353 |
} elseif ( email_exists( $user_email ) ) { |
|
2354 |
$errors->add( 'email_exists', __( '<strong>ERROR</strong>: This email is already registered, please choose another one.' ) ); |
|
2355 |
} |
|
2356 |
|
5
|
2357 |
/** |
|
2358 |
* Fires when submitting registration form data, before the user is created. |
|
2359 |
* |
|
2360 |
* @since 2.1.0 |
|
2361 |
* |
|
2362 |
* @param string $sanitized_user_login The submitted username after being sanitized. |
|
2363 |
* @param string $user_email The submitted email. |
|
2364 |
* @param WP_Error $errors Contains any errors with submitted username and email, |
|
2365 |
* e.g., an empty field, an invalid username or email, |
|
2366 |
* or an existing username or email. |
|
2367 |
*/ |
0
|
2368 |
do_action( 'register_post', $sanitized_user_login, $user_email, $errors ); |
|
2369 |
|
5
|
2370 |
/** |
|
2371 |
* Filter the errors encountered when a new user is being registered. |
|
2372 |
* |
|
2373 |
* The filtered WP_Error object may, for example, contain errors for an invalid |
|
2374 |
* or existing username or email address. A WP_Error object should always returned, |
|
2375 |
* but may or may not contain errors. |
|
2376 |
* |
|
2377 |
* If any errors are present in $errors, this will abort the user's registration. |
|
2378 |
* |
|
2379 |
* @since 2.1.0 |
|
2380 |
* |
|
2381 |
* @param WP_Error $errors A WP_Error object containing any errors encountered |
|
2382 |
* during registration. |
|
2383 |
* @param string $sanitized_user_login User's username after it has been sanitized. |
|
2384 |
* @param string $user_email User's email. |
|
2385 |
*/ |
0
|
2386 |
$errors = apply_filters( 'registration_errors', $errors, $sanitized_user_login, $user_email ); |
|
2387 |
|
|
2388 |
if ( $errors->get_error_code() ) |
|
2389 |
return $errors; |
|
2390 |
|
|
2391 |
$user_pass = wp_generate_password( 12, false ); |
|
2392 |
$user_id = wp_create_user( $sanitized_user_login, $user_pass, $user_email ); |
|
2393 |
if ( ! $user_id || is_wp_error( $user_id ) ) { |
|
2394 |
$errors->add( 'registerfail', sprintf( __( '<strong>ERROR</strong>: Couldn’t register you… please contact the <a href="mailto:%s">webmaster</a> !' ), get_option( 'admin_email' ) ) ); |
|
2395 |
return $errors; |
|
2396 |
} |
|
2397 |
|
|
2398 |
update_user_option( $user_id, 'default_password_nag', true, true ); //Set up the Password change nag. |
|
2399 |
|
|
2400 |
wp_new_user_notification( $user_id, $user_pass ); |
|
2401 |
|
|
2402 |
return $user_id; |
|
2403 |
} |
5
|
2404 |
|
|
2405 |
/** |
|
2406 |
* Retrieve the current session token from the logged_in cookie. |
|
2407 |
* |
|
2408 |
* @since 4.0.0 |
|
2409 |
* |
|
2410 |
* @return string Token. |
|
2411 |
*/ |
|
2412 |
function wp_get_session_token() { |
|
2413 |
$cookie = wp_parse_auth_cookie( '', 'logged_in' ); |
|
2414 |
return ! empty( $cookie['token'] ) ? $cookie['token'] : ''; |
|
2415 |
} |
|
2416 |
|
|
2417 |
/** |
|
2418 |
* Retrieve a list of sessions for the current user. |
|
2419 |
* |
|
2420 |
* @since 4.0.0 |
|
2421 |
* @return array Array of sessions. |
|
2422 |
*/ |
|
2423 |
function wp_get_all_sessions() { |
|
2424 |
$manager = WP_Session_Tokens::get_instance( get_current_user_id() ); |
|
2425 |
return $manager->get_all(); |
|
2426 |
} |
|
2427 |
|
|
2428 |
/** |
|
2429 |
* Remove the current session token from the database. |
|
2430 |
* |
|
2431 |
* @since 4.0.0 |
|
2432 |
*/ |
|
2433 |
function wp_destroy_current_session() { |
|
2434 |
$token = wp_get_session_token(); |
|
2435 |
if ( $token ) { |
|
2436 |
$manager = WP_Session_Tokens::get_instance( get_current_user_id() ); |
|
2437 |
$manager->destroy( $token ); |
|
2438 |
} |
|
2439 |
} |
|
2440 |
|
|
2441 |
/** |
|
2442 |
* Remove all but the current session token for the current user for the database. |
|
2443 |
* |
|
2444 |
* @since 4.0.0 |
|
2445 |
*/ |
|
2446 |
function wp_destroy_other_sessions() { |
|
2447 |
$token = wp_get_session_token(); |
|
2448 |
if ( $token ) { |
|
2449 |
$manager = WP_Session_Tokens::get_instance( get_current_user_id() ); |
|
2450 |
$manager->destroy_others( $token ); |
|
2451 |
} |
|
2452 |
} |
|
2453 |
|
|
2454 |
/** |
|
2455 |
* Remove all session tokens for the current user from the database. |
|
2456 |
* |
|
2457 |
* @since 4.0.0 |
|
2458 |
*/ |
|
2459 |
function wp_destroy_all_sessions() { |
|
2460 |
$manager = WP_Session_Tokens::get_instance( get_current_user_id() ); |
|
2461 |
$manager->destroy_all(); |
|
2462 |
} |