0

I am migrating a wordpress site to another site. The users from the old site need to work with the new site. I am doing a staggered implementation, so do not want to bring all the users over at once.

Basically, when a user attempts to sign in, before the login is authenticated, if the user does not exist on the new site, I am using an api call to grab the user details from the old site, and create the user on the new site.

I am using the wp_authenticate action to do the checks before the user is authenticated. This works, the user is created, and then the authentication should be done. The authentication fails though. If I then try to login again, it works, so I know the credentials are OK and all of the data has been written correctly.

It feels like during the same trip on the server, I cannot create a user and login.

add_action( 'wp_authenticate' , [$this,"preAuthenticate"],10,1);

public function preAuthenticate($username) {
    try {
        if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
            throw new \Exception("Not an email address - carry on");
        }
        
        $usr = get_user_by("email", $username);
        
        if ($usr) {
            throw new \Exception("Already a user - carry on");                
        }
        
        $this->getExternalUser($username);
        
    } catch (\Exception $ex) {
        // no need to do anything
    }
}

private function getExternalUser($emailAddress) {
    try {
        $oldUser = $this->readExternalUser($emailAddress); 
        
        if (!$oldUser)) {
            throw new \Exception("No user found");
        }

        $userData = [
            'user_pass' => $this->randomPassword(), //This will be updated after the user has been created using the hash passed
            'user_login' => $oldUser->login,
            'user_nicename' => $oldUser->niceName,
            'user_email' => $emailAddress,               
            'role' => "subscriber"                
        ];
        
        $result = wp_insert_user($userData);
        $usr = get_user_by("ID", $result);    
        if (!$usr) {
            throw new \Exception("user not created");
        }

        global $wpdb;
              
        $wpdb->update($wpdb->users, ["user_pass" => $oldUser->hash],['ID' => $usr->ID]);
        
        return true;

    } catch (\Exception $ex) {
        return false;
    }
}
2
  • Just looking at the code you provided makes me think that while the person is getting added correct. It is not getting added prior to the actual check itself. Have you tried firing it on the wp_signon()? so it occurs prior to the auth? developer.wordpress.org/reference/functions/wp_signon
    – Bazdin
    Commented Jan 26, 2022 at 21:57
  • Thanks - the wp_authenticate action is actually called from the wp_signon function, so unfortunately that hasn't helped. Commented Jan 27, 2022 at 14:56

1 Answer 1

0

I discovered what was happening. Because I already had the password hash, the only way (I know of) of updating the hash directly is by doing an update on the users table - which is what I was doing.

The problem was WP caches the users, so the next time you try and read the value (of the hash in this case to authenticate the user), the user was cached, but the cache has not been updated with the new hash, so the validation was happening on the old hash. After the page refresh, it was all OK.

So after the hash update, I am now clearing the cache which has sorted it out.

global $wpdb;
          
$wpdb->update($wpdb->users, ["user_pass" => $oldUser->hash],['ID' => $usr->ID]);
/* new line below */
wp_cache_delete($usr->ID, "users");    

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.