Make WordPress Core

Opened 7 years ago

Last modified 5 years ago

#43734 new defect (bug)

user_profile_update_errors hook needs work-around to validate a to-be updated email address

Reported by: bjornw's profile BjornW Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version:
Component: Users Keywords:
Focuses: docs Cc:

Description

The 'user_profile_update_errors' hook can be used to (in)validate (custom added) fields in the user_profile before these fields are saved.

As far as I know, the 'best-practice' to do this is, is by accessing the field using it's name in $_POST. Grab it's value, do your thing and if this results in an error, add an error message to the $errors object and prevent the field from being saved to the database.

This does not work with the email field anymore (since WordPress version 4.9.0?), because $_POST['email'] is reset to the current value in the database in the function send_confirmation_on_profile_email(). See: wp-includes/user.php

The reset of $_POST['email'] to the current email address in the database prevents the 'best-practice' of accessing a field's value through $_POST because the new email address is now gone from $_POST.

Why is there a reset on $_POST?

My assumption is:
Resetting $_POST['email'] to the current email address in the database is needed, because of the new flow in WordPres in which WordPress requests a user's confirmation of a proposed email change (by sending an email to the new address and requesting the user to clink a link to confirm the change) before saving the new email address.

Therefor the value in the form should (at least temporarily) not be changed until the user has confirmed the change in email address. The chosen solution is such that the new email address is temporarily saved in a user meta field with the name '_new_email' including a hash. This is then processed upon when the user clicks on the link in the email requesting the email change.

Solution
I don't have a good solution yet and by submitting this ticket I hope more people can have a look at this issue.

For now I'd suggest to update docs to include detailed information on how to use the user meta field _new_email['newemail']}} instead of {{{$_POST['email'] in the user_profile_update_errors hook.



Change History (5)

#1 follow-up: @soulseekah
7 years ago

I think the deeper issue is that there's no straightforward way to prevent send_confirmation_on_profile_email from running without prevalidation. Like what if I want to prevent certain domains from being picked as a new e-mail? I should be able to prevent everything from triggering.

One way is to register personal_options_update and edit_user_profile_update hooks and remove send_confirmation_on_profile_email and then run it after validation. But that seems hacky.

#2 in reply to: ↑ 1 @BjornW
7 years ago

Replying to soulseekah:

I think the deeper issue is that there's no straightforward way to prevent send_confirmation_on_profile_email from running without prevalidation. Like what if I want to prevent certain domains from being picked as a new e-mail? I should be able to prevent everything from triggering.

One way is to register personal_options_update and edit_user_profile_update hooks and remove send_confirmation_on_profile_email and then run it after validation. But that seems hacky.

I agree completely. Seems to me the current implementation warrants a better one taking these use cases into account. I guess we need to come up with a patch as a proof-of-concept?

This ticket was mentioned in Slack in #core by bjornw. View the logs.


6 years ago

#4 @pento
6 years ago

  • Version trunk deleted

#5 @roytanck
5 years ago

I'm running into the exact issue @soulseekah describes in a client project (a custom-build domain blacklist plugin). Through a lot of trickery I've managed to sabotage the 'send_confirmation_on_profile_email' email so it does not get sent. However, I feel this issue warrants a new hook, probably in the send_confirmation_on_profile_email() function.

How about a filter hook called send_confirmation_on_profile_email that receives a boolean value (send mail or not, initially set to true), and the current user object? I'll gladly write a patch to add this hook. It would make suppressing the email trivial.

Note: See TracTickets for help on using tickets.