WordPress 4.7
[autoinstalls/wordpress.git] / wp-admin / includes / user.php
1 <?php
2 /**
3  * WordPress user administration API.
4  *
5  * @package WordPress
6  * @subpackage Administration
7  */
8
9 /**
10  * Creates a new user from the "Users" form using $_POST information.
11  *
12  * @since 2.0.0
13  *
14  * @return int|WP_Error WP_Error or User ID.
15  */
16 function add_user() {
17         return edit_user();
18 }
19
20 /**
21  * Edit user settings based on contents of $_POST
22  *
23  * Used on user-edit.php and profile.php to manage and process user options, passwords etc.
24  *
25  * @since 2.0.0
26  *
27  * @param int $user_id Optional. User ID.
28  * @return int|WP_Error user id of the updated user
29  */
30 function edit_user( $user_id = 0 ) {
31         $wp_roles = wp_roles();
32         $user = new stdClass;
33         if ( $user_id ) {
34                 $update = true;
35                 $user->ID = (int) $user_id;
36                 $userdata = get_userdata( $user_id );
37                 $user->user_login = wp_slash( $userdata->user_login );
38         } else {
39                 $update = false;
40         }
41
42         if ( !$update && isset( $_POST['user_login'] ) )
43                 $user->user_login = sanitize_user($_POST['user_login'], true);
44
45         $pass1 = $pass2 = '';
46         if ( isset( $_POST['pass1'] ) )
47                 $pass1 = $_POST['pass1'];
48         if ( isset( $_POST['pass2'] ) )
49                 $pass2 = $_POST['pass2'];
50
51         if ( isset( $_POST['role'] ) && current_user_can( 'edit_users' ) ) {
52                 $new_role = sanitize_text_field( $_POST['role'] );
53                 $potential_role = isset($wp_roles->role_objects[$new_role]) ? $wp_roles->role_objects[$new_role] : false;
54                 // Don't let anyone with 'edit_users' (admins) edit their own role to something without it.
55                 // Multisite super admins can freely edit their blog roles -- they possess all caps.
56                 if ( ( is_multisite() && current_user_can( 'manage_sites' ) ) || $user_id != get_current_user_id() || ($potential_role && $potential_role->has_cap( 'edit_users' ) ) )
57                         $user->role = $new_role;
58
59                 // If the new role isn't editable by the logged-in user die with error
60                 $editable_roles = get_editable_roles();
61                 if ( ! empty( $new_role ) && empty( $editable_roles[$new_role] ) )
62                         wp_die(__('You can&#8217;t give users that role.'));
63         }
64
65         if ( isset( $_POST['email'] ))
66                 $user->user_email = sanitize_text_field( wp_unslash( $_POST['email'] ) );
67         if ( isset( $_POST['url'] ) ) {
68                 if ( empty ( $_POST['url'] ) || $_POST['url'] == 'http://' ) {
69                         $user->user_url = '';
70                 } else {
71                         $user->user_url = esc_url_raw( $_POST['url'] );
72                         $protocols = implode( '|', array_map( 'preg_quote', wp_allowed_protocols() ) );
73                         $user->user_url = preg_match('/^(' . $protocols . '):/is', $user->user_url) ? $user->user_url : 'http://'.$user->user_url;
74                 }
75         }
76         if ( isset( $_POST['first_name'] ) )
77                 $user->first_name = sanitize_text_field( $_POST['first_name'] );
78         if ( isset( $_POST['last_name'] ) )
79                 $user->last_name = sanitize_text_field( $_POST['last_name'] );
80         if ( isset( $_POST['nickname'] ) )
81                 $user->nickname = sanitize_text_field( $_POST['nickname'] );
82         if ( isset( $_POST['display_name'] ) )
83                 $user->display_name = sanitize_text_field( $_POST['display_name'] );
84
85         if ( isset( $_POST['description'] ) )
86                 $user->description = trim( $_POST['description'] );
87
88         foreach ( wp_get_user_contact_methods( $user ) as $method => $name ) {
89                 if ( isset( $_POST[$method] ))
90                         $user->$method = sanitize_text_field( $_POST[$method] );
91         }
92
93         if ( $update ) {
94                 $user->rich_editing = isset( $_POST['rich_editing'] ) && 'false' == $_POST['rich_editing'] ? 'false' : 'true';
95                 $user->admin_color = isset( $_POST['admin_color'] ) ? sanitize_text_field( $_POST['admin_color'] ) : 'fresh';
96                 $user->show_admin_bar_front = isset( $_POST['admin_bar_front'] ) ? 'true' : 'false';
97                 $user->locale = '';
98
99                 if ( isset( $_POST['locale'] ) ) {
100                         $locale = sanitize_text_field( $_POST['locale'] );
101                         if ( 'site-default' === $locale ) {
102                                 $locale = '';
103                         } elseif ( '' === $locale ) {
104                                 $locale = 'en_US';
105                         } elseif ( ! in_array( $locale, get_available_languages(), true ) ) {
106                                 $locale = '';
107                         }
108
109                         $user->locale = $locale;
110                 }
111         }
112
113         $user->comment_shortcuts = isset( $_POST['comment_shortcuts'] ) && 'true' == $_POST['comment_shortcuts'] ? 'true' : '';
114
115         $user->use_ssl = 0;
116         if ( !empty($_POST['use_ssl']) )
117                 $user->use_ssl = 1;
118
119         $errors = new WP_Error();
120
121         /* checking that username has been typed */
122         if ( $user->user_login == '' )
123                 $errors->add( 'user_login', __( '<strong>ERROR</strong>: Please enter a username.' ) );
124
125         /* checking that nickname has been typed */
126         if ( $update && empty( $user->nickname ) ) {
127                 $errors->add( 'nickname', __( '<strong>ERROR</strong>: Please enter a nickname.' ) );
128         }
129
130         /**
131          * Fires before the password and confirm password fields are checked for congruity.
132          *
133          * @since 1.5.1
134          *
135          * @param string $user_login The username.
136          * @param string &$pass1     The password, passed by reference.
137          * @param string &$pass2     The confirmed password, passed by reference.
138          */
139         do_action_ref_array( 'check_passwords', array( $user->user_login, &$pass1, &$pass2 ) );
140
141         // Check for blank password when adding a user.
142         if ( ! $update && empty( $pass1 ) ) {
143                 $errors->add( 'pass', __( '<strong>ERROR</strong>: Please enter a password.' ), array( 'form-field' => 'pass1' ) );
144         }
145
146         // Check for "\" in password.
147         if ( false !== strpos( wp_unslash( $pass1 ), "\\" ) ) {
148                 $errors->add( 'pass', __( '<strong>ERROR</strong>: Passwords may not contain the character "\\".' ), array( 'form-field' => 'pass1' ) );
149         }
150
151         // Checking the password has been typed twice the same.
152         if ( ( $update || ! empty( $pass1 ) ) && $pass1 != $pass2 ) {
153                 $errors->add( 'pass', __( '<strong>ERROR</strong>: Please enter the same password in both password fields.' ), array( 'form-field' => 'pass1' ) );
154         }
155
156         if ( !empty( $pass1 ) )
157                 $user->user_pass = $pass1;
158
159         if ( !$update && isset( $_POST['user_login'] ) && !validate_username( $_POST['user_login'] ) )
160                 $errors->add( 'user_login', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' ));
161
162         if ( !$update && username_exists( $user->user_login ) )
163                 $errors->add( 'user_login', __( '<strong>ERROR</strong>: This username is already registered. Please choose another one.' ));
164
165         /** This filter is documented in wp-includes/user.php */
166         $illegal_logins = (array) apply_filters( 'illegal_user_logins', array() );
167
168         if ( in_array( strtolower( $user->user_login ), array_map( 'strtolower', $illegal_logins ) ) ) {
169                 $errors->add( 'invalid_username', __( '<strong>ERROR</strong>: Sorry, that username is not allowed.' ) );
170         }
171
172         /* checking email address */
173         if ( empty( $user->user_email ) ) {
174                 $errors->add( 'empty_email', __( '<strong>ERROR</strong>: Please enter an email address.' ), array( 'form-field' => 'email' ) );
175         } elseif ( !is_email( $user->user_email ) ) {
176                 $errors->add( 'invalid_email', __( '<strong>ERROR</strong>: The email address isn&#8217;t correct.' ), array( 'form-field' => 'email' ) );
177         } elseif ( ( $owner_id = email_exists($user->user_email) ) && ( !$update || ( $owner_id != $user->ID ) ) ) {
178                 $errors->add( 'email_exists', __('<strong>ERROR</strong>: This email is already registered, please choose another one.'), array( 'form-field' => 'email' ) );
179         }
180
181         /**
182          * Fires before user profile update errors are returned.
183          *
184          * @since 2.8.0
185          *
186          * @param WP_Error &$errors WP_Error object, passed by reference.
187          * @param bool     $update  Whether this is a user update.
188          * @param stdClass &$user   User object, passed by reference.
189          */
190         do_action_ref_array( 'user_profile_update_errors', array( &$errors, $update, &$user ) );
191
192         if ( $errors->get_error_codes() )
193                 return $errors;
194
195         if ( $update ) {
196                 $user_id = wp_update_user( $user );
197         } else {
198                 $user_id = wp_insert_user( $user );
199                 $notify  = isset( $_POST['send_user_notification'] ) ? 'both' : 'admin';
200
201                 /**
202                   * Fires after a new user has been created.
203                   *
204                   * @since 4.4.0
205                   *
206                   * @param int    $user_id ID of the newly created user.
207                   * @param string $notify  Type of notification that should happen. See wp_send_new_user_notifications()
208                   *                        for more information on possible values.
209                   */
210                 do_action( 'edit_user_created_user', $user_id, $notify );
211         }
212         return $user_id;
213 }
214
215 /**
216  * Fetch a filtered list of user roles that the current user is
217  * allowed to edit.
218  *
219  * Simple function who's main purpose is to allow filtering of the
220  * list of roles in the $wp_roles object so that plugins can remove
221  * inappropriate ones depending on the situation or user making edits.
222  * Specifically because without filtering anyone with the edit_users
223  * capability can edit others to be administrators, even if they are
224  * only editors or authors. This filter allows admins to delegate
225  * user management.
226  *
227  * @since 2.8.0
228  *
229  * @return array
230  */
231 function get_editable_roles() {
232         $all_roles = wp_roles()->roles;
233
234         /**
235          * Filters the list of editable roles.
236          *
237          * @since 2.8.0
238          *
239          * @param array $all_roles List of roles.
240          */
241         $editable_roles = apply_filters( 'editable_roles', $all_roles );
242
243         return $editable_roles;
244 }
245
246 /**
247  * Retrieve user data and filter it.
248  *
249  * @since 2.0.5
250  *
251  * @param int $user_id User ID.
252  * @return WP_User|bool WP_User object on success, false on failure.
253  */
254 function get_user_to_edit( $user_id ) {
255         $user = get_userdata( $user_id );
256
257         if ( $user )
258                 $user->filter = 'edit';
259
260         return $user;
261 }
262
263 /**
264  * Retrieve the user's drafts.
265  *
266  * @since 2.0.0
267  *
268  * @global wpdb $wpdb WordPress database abstraction object.
269  *
270  * @param int $user_id User ID.
271  * @return array
272  */
273 function get_users_drafts( $user_id ) {
274         global $wpdb;
275         $query = $wpdb->prepare("SELECT ID, post_title FROM $wpdb->posts WHERE post_type = 'post' AND post_status = 'draft' AND post_author = %d ORDER BY post_modified DESC", $user_id);
276
277         /**
278          * Filters the user's drafts query string.
279          *
280          * @since 2.0.0
281          *
282          * @param string $query The user's drafts query string.
283          */
284         $query = apply_filters( 'get_users_drafts', $query );
285         return $wpdb->get_results( $query );
286 }
287
288 /**
289  * Remove user and optionally reassign posts and links to another user.
290  *
291  * If the $reassign parameter is not assigned to a User ID, then all posts will
292  * be deleted of that user. The action {@see 'delete_user'} that is passed the User ID
293  * being deleted will be run after the posts are either reassigned or deleted.
294  * The user meta will also be deleted that are for that User ID.
295  *
296  * @since 2.0.0
297  *
298  * @global wpdb $wpdb WordPress database abstraction object.
299  *
300  * @param int $id User ID.
301  * @param int $reassign Optional. Reassign posts and links to new User ID.
302  * @return bool True when finished.
303  */
304 function wp_delete_user( $id, $reassign = null ) {
305         global $wpdb;
306
307         if ( ! is_numeric( $id ) ) {
308                 return false;
309         }
310
311         $id = (int) $id;
312         $user = new WP_User( $id );
313
314         if ( !$user->exists() )
315                 return false;
316
317         // Normalize $reassign to null or a user ID. 'novalue' was an older default.
318         if ( 'novalue' === $reassign ) {
319                 $reassign = null;
320         } elseif ( null !== $reassign ) {
321                 $reassign = (int) $reassign;
322         }
323
324         /**
325          * Fires immediately before a user is deleted from the database.
326          *
327          * @since 2.0.0
328          *
329          * @param int      $id       ID of the user to delete.
330          * @param int|null $reassign ID of the user to reassign posts and links to.
331          *                           Default null, for no reassignment.
332          */
333         do_action( 'delete_user', $id, $reassign );
334
335         if ( null === $reassign ) {
336                 $post_types_to_delete = array();
337                 foreach ( get_post_types( array(), 'objects' ) as $post_type ) {
338                         if ( $post_type->delete_with_user ) {
339                                 $post_types_to_delete[] = $post_type->name;
340                         } elseif ( null === $post_type->delete_with_user && post_type_supports( $post_type->name, 'author' ) ) {
341                                 $post_types_to_delete[] = $post_type->name;
342                         }
343                 }
344
345                 /**
346                  * Filters the list of post types to delete with a user.
347                  *
348                  * @since 3.4.0
349                  *
350                  * @param array $post_types_to_delete Post types to delete.
351                  * @param int   $id                   User ID.
352                  */
353                 $post_types_to_delete = apply_filters( 'post_types_to_delete_with_user', $post_types_to_delete, $id );
354                 $post_types_to_delete = implode( "', '", $post_types_to_delete );
355                 $post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_author = %d AND post_type IN ('$post_types_to_delete')", $id ) );
356                 if ( $post_ids ) {
357                         foreach ( $post_ids as $post_id )
358                                 wp_delete_post( $post_id );
359                 }
360
361                 // Clean links
362                 $link_ids = $wpdb->get_col( $wpdb->prepare("SELECT link_id FROM $wpdb->links WHERE link_owner = %d", $id) );
363
364                 if ( $link_ids ) {
365                         foreach ( $link_ids as $link_id )
366                                 wp_delete_link($link_id);
367                 }
368         } else {
369                 $post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_author = %d", $id ) );
370                 $wpdb->update( $wpdb->posts, array('post_author' => $reassign), array('post_author' => $id) );
371                 if ( ! empty( $post_ids ) ) {
372                         foreach ( $post_ids as $post_id )
373                                 clean_post_cache( $post_id );
374                 }
375                 $link_ids = $wpdb->get_col( $wpdb->prepare("SELECT link_id FROM $wpdb->links WHERE link_owner = %d", $id) );
376                 $wpdb->update( $wpdb->links, array('link_owner' => $reassign), array('link_owner' => $id) );
377                 if ( ! empty( $link_ids ) ) {
378                         foreach ( $link_ids as $link_id )
379                                 clean_bookmark_cache( $link_id );
380                 }
381         }
382
383         // FINALLY, delete user
384         if ( is_multisite() ) {
385                 remove_user_from_blog( $id, get_current_blog_id() );
386         } else {
387                 $meta = $wpdb->get_col( $wpdb->prepare( "SELECT umeta_id FROM $wpdb->usermeta WHERE user_id = %d", $id ) );
388                 foreach ( $meta as $mid )
389                         delete_metadata_by_mid( 'user', $mid );
390
391                 $wpdb->delete( $wpdb->users, array( 'ID' => $id ) );
392         }
393
394         clean_user_cache( $user );
395
396         /**
397          * Fires immediately after a user is deleted from the database.
398          *
399          * @since 2.9.0
400          *
401          * @param int      $id       ID of the deleted user.
402          * @param int|null $reassign ID of the user to reassign posts and links to.
403          *                           Default null, for no reassignment.
404          */
405         do_action( 'deleted_user', $id, $reassign );
406
407         return true;
408 }
409
410 /**
411  * Remove all capabilities from user.
412  *
413  * @since 2.1.0
414  *
415  * @param int $id User ID.
416  */
417 function wp_revoke_user($id) {
418         $id = (int) $id;
419
420         $user = new WP_User($id);
421         $user->remove_all_caps();
422 }
423
424 /**
425  * @since 2.8.0
426  *
427  * @global int $user_ID
428  *
429  * @param false $errors Deprecated.
430  */
431 function default_password_nag_handler($errors = false) {
432         global $user_ID;
433         // Short-circuit it.
434         if ( ! get_user_option('default_password_nag') )
435                 return;
436
437         // get_user_setting = JS saved UI setting. else no-js-fallback code.
438         if ( 'hide' == get_user_setting('default_password_nag') || isset($_GET['default_password_nag']) && '0' == $_GET['default_password_nag'] ) {
439                 delete_user_setting('default_password_nag');
440                 update_user_option($user_ID, 'default_password_nag', false, true);
441         }
442 }
443
444 /**
445  * @since 2.8.0
446  *
447  * @param int    $user_ID
448  * @param object $old_data
449  */
450 function default_password_nag_edit_user($user_ID, $old_data) {
451         // Short-circuit it.
452         if ( ! get_user_option('default_password_nag', $user_ID) )
453                 return;
454
455         $new_data = get_userdata($user_ID);
456
457         // Remove the nag if the password has been changed.
458         if ( $new_data->user_pass != $old_data->user_pass ) {
459                 delete_user_setting('default_password_nag');
460                 update_user_option($user_ID, 'default_password_nag', false, true);
461         }
462 }
463
464 /**
465  * @since 2.8.0
466  *
467  * @global string $pagenow
468  */
469 function default_password_nag() {
470         global $pagenow;
471         // Short-circuit it.
472         if ( 'profile.php' == $pagenow || ! get_user_option('default_password_nag') )
473                 return;
474
475         echo '<div class="error default-password-nag">';
476         echo '<p>';
477         echo '<strong>' . __('Notice:') . '</strong> ';
478         _e('You&rsquo;re using the auto-generated password for your account. Would you like to change it?');
479         echo '</p><p>';
480         printf( '<a href="%s">' . __('Yes, take me to my profile page') . '</a> | ', get_edit_profile_url() . '#password' );
481         printf( '<a href="%s" id="default-password-nag-no">' . __('No thanks, do not remind me again') . '</a>', '?default_password_nag=0' );
482         echo '</p></div>';
483 }
484
485 /**
486  * @since 3.5.0
487  * @access private
488  */
489 function delete_users_add_js() { ?>
490 <script>
491 jQuery(document).ready( function($) {
492         var submit = $('#submit').prop('disabled', true);
493         $('input[name="delete_option"]').one('change', function() {
494                 submit.prop('disabled', false);
495         });
496         $('#reassign_user').focus( function() {
497                 $('#delete_option1').prop('checked', true).trigger('change');
498         });
499 });
500 </script>
501 <?php
502 }
503
504 /**
505  * Optional SSL preference that can be turned on by hooking to the 'personal_options' action.
506  *
507  * See the {@see 'personal_options'} action.
508  *
509  * @since 2.7.0
510  *
511  * @param object $user User data object
512  */
513 function use_ssl_preference($user) {
514 ?>
515         <tr class="user-use-ssl-wrap">
516                 <th scope="row"><?php _e('Use https')?></th>
517                 <td><label for="use_ssl"><input name="use_ssl" type="checkbox" id="use_ssl" value="1" <?php checked('1', $user->use_ssl); ?> /> <?php _e('Always use https when visiting the admin'); ?></label></td>
518         </tr>
519 <?php
520 }
521
522 /**
523  *
524  * @param string $text
525  * @return string
526  */
527 function admin_created_user_email( $text ) {
528         $roles = get_editable_roles();
529         $role = $roles[ $_REQUEST['role'] ];
530         /* translators: 1: Site name, 2: site URL, 3: role */
531         return sprintf( __( 'Hi,
532 You\'ve been invited to join \'%1$s\' at
533 %2$s with the role of %3$s.
534 If you do not want to join this site please ignore
535 this email. This invitation will expire in a few days.
536
537 Please click the following link to activate your user account:
538 %%s' ), get_bloginfo( 'name' ), home_url(), wp_specialchars_decode( translate_user_role( $role['name'] ) ) );
539 }