0

We have a front-end registration form that was working as expected for months, and now mysteriously when someone registers they can't log in because their password is empty. Using a front-end password reset works and then they can log in normally.

Clearly a bug was introduced into the code somehow but I can't find it and we don't know when exactly this happened. We are currently using Craft CMS 3.7.56.

We have a custom module controller handling the registration, and I can output the new user's chosen password to a custom log file all the way up to just before we call the redirect for the next page. Then on that page if I try to output the user's password it is empty. I have boiled this down so there is not — I think — anything happening in my code between those two events, the redirect return $this->redirectToPostedUrl(); and then the calling of currentUser.password. Still there is no output of the password, whereas with an established user account the password is visible. (This is all in a test environment.)

I am at a loss as to what else to try to figure this out. Any tips will be greatly appreciated!

Update

Typical "give up, post for help, then facepalm" moment. I think I see where the issue is now, but am still unclear as to how I am going wrong.

Here is part of actionRegisterUser() in my module's Controller:

$userData = array(
        'firstName' => $post['firstName'],
        'lastName' => $post['lastName'],
        'email' => $post['email'],
        'phone' => $post['phone'],
        'emailNotificationsSales' => @$post['emailNotificationsSales'],
        'password' => $post['password'],
        'eventIds' => array($event->id),
      );
      $user = StpModule::$instance->stpModuleService->saveAndGetUser($userData);

The saveAndGetUser() Service's relevant code is:

$user = Craft::$app->users->getUserByUsernameOrEmail($userData['email']);
if (empty($user)) {
          // if not, create a new one
          $user = new User();
          $user->firstName = trim($userData['firstName']);
          $user->lastName = trim($userData['lastName']);
          $user->email = $userData['email'];
          $user->username = $userData['email'];
          $user->setFieldValues([
              'phone' => $userData['phone'],
              'emailNotificationsSales' => @$userData['emailNotificationsSales'] ?? 1,
              'wasPreregistered' => @$userData['wasPreregistered'] ?? 0,
          ]);
          if (!empty($userData['password'])) {
              $user->password = $userData['password'];
          }
          $user->validate(null, false);
        }
Craft::$app->getElements()->saveElement($user, false);
return $user;

This is the point where things are wacky. If I test for $user->password I get the entered value. If I do a fresh query to get that User like this:

$userTest = Craft::$app->users->getUserByUsernameOrEmail($user->email);

Then $userTest->password is empty. So it seems like the password is not saved even though it is passed to the Service.

4
  • Can you share the relevant parts of the custom controller action that sets the password, saves the user and redirects? Oct 21, 2022 at 22:38
  • Thanks for the response Mats. I'll see about posting code later today when I have a chance to look at this again. Oct 24, 2022 at 11:16
  • @MatsMikkelRummelhoff Digging deeper it looks like my issue is that I am trying to save the User, then log them in so they will be the "owner" of some Entries that are being created as part of registration, then update the User with relations to those Entries. I will add some code to my initial post. Oct 24, 2022 at 13:23
  • @MatsMikkelRummelhoff Added some code. Please be gentle! :D Oct 24, 2022 at 13:54

1 Answer 1

1

When setting the password for the new User model, you should use the newPassword property instead of password, i.e.

$user->newPassword = $userData['password'];

This is due to the User model actually hashing and saving the provided password only after the user has initially been saved, and only if that password is provided via the newPassword model attribute. Relevant logic in the Craft source code is here.

The above is tested and working as expected on Craft 3.7.56. I'm not aware if or when something changed in regards to setting $user->password when saving users programmatically via Craft::$app->getElementes() – I could be wrong, but chances are that it has never actually worked?

1
  • Thank you, that did it! While it seems highly unlikely that it never worked, I guess it is possible. I would have started with Craft's own code from their front-end registration help doc (which now has the "newPassword" variable, but may not have in the past). No matter, it works now. Thank you again for your help! Oct 25, 2022 at 16:58

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.