Bulk import wordpress users with pre-hashed passwords

I’m migrating a whole slew of users between two self-hosted WordPress sites, and I’m trying to find a way to bring them across without resetting their passwords. The current site has everyone’s passwords, naturally, all nicely hashed. Currently the two methods I could see to import these users (wp_insert_user() and wp_create_user()) both require the passwords to be in clear text. Is there something I’m missing, or can this just not be done with current methods?

Related posts

Leave a Reply

1 comment

  1. You have 3 options. Run a custom database query, copy and modify wp_insert_user(), or run wp_insert_user() twice.

    Copy and modify wp_insert_user()

    Below is a custom wp_insert_user function. All I’ve done is removed the line that hashes the PW.

    function wpse_custom_insert_user( $userdata ) {
        global $wpdb;
    
        if ( is_a( $userdata, 'stdClass' ) )
            $userdata = get_object_vars( $userdata );
        elseif ( is_a( $userdata, 'WP_User' ) )
            $userdata = $userdata->to_array();
    
        extract( $userdata, EXTR_SKIP );
    
        // Are we updating or creating?
        if ( !empty($ID) ) {
            $ID = (int) $ID;
            $update = true;
            $old_user_data = WP_User::get_data_by( 'id', $ID );
        } else {
            $update = false;
        }
    
        $user_login = sanitize_user($user_login, true);
        $user_login = apply_filters('pre_user_login', $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($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 ( empty($user_nicename) )
            $user_nicename = sanitize_title( $user_login );
        $user_nicename = apply_filters('pre_user_nicename', $user_nicename);
    
        if ( empty($user_url) )
            $user_url = '';
        $user_url = apply_filters('pre_user_url', $user_url);
    
        if ( empty($user_email) )
            $user_email = '';
        $user_email = apply_filters('pre_user_email', $user_email);
    
        if ( !$update && ! defined( 'WP_IMPORTING' ) && email_exists($user_email) )
            return new WP_Error( 'existing_user_email', __( 'Sorry, that email address is already used!' ) );
    
        if ( empty($nickname) )
            $nickname = $user_login;
        $nickname = apply_filters('pre_user_nickname', $nickname);
    
        if ( empty($first_name) )
            $first_name = '';
        $first_name = apply_filters('pre_user_first_name', $first_name);
    
        if ( empty($last_name) )
            $last_name = '';
        $last_name = apply_filters('pre_user_last_name', $last_name);
    
        if ( empty( $display_name ) ) {
            if ( $update )
                $display_name = $user_login;
            elseif ( $first_name && $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' ), $first_name, $last_name );
            elseif ( $first_name )
                $display_name = $first_name;
            elseif ( $last_name )
                $display_name = $last_name;
            else
                $display_name = $user_login;
        }
        $display_name = apply_filters( 'pre_user_display_name', $display_name );
    
        if ( empty($description) )
            $description = '';
        $description = apply_filters('pre_user_description', $description);
    
        if ( empty($rich_editing) )
            $rich_editing = 'true';
    
        if ( empty($comment_shortcuts) )
            $comment_shortcuts = 'false';
    
        if ( empty($admin_color) )
            $admin_color = 'fresh';
        $admin_color = preg_replace('|[^a-z0-9 _.-@]|i', '', $admin_color);
    
        if ( empty($use_ssl) )
            $use_ssl = 0;
    
        if ( empty($user_registered) )
            $user_registered = gmdate('Y-m-d H:i:s');
    
        if ( empty($show_admin_bar_front) )
            $show_admin_bar_front = 'true';
    
        $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));
    
        if ( $user_nicename_check ) {
            $suffix = 2;
            while ($user_nicename_check) {
                $alt_user_nicename = $user_nicename . "-$suffix";
                $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));
                $suffix++;
            }
            $user_nicename = $alt_user_nicename;
        }
    
        $data = compact( 'user_pass', 'user_email', 'user_url', 'user_nicename', 'display_name', 'user_registered' );
        $data = wp_unslash( $data );
    
        if ( $update ) {
            $wpdb->update( $wpdb->users, $data, compact( 'ID' ) );
            $user_id = (int) $ID;
        } else {
            $wpdb->insert( $wpdb->users, $data + compact( 'user_login' ) );
            $user_id = (int) $wpdb->insert_id;
        }
    
        $user = new WP_User( $user_id );
    
        foreach ( _get_additional_user_keys( $user ) as $key ) {
            if ( isset( $$key ) )
                update_user_meta( $user_id, $key, $$key );
        }
    
        if ( isset($role) )
            $user->set_role($role);
        elseif ( !$update )
            $user->set_role(get_option('default_role'));
    
        wp_cache_delete($user_id, 'users');
        wp_cache_delete($user_login, 'userlogins');
    
        if ( $update )
            do_action('profile_update', $user_id, $old_user_data);
        else
            do_action('user_register', $user_id);
    
        return $user_id;
    }
    

    Running wp_insert_user twice

    If you run wp_insert_user() user_pass is expected to be a plain string. If you include an ID parameter however you need to use a hashed password instead.

    You could run wp_insert_user() with a random password to insert the user. This will return an ID. You could then run the same function again including the ID and the hashed password.

    As I pointed out above this is inefficient and not something I’d suggest but it would be possible. Here’s an example:

    $hashed_pw = get_hashed_pw(); // Replace this with the correct hashed password.
    
    $user_args = array(
        'ALL MY' => 'OTHER ARGS', // Enter all your other arguments for wp_insert_user().
        'user_pass' => 'random', // Set this to a random string.
    );
    
    $user_id = wp_insert_user( $user_args );
    
    $update_user_args = array(
        'ID' => $user_id,
        'user_pass' => $hashed_pw,
    );
    
    wp_insert_user( $update_user_args );
    

    This is not a complete solution. If you were to use it you’d want to include some error checking, etc. You’re much better off with one of the two other solutions posed.