Created
May 16, 2026 16:38
-
-
Save rocketgeek/d1741d3317c66df7d37c706a95b60436 to your computer and use it in GitHub Desktop.
Proposed change to WP-Members email validation process (makes it a two step process)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * | |
| * | |
| */ | |
| class WP_Members_Validation_Link { | |
| /** | |
| * Meta containers | |
| * | |
| * @since 3.3.5 | |
| */ | |
| public $validation_confirm = '_wpmem_user_confirmed'; | |
| /** | |
| * Options. | |
| * | |
| * @since 3.3.5 | |
| */ | |
| public $send_welcome = true; | |
| public $show_success = true; | |
| public $send_notify = true; | |
| public $validated = false; | |
| public $email_text; | |
| public $invalid_message; | |
| public $success_message; | |
| public $moderated_message; | |
| /** | |
| * Initialize validation link feature. | |
| * | |
| * @since 3.3.5 | |
| */ | |
| public function __construct() { | |
| $defaults = array( | |
| 'email_text' => wpmem_get_text( 'validate_email_text' ), // 'Click to validate your account: ' | |
| 'success_message' => wpmem_get_text( 'validate_success_msg' ), // 'Thank you for validating your account.' | |
| 'invalid_message' => wpmem_get_text( 'validate_invalid_msg' ), // 'Validation key was expired or invalid' | |
| 'moderated_message' => wpmem_get_text( 'validate_moderated_msg' ), // 'Your account is now pending approval' | |
| ); | |
| /** | |
| * Filter default dialogs. | |
| * | |
| * @since 3.3.8 | |
| * | |
| * @param array $defaults | |
| */ | |
| $defaults = apply_filters( 'wpmem_validation_link_default_dialogs', $defaults ); | |
| foreach ( $defaults as $key => $value ) { | |
| $this->{$key} = $value; | |
| } | |
| add_action( 'the_content', array( $this, 'maybe_process_validation' ) ); | |
| add_action( 'template_redirect', array( $this, 'validate_key' ) ); | |
| add_filter( 'authenticate', array( $this, 'check_validated' ), 99, 3 ); | |
| add_filter( 'wpmem_email_filter', array( $this, 'add_key_to_email' ), 10, 3 ); | |
| add_filter( 'the_content', array( $this, 'validation_success' ), 100 ); | |
| add_action( 'wpmem_account_validation_success', array( $this, 'set_as_logged_in' ), 9 ); | |
| add_action( 'wpmem_account_validation_success', array( $this, 'send_welcome' ) ); | |
| add_action( 'wpmem_account_validation_success', array( $this, 'notify_admin' ) ); | |
| } | |
| /** | |
| * Include the validation key in the new user registration email as a validation link. | |
| * | |
| * @since 3.3.5 | |
| * | |
| * @param array $arr | |
| * @param array $wpmem_fields | |
| * @param array $field_data | |
| * @return array | |
| */ | |
| public function add_key_to_email( $arr, $wpmem_fields, $field_data ) { | |
| // Only do this for new registrations. | |
| $email_type = ( wpmem_is_enabled( 'mod_reg' ) ) ? 'newmod' : 'newreg'; | |
| if ( $arr['toggle'] == $email_type ) { | |
| $user = get_user_by( 'ID', intval( $arr['user_id'] ) ); | |
| /** | |
| * Gets the user based on the password key. | |
| * | |
| * WP filters/actions triggered: | |
| * - retrieve_password | |
| * - allow_password_reset | |
| * - retrieve_password_key | |
| * | |
| * @see: https://developer.wordpress.org/reference/functions/get_password_reset_key/ | |
| * @param WP_User User to retrieve password reset key for. | |
| * @return string|WP_Error Password reset key on success. WP_Error on error. | |
| */ | |
| $key = $this->set_validation_key( $user ); | |
| // Generate confirm link. | |
| /** | |
| * Filter the return url | |
| * | |
| * @since 3.3.5 | |
| * @since 3.3.9 Added $user object | |
| * | |
| * @param string The link URL (trailing slash recommended). | |
| * @param object $user | |
| */ | |
| $url = apply_filters( 'wpmem_validation_link_return_url', trailingslashit( wpmem_profile_url() ), $user ); | |
| $query_args = array( | |
| 'a' => 'confirm', | |
| 'key' => $key, | |
| 'login' => $user->user_login, | |
| ); | |
| // urlencode, primarily for user_login with a space. | |
| $query_args = array_map( 'rawurlencode', $query_args ); | |
| $link = add_query_arg( $query_args, trailingslashit( $url ) ); | |
| /** | |
| * Filter the confirmation link. | |
| * | |
| * @since 3.3.9 | |
| * | |
| * @param string $link | |
| * @param string $url | |
| * @param array $query_args | |
| */ | |
| $link = apply_filters( 'wpmem_validation_link', $link, $url, $query_args ); | |
| $sanitized_link = esc_url_raw( $link ); | |
| // Does email body have the [confirm_link] shortcode? | |
| if ( strpos( $arr['body'], '[confirm_link]' ) ) { | |
| $arr['body'] = str_replace( '[confirm_link]', $sanitized_link, $arr['body'] ); | |
| } else { | |
| // Add text and link to the email body. | |
| $arr['body'] = $arr['body'] . "\r\n" | |
| . $this->email_text . ' ' . $sanitized_link; | |
| } | |
| } | |
| return $arr; | |
| } | |
| /** | |
| * Checks for validation key in the URL and starts validation process. | |
| * | |
| * @since 3.5.7 | |
| */ | |
| public function maybe_process_validation( $content ) { | |
| if ( 'confirm' == wpmem_get( 'a', false, 'get' ) ) { | |
| $content = '<div id="wpmem-email-confirm"> | |
| <p>' . __( 'Please click the button below to confirm your email address and complete your registration:', 'wp-members' ) . '</p> | |
| <form method="post" action="' . esc_url( wpmem_profile_url() ) . '"> | |
| <input type="hidden" name="a" value="confirm" /> | |
| <input type="hidden" name="key" value="' . esc_attr( wpmem_get( 'key', false, 'get' ) ) . '" /> | |
| <input type="hidden" name="login" value="' . esc_attr( wpmem_get( 'login', false, 'get' ) ) . '" /> | |
| <button type="submit">' . __( 'Confirm Email', 'wp-members' ) . '</button> | |
| </form> | |
| </div>'; | |
| return $content; | |
| } | |
| return $content; | |
| } | |
| /** | |
| * Check for a validation key and if one exists, validate and log in user. | |
| * | |
| * @since 3.3.5 | |
| */ | |
| public function validate_key() { | |
| // Check for validation key. | |
| $key = ( 'confirm' == wpmem_get( 'a', false ) ) ? wpmem_get( 'key', false ) : false; | |
| $login = ( 'confirm' == wpmem_get( 'a', false ) ) ? wpmem_get( 'login', false ) : false; | |
| // Do not attempt validation if key or login is missing. | |
| if ( false !== $key ) { | |
| // Set an error container. | |
| $errors = new WP_Error(); | |
| /** | |
| * Validate the key. | |
| * | |
| * WP_Error will be invalid_key or expired_key. Process triggers password_reset_expiration filter | |
| * filtering DAY_IN_SECONDS default. Filter password_reset_key_expired is also triggered filtering | |
| * the return value (which can be used to override the expired/invalid check based on user_id). | |
| * | |
| * WP filter/actions triggered: | |
| * - password_reset_expiration | |
| * - password_reset_key_expired | |
| * | |
| * @see https://developer.wordpress.org/reference/functions/check_password_reset_key/ | |
| * @param string Hash to validate sending user's password. | |
| * @param string The user login. | |
| * @return WP_User|WP_Error WP_User object on success, WP_Error object for invalid or expired keys (invalid_key|expired_key). | |
| */ | |
| $user = check_password_reset_key( $key, $login ); | |
| if ( ! is_wp_error( $user ) ) { | |
| $this->validated = true; | |
| // Delete validation_key meta and set active. | |
| $this->clear_activation_key( $user->ID ); | |
| $this->set_as_confirmed( $user->ID ); | |
| /** | |
| * Fires when a user has successfully validated their account. | |
| * | |
| * @since 3.3.5 | |
| * | |
| * @param int $user_id | |
| */ | |
| do_action( 'wpmem_account_validation_success', $user->ID ); | |
| } else { | |
| $this->validated = false; | |
| } | |
| } | |
| return; | |
| } | |
| /** | |
| * Display messaging. | |
| * | |
| * Shows success if key validates, expired if it does not. | |
| * | |
| * @since 3.3.5 | |
| * | |
| * @param string $content | |
| * @return string $content | |
| */ | |
| public function validation_success( $content ) { | |
| if ( $this->show_success && 'confirm' == wpmem_get( 'a', false ) && isset( $this->validated ) ) { | |
| if ( true === $this->validated ) { | |
| $msg = $this->success_message; | |
| if ( wpmem_is_mod_reg() ) { | |
| $user = get_user_by( 'login', sanitize_user( wpmem_get( 'login', false ) ) ); | |
| if ( ! wpmem_is_user_activated( $user->ID ) ) { | |
| $msg = $msg . ' ' . $this->moderated_message; | |
| } | |
| } | |
| } elseif ( false === $this->validated ) { | |
| $msg = $this->invalid_message; | |
| } else { | |
| $msg = ''; | |
| } | |
| $content = wpmem_get_display_message( 'custom', $msg ) . $content; | |
| } | |
| return $content; | |
| } | |
| /** | |
| * Checks if a user is activated during user authentication. | |
| * | |
| * This prevents access via login if the user has not confirmed their email. | |
| * | |
| * @since 3.3.5 Moved from core to user object. | |
| * | |
| * @param object $user The WordPress User object. | |
| * @param string $username The user's username (user_login). | |
| * @param string $password The user's password. | |
| * @return object $user The WordPress User object. | |
| */ | |
| function check_validated( $user, $username, $password ) { | |
| if ( ! is_wp_error( $user ) && ! is_null( $user ) && false == wpmem_is_user_confirmed( $user->ID ) ) { | |
| $error_message = sprintf( wpmem_get_text( 'login_not_confirmed' ), '<strong>', '</strong>', '<a href="' . esc_url_raw( wpmem_reconfirm_url() ) . '">', '</a>' ); | |
| $user = new WP_Error( 'authentication_failed', $error_message ); | |
| } | |
| /** | |
| * Filters the check_validated result. | |
| * | |
| * @since 3.4.2 | |
| * | |
| * @param mixed $user | |
| * @param string $username | |
| * @param string $password | |
| */ | |
| return apply_filters( 'wpmem_check_validated', $user, $username, $password ); | |
| } | |
| /** | |
| * Sets user as logged in upon validation (if moderated reg is not enabled). | |
| * | |
| * @since 3.5.0 | |
| * | |
| * @param int $user_id | |
| */ | |
| public function set_as_logged_in( $user_id ) { | |
| // If registration is not moderated, set the user as logged in. | |
| if ( ! wpmem_is_enabled( 'mod_reg' ) ) { | |
| wpmem_set_as_logged_in( $user_id ); | |
| } | |
| } | |
| /** | |
| * Sends the welcome email to the user upon validation of their email. | |
| * | |
| * @since 3.3.5 | |
| * @since 3.3.8 Sends email specific to email validation (previously was moderated approved email). | |
| * | |
| * @param int $user_id | |
| */ | |
| public function send_welcome( $user_id ) { | |
| if ( $this->send_welcome ) { | |
| $email_to_send = ( wpmem_get_email_settings( 'wpmembers_email_validated' ) ) ? 'validated' : 'modreg'; | |
| wpmem_email_to_user( array( 'user_id'=>$user_id, 'tag'=>$email_to_send ) ); | |
| } | |
| } | |
| /** | |
| * Sends notification email to the admin upon validation of the user's email. | |
| * | |
| * @since 3.3.5 | |
| * | |
| * @param int $user_id | |
| */ | |
| public function notify_admin( $user_id ) { | |
| if ( $this->send_notify ) { | |
| wpmem_notify_admin( $user_id ); | |
| } | |
| } | |
| /** | |
| * Clears user_activation_key. | |
| * | |
| * @since 3.3.8 | |
| * | |
| * @param int $user_id | |
| */ | |
| public function clear_activation_key( $user_id ) { | |
| global $wpdb; | |
| $result = $wpdb->update( $wpdb->users, array( 'user_activation_key' => '', ), array( 'ID' => intval( $user_id ) ) ); | |
| //clean_user_cache( $user_id ); | |
| } | |
| /** | |
| * Sets a user activation key. | |
| * | |
| * @since 3.3.8 | |
| * | |
| * @param mixed $user user ID (int)|WP_User (object). | |
| */ | |
| public function set_validation_key( $user ) { | |
| $user = ( is_object( $user ) ) ? $user : get_user_by( 'ID', intval( $user ) ); | |
| return get_password_reset_key( $user ); | |
| } | |
| /** | |
| * Sets user as having validated their email. | |
| * | |
| * @since 3.3.8 | |
| * | |
| * @param int $user_id | |
| */ | |
| public function set_as_confirmed( $user_id ) { | |
| update_user_meta( $user_id, $this->validation_confirm, time() ); | |
| /** | |
| * Fires when user is set as confirmed (either manually or by user). | |
| * | |
| * @since 3.3.9 | |
| * | |
| * @param int $user_id | |
| * @param string time() | |
| */ | |
| do_action( 'wpmem_user_set_as_confirmed', $user_id, time() ); | |
| } | |
| /** | |
| * Sets user as NOT having validated their email. | |
| * | |
| * @since 3.3.8 | |
| * | |
| * @param int $user_id | |
| */ | |
| public function set_as_unconfirmed( $user_id ) { | |
| delete_user_meta( $user_id, $this->validation_confirm ); | |
| $validation_key = $this->set_validation_key( $user_id ); | |
| /** | |
| * Fires when user is set as confirmed (either manually or by user). | |
| * | |
| * @since 3.3.9 | |
| * | |
| * @param int $user_id | |
| * @param string time() | |
| * @param string $key | |
| */ | |
| do_action( 'wpmem_user_set_as_unconfirmed', $user_id, time(), $validation_key ); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment