+ * @param WP_User|int $user User object or ID to be cleaned from the cache
+ */
+function clean_user_cache( $user ) {
+ if ( is_numeric( $user ) )
+ $user = new WP_User( $user );
+
+ if ( ! $user->exists() )
+ return;
+
+ wp_cache_delete( $user->ID, 'users' );
+ wp_cache_delete( $user->user_login, 'userlogins' );
+ wp_cache_delete( $user->user_email, 'useremail' );
+ wp_cache_delete( $user->user_nicename, 'userslugs' );
+}
+
+/**
+ * Checks whether the given username exists.
+ *
+ * @since 2.0.0
+ *
+ * @param string $username Username.
+ * @return int|false The user's ID on success, and false on failure.
+ */
+function username_exists( $username ) {
+ if ( $user = get_user_by( 'login', $username ) ) {
+ return $user->ID;
+ }
+ return false;
+}
+
+/**
+ * Checks whether the given email exists.
+ *
+ * @since 2.1.0
+ *
+ * @param string $email Email.
+ * @return int|false The user's ID on success, and false on failure.
+ */
+function email_exists( $email ) {
+ if ( $user = get_user_by( 'email', $email) ) {
+ return $user->ID;
+ }
+ return false;
+}
+
+/**
+ * Checks whether a username is valid.
+ *
+ * @since 2.0.1
+ *
+ * @param string $username Username.
+ * @return bool Whether username given is valid
+ */
+function validate_username( $username ) {
+ $sanitized = sanitize_user( $username, true );
+ $valid = ( $sanitized == $username );
+ /**
+ * Filter whether the provided username is valid or not.
+ *
+ * @since 2.0.1
+ *
+ * @param bool $valid Whether given username is valid.
+ * @param string $username Username to check.
+ */
+ return apply_filters( 'validate_username', $valid, $username );
+}
+
+/**
+ * Insert a user into the database.
+ *
+ * Most of the `$userdata` array fields have filters associated with the values. Exceptions are
+ * 'ID', 'rich_editing', 'comment_shortcuts', 'admin_color', 'use_ssl',
+ * 'user_registered', and 'role'. The filters have the prefix 'pre_user_' followed by the field
+ * name. An example using 'description' would have the filter called, 'pre_user_description' that
+ * can be hooked into.
+ *
+ * @since 2.0.0
+ * @since 3.6.0 The `aim`, `jabber`, and `yim` fields were removed as default user contact
+ * methods for new installs. See wp_get_user_contact_methods().
+ *
+ * @global wpdb $wpdb WordPress database object for queries.
+ *
+ * @param array|object|WP_User $userdata {
+ * An array, object, or WP_User object of user data arguments.
+ *
+ * @type int $ID User ID. If supplied, the user will be updated.
+ * @type string $user_pass The plain-text user password.
+ * @type string $user_login The user's login username.
+ * @type string $user_nicename The URL-friendly user name.
+ * @type string $user_url The user URL.
+ * @type string $user_email The user email address.
+ * @type string $display_name The user's display name.
+ * Default is the the user's username.
+ * @type string $nickname The user's nickname.
+ * Default is the the user's username.
+ * @type string $first_name The user's first name. For new users, will be used
+ * to build the first part of the user's display name
+ * if `$display_name` is not specified.
+ * @type string $last_name The user's last name. For new users, will be used
+ * to build the second part of the user's display name
+ * if `$display_name` is not specified.
+ * @type string $description The user's biographical description.
+ * @type string|bool $rich_editing Whether to enable the rich-editor for the user.
+ * False if not empty.
+ * @type string|bool $comment_shortcuts Whether to enable comment moderation keyboard
+ * shortcuts for the user. Default false.
+ * @type string $admin_color Admin color scheme for the user. Default 'fresh'.
+ * @type bool $use_ssl Whether the user should always access the admin over
+ * https. Default false.
+ * @type string $user_registered Date the user registered. Format is 'Y-m-d H:i:s'.
+ * @type string|bool $show_admin_bar_front Whether to display the Admin Bar for the user on the
+ * site's frontend. Default true.
+ * @type string $role User's role.
+ * }
+ * @return int|WP_Error The newly created user's ID or a WP_Error object if the user could not
+ * be created.
+ */
+function wp_insert_user( $userdata ) {
+ global $wpdb;
+
+ if ( $userdata instanceof stdClass ) {
+ $userdata = get_object_vars( $userdata );
+ } elseif ( $userdata instanceof WP_User ) {
+ $userdata = $userdata->to_array();
+ }
+ // Are we updating or creating?
+ if ( ! empty( $userdata['ID'] ) ) {
+ $ID = (int) $userdata['ID'];
+ $update = true;
+ $old_user_data = WP_User::get_data_by( 'id', $ID );
+ // hashed in wp_update_user(), plaintext if called directly
+ $user_pass = $userdata['user_pass'];
+ } else {
+ $update = false;
+ // Hash the password
+ $user_pass = wp_hash_password( $userdata['user_pass'] );
+ }
+
+ $sanitized_user_login = sanitize_user( $userdata['user_login'], true );
+
+ /**
+ * Filter a username after it has been sanitized.
+ *
+ * This filter is called before the user is created or updated.
+ *
+ * @since 2.0.3
+ *
+ * @param string $sanitized_user_login Username after it has been sanitized.
+ */
+ $pre_user_login = apply_filters( 'pre_user_login', $sanitized_user_login );
+
+ //Remove any non-printable chars from the login string to see if we have ended up with an empty username
+ $user_login = trim( $pre_user_login );
+
+ if ( empty( $user_login ) ) {
+ return new WP_Error('empty_user_login', __('Cannot create a user with an empty login name.') );
+ }
+ if ( ! $update && username_exists( $user_login ) ) {
+ return new WP_Error( 'existing_user_login', __( 'Sorry, that username already exists!' ) );
+ }
+
+ // If a nicename is provided, remove unsafe user characters before
+ // using it. Otherwise build a nicename from the user_login.
+ if ( ! empty( $userdata['user_nicename'] ) ) {
+ $user_nicename = sanitize_user( $userdata['user_nicename'], true );
+ } else {
+ $user_nicename = $user_login;
+ }
+
+ $user_nicename = sanitize_title( $user_nicename );
+
+ // Store values to save in user meta.
+ $meta = array();
+
+ /**
+ * Filter a user's nicename before the user is created or updated.
+ *
+ * @since 2.0.3
+ *
+ * @param string $user_nicename The user's nicename.
+ */
+ $user_nicename = apply_filters( 'pre_user_nicename', $user_nicename );
+
+ $raw_user_url = empty( $userdata['user_url'] ) ? '' : $userdata['user_url'];
+
+ /**
+ * Filter a user's URL before the user is created or updated.
+ *
+ * @since 2.0.3
+ *
+ * @param string $raw_user_url The user's URL.
+ */
+ $user_url = apply_filters( 'pre_user_url', $raw_user_url );
+
+ $raw_user_email = empty( $userdata['user_email'] ) ? '' : $userdata['user_email'];
+
+ /**
+ * Filter a user's email before the user is created or updated.
+ *
+ * @since 2.0.3
+ *
+ * @param string $raw_user_email The user's email.
+ */
+ $user_email = apply_filters( 'pre_user_email', $raw_user_email );
+
+ /*
+ * If there is no update, just check for `email_exists`. If there is an update,
+ * check if current email and new email are the same, or not, and check `email_exists`
+ * accordingly.
+ */
+ if ( ( ! $update || ( ! empty( $old_user_data ) && 0 !== strcasecmp( $user_email, $old_user_data->user_email ) ) )
+ && ! defined( 'WP_IMPORTING' )
+ && email_exists( $user_email )
+ ) {
+ return new WP_Error( 'existing_user_email', __( 'Sorry, that email address is already used!' ) );
+ }
+ $nickname = empty( $userdata['nickname'] ) ? $user_login : $userdata['nickname'];
+
+ /**
+ * Filter a user's nickname before the user is created or updated.
+ *
+ * @since 2.0.3
+ *
+ * @param string $nickname The user's nickname.
+ */
+ $meta['nickname'] = apply_filters( 'pre_user_nickname', $nickname );
+
+ $first_name = empty( $userdata['first_name'] ) ? '' : $userdata['first_name'];
+
+ /**
+ * Filter a user's first name before the user is created or updated.
+ *
+ * @since 2.0.3
+ *
+ * @param string $first_name The user's first name.
+ */
+ $meta['first_name'] = apply_filters( 'pre_user_first_name', $first_name );
+
+ $last_name = empty( $userdata['last_name'] ) ? '' : $userdata['last_name'];
+
+ /**
+ * Filter a user's last name before the user is created or updated.
+ *
+ * @since 2.0.3
+ *
+ * @param string $last_name The user's last name.
+ */
+ $meta['last_name'] = apply_filters( 'pre_user_last_name', $last_name );
+
+ if ( empty( $userdata['display_name'] ) ) {
+ if ( $update ) {
+ $display_name = $user_login;
+ } elseif ( $meta['first_name'] && $meta['last_name'] ) {
+ /* translators: 1: first name, 2: last name */
+ $display_name = sprintf( _x( '%1$s %2$s', 'Display name based on first name and last name' ), $meta['first_name'], $meta['last_name'] );
+ } elseif ( $meta['first_name'] ) {
+ $display_name = $meta['first_name'];
+ } elseif ( $meta['last_name'] ) {
+ $display_name = $meta['last_name'];
+ } else {
+ $display_name = $user_login;