From 7f7820e67c6a005aade8cd4950e3e7ae7598f810 Mon Sep 17 00:00:00 2001 From: Mykyta Synelnikov Date: Thu, 10 Oct 2024 18:18:56 +0300 Subject: [PATCH 1/6] * fixed sending emails upon registration; * fixed using `um_user( 'status' )` and `um_user( 'account_status' )` functions; * fixed using `set_status()` function; * based on https://github.com/ultimatemember/ultimatemember/pull/1564 --- includes/admin/class-secure.php | 3 +- includes/common/class-secure.php | 6 ++- includes/core/class-member-directory.php | 4 +- includes/core/class-user.php | 52 +++++------------------- includes/core/rest/class-api-v1.php | 7 ++-- includes/core/rest/class-api-v2.php | 7 ++-- includes/core/um-actions-access.php | 19 ++++----- includes/core/um-actions-login.php | 4 +- includes/core/um-actions-profile.php | 4 +- includes/core/um-actions-register.php | 30 +++++--------- includes/core/um-filters-login.php | 3 +- 11 files changed, 49 insertions(+), 90 deletions(-) diff --git a/includes/admin/class-secure.php b/includes/admin/class-secure.php index a3f173de..a8a37d61 100644 --- a/includes/admin/class-secure.php +++ b/includes/admin/class-secure.php @@ -150,6 +150,7 @@ if ( ! class_exists( 'um\admin\Secure' ) ) { } // Restore Account Status. if ( isset( $metadata['account_status'] ) ) { + // Force update of the user status without email notifications. UM()->common()->users()->set_status( $user_id, $metadata['account_status'] ); } @@ -327,7 +328,7 @@ if ( ! class_exists( 'um\admin\Secure' ) ) { if ( 'account_status' === $column_name ) { um_fetch_user( $user_id ); $is_blocked = um_user( 'um_user_blocked' ); - $account_status = um_user( 'account_status' ); + $account_status = UM()->common()->users()->get_status( $user_id ); if ( ! empty( $is_blocked ) && in_array( $account_status, array( 'rejected', 'inactive' ), true ) ) { $datetime = um_user( 'um_user_blocked__timestamp' ); $val .= '
' . esc_html__( 'Blocked Due to Suspicious Activity', 'ultimate-member' ) . '
'; diff --git a/includes/common/class-secure.php b/includes/common/class-secure.php index 141ef494..65396d7e 100644 --- a/includes/common/class-secure.php +++ b/includes/common/class-secure.php @@ -106,7 +106,7 @@ if ( ! class_exists( 'um\common\Secure' ) ) { $banned_profile_links = ''; foreach ( $user_ids as $uid ) { um_fetch_user( $uid ); - $banned_profile_links .= UM()->user()->get_profile_link( $uid ) . ' ' . um_user( 'account_status' ) . '
'; + $banned_profile_links .= UM()->user()->get_profile_link( $uid ) . ' ' . UM()->common()->users()->get_status( $uid ) . '
'; } um_reset_user(); @@ -221,18 +221,20 @@ if ( ! class_exists( 'um\common\Secure' ) ) { 'submitted' => ! empty( UM()->form()->post_form ) ? UM()->form()->post_form : '', 'roles' => $user->roles, 'user_agent' => $user_agent, - 'account_status' => um_user( 'status' ), + 'account_status' => UM()->common()->users()->get_status( $user->ID ), ); update_user_meta( $user->ID, 'um_user_blocked__metadata', $captured ); $user->remove_all_caps(); $user->update_user_level_from_caps(); + // Force update of the user status without email notifications. if ( is_user_logged_in() ) { UM()->common()->users()->set_status( $user->ID, 'inactive' ); } else { UM()->common()->users()->set_status( $user->ID, 'rejected' ); } + um_reset_user(); update_user_meta( $user->ID, 'um_user_blocked', 'suspicious_activity' ); update_user_meta( $user->ID, 'um_user_blocked__timestamp', current_time( 'mysql', true ) ); diff --git a/includes/core/class-member-directory.php b/includes/core/class-member-directory.php index ea83dffa..dd40f0dd 100644 --- a/includes/core/class-member-directory.php +++ b/includes/core/class-member-directory.php @@ -2680,8 +2680,8 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) { 'card_anchor' => esc_html( substr( md5( $user_id ), 10, 5 ) ), 'id' => absint( $user_id ), 'role' => esc_html( um_user( 'role' ) ), - 'account_status' => esc_html( um_user( 'account_status' ) ), - 'account_status_name' => esc_html( um_user( 'account_status_name' ) ), + 'account_status' => esc_html( UM()->common()->users()->get_status( $user_id ) ), + 'account_status_name' => esc_html( UM()->common()->users()->get_status( $user_id, 'formatted' ) ), 'cover_photo' => wp_kses( um_user( 'cover_photo', $this->cover_size ), UM()->get_allowed_html( 'templates' ) ), 'display_name' => esc_html( um_user( 'display_name' ) ), 'profile_url' => esc_url( um_user_profile_url() ), diff --git a/includes/core/class-user.php b/includes/core/class-user.php index 7512e920..14f7aa09 100644 --- a/includes/core/class-user.php +++ b/includes/core/class-user.php @@ -432,7 +432,7 @@ if ( ! class_exists( 'um\core\User' ) ) { } $metakeys = array( 'account_status', 'hide_in_members', 'synced_gravatar_hashed_id', 'synced_profile_photo', 'profile_photo', 'cover_photo', '_um_verified' ); - if ( ! in_array( $meta_key, $metakeys ) ) { + if ( ! in_array( $meta_key, $metakeys, true ) ) { return; } @@ -506,7 +506,7 @@ if ( ! class_exists( 'um\core\User' ) ) { function on_update_usermeta( $meta_id, $object_id, $meta_key, $_meta_value ) { $metakeys = array( 'account_status', 'hide_in_members', 'synced_gravatar_hashed_id', 'synced_profile_photo', 'profile_photo', 'cover_photo', '_um_verified' ); - if ( ! in_array( $meta_key, $metakeys ) ) { + if ( ! in_array( $meta_key, $metakeys, true ) ) { return; } @@ -642,28 +642,23 @@ if ( ! class_exists( 'um\core\User' ) ) { delete_transient( 'um_count_users_pending_dot' ); } - /** * */ - function check_membership() { + public function check_membership() { if ( ! is_user_logged_in() ) { return; } - um_fetch_user( get_current_user_id() ); - $status = um_user( 'account_status' ); - - if ( 'rejected' == $status ) { + $status = UM()->common()->users()->get_status( get_current_user_id() ); + if ( 'rejected' === $status ) { wp_logout(); session_unset(); - exit( wp_redirect( um_get_core_page( 'login' ) ) ); + um_safe_redirect( um_get_core_page( 'login' ) ); + exit; } - - um_reset_user(); } - /** * Multisite add existing user * @@ -1295,25 +1290,7 @@ if ( ! class_exists( 'um\core\User' ) ) { $this->usermeta['account_status'][0] = 'approved'; } - if ( $this->usermeta['account_status'][0] == 'approved' ) { - $this->usermeta['account_status_name'][0] = __( 'Approved', 'ultimate-member' ); - } - - if ( $this->usermeta['account_status'][0] == 'awaiting_email_confirmation' ) { - $this->usermeta['account_status_name'][0] = __( 'Awaiting Email Confirmation', 'ultimate-member' ); - } - - if ( $this->usermeta['account_status'][0] == 'awaiting_admin_review' ) { - $this->usermeta['account_status_name'][0] = __( 'Pending Review', 'ultimate-member' ); - } - - if ( $this->usermeta['account_status'][0] == 'rejected' ) { - $this->usermeta['account_status_name'][0] = __( 'Membership Rejected', 'ultimate-member' ); - } - - if ( $this->usermeta['account_status'][0] == 'inactive' ) { - $this->usermeta['account_status_name'][0] = __( 'Membership Inactive', 'ultimate-member' ); - } + $this->usermeta['account_status_name'][0] = UM()->common()->users()->get_status( $this->id, 'formatted' ); // add user meta foreach ( $this->usermeta as $k => $v ) { @@ -1619,36 +1596,29 @@ if ( ! class_exists( 'um\core\User' ) ) { * * @param bool $send_mail */ - function delete( $send_mail = true ) { - + public function delete( $send_mail = true ) { $this->send_mail_on_delete = $send_mail; - //don't send email notification to not approved user - if ( 'approved' != um_user( 'account_status' ) ) { + // Don't send email notification to not approved user + if ( 'approved' !== UM()->common()->users()->get_status( $this->id ) ) { $this->send_mail_on_delete = false; } // remove user if ( is_multisite() ) { - if ( ! function_exists( 'wpmu_delete_user' ) ) { require_once ABSPATH . 'wp-admin/includes/ms.php'; } wpmu_delete_user( $this->id ); - } else { - if ( ! function_exists( 'wp_delete_user' ) ) { require_once ABSPATH . 'wp-admin/includes/user.php'; } wp_delete_user( $this->id ); - } - } - /** * This method gets a user role in slug format. e.g. member * diff --git a/includes/core/rest/class-api-v1.php b/includes/core/rest/class-api-v1.php index f999a3d5..e80a59ea 100644 --- a/includes/core/rest/class-api-v1.php +++ b/includes/core/rest/class-api-v1.php @@ -174,7 +174,7 @@ if ( ! class_exists( 'um\core\rest\API_v1' ) ) { $val->roles = $user->roles; $val->first_name = um_user( 'first_name' ); $val->last_name = um_user( 'last_name' ); - $val->account_status = um_user( 'account_status' ); + $val->account_status = UM()->common()->users()->get_status( $user->ID ); $val->profile_pic_original = um_get_user_avatar_url( '', 'original' ); $val->profile_pic_normal = um_get_user_avatar_url( '', 200 ); $val->profile_pic_small = um_get_user_avatar_url( '', 40 ); @@ -239,6 +239,7 @@ if ( ! class_exists( 'um\core\rest\API_v1' ) ) { switch ( $data ) { case 'status': + // Force update of the user status without email notifications. UM()->common()->users()->set_status( $id, $value ); $response['success'] = __( 'User status has been changed.', 'ultimate-member' ); break; @@ -361,7 +362,7 @@ if ( ! class_exists( 'um\core\rest\API_v1' ) ) { $response['profile_pic_small'] = um_get_user_avatar_url( '', 40 ); break; case 'status': - $response['status'] = um_user( 'account_status' ); + $response['status'] = UM()->common()->users()->get_status( $user->ID ); break; case 'role': //get priority role here @@ -382,7 +383,7 @@ if ( ! class_exists( 'um\core\rest\API_v1' ) ) { $val->roles = $user->roles; $val->first_name = um_user( 'first_name' ); $val->last_name = um_user( 'last_name' ); - $val->account_status = um_user( 'account_status' ); + $val->account_status = UM()->common()->users()->get_status( $user->ID ); $val->profile_pic_original = um_get_user_avatar_url( '', 'original' ); $val->profile_pic_normal = um_get_user_avatar_url( '', 200 ); $val->profile_pic_small = um_get_user_avatar_url( '', 40 ); diff --git a/includes/core/rest/class-api-v2.php b/includes/core/rest/class-api-v2.php index 6163e683..8f72fd83 100644 --- a/includes/core/rest/class-api-v2.php +++ b/includes/core/rest/class-api-v2.php @@ -173,7 +173,7 @@ if ( ! class_exists( 'um\core\rest\API_v2' ) ) { $val->roles = $user->roles; $val->first_name = um_user( 'first_name' ); $val->last_name = um_user( 'last_name' ); - $val->account_status = um_user( 'account_status' ); + $val->account_status = UM()->common()->users()->get_status( $user->ID ); $val->profile_pic_original = um_get_user_avatar_url( '', 'original' ); $val->profile_pic_normal = um_get_user_avatar_url( '', 200 ); $val->profile_pic_small = um_get_user_avatar_url( '', 40 ); @@ -221,6 +221,7 @@ if ( ! class_exists( 'um\core\rest\API_v2' ) ) { switch ( $data ) { case 'status': + // Force update of the user status without email notifications. UM()->common()->users()->set_status( $id, $value ); $response['success'] = __( 'User status has been changed.', 'ultimate-member' ); break; @@ -325,7 +326,7 @@ if ( ! class_exists( 'um\core\rest\API_v2' ) ) { $response['profile_pic_small'] = um_get_user_avatar_url( '', 40 ); break; case 'status': - $response['status'] = um_user( 'account_status' ); + $response['status'] = UM()->common()->users()->get_status( $user->ID ); break; case 'role': //get priority role here @@ -346,7 +347,7 @@ if ( ! class_exists( 'um\core\rest\API_v2' ) ) { $val->roles = $user->roles; $val->first_name = um_user( 'first_name' ); $val->last_name = um_user( 'last_name' ); - $val->account_status = um_user( 'account_status' ); + $val->account_status = UM()->common()->users()->get_status( $user->ID ); $val->profile_pic_original = um_get_user_avatar_url( '', 'original' ); $val->profile_pic_normal = um_get_user_avatar_url( '', 200 ); $val->profile_pic_small = um_get_user_avatar_url( '', 40 ); diff --git a/includes/core/um-actions-access.php b/includes/core/um-actions-access.php index c8e53613..a56d66bb 100644 --- a/includes/core/um-actions-access.php +++ b/includes/core/um-actions-access.php @@ -1,5 +1,7 @@ -common()->users()->get_status( $user_id ); + if ( 'approved' !== $account_status ) { um_redirect_home(); } - - um_reset_user(); - } } -add_action( 'um_access_profile', 'um_access_profile' ); \ No newline at end of file +add_action( 'um_access_profile', 'um_access_profile' ); diff --git a/includes/core/um-actions-login.php b/includes/core/um-actions-login.php index a47065fe..816f53e7 100644 --- a/includes/core/um-actions-login.php +++ b/includes/core/um-actions-login.php @@ -130,16 +130,14 @@ function um_submit_form_errors_hook_logincheck( $submitted_data, $form_data ) { } $user_id = ( isset( UM()->login()->auth_id ) ) ? UM()->login()->auth_id : ''; - um_fetch_user( $user_id ); - $status = um_user( 'account_status' ); // account status + $status = UM()->common()->users()->get_status( $user_id ); // account status switch ( $status ) { // If user can't log in to site... case 'inactive': case 'awaiting_admin_review': case 'awaiting_email_confirmation': case 'rejected': - um_reset_user(); // Not `um_safe_redirect()` because UM()->permalinks()->get_current_url() is situated on the same host. wp_safe_redirect( add_query_arg( 'err', esc_attr( $status ), UM()->permalinks()->get_current_url() ) ); exit; diff --git a/includes/core/um-actions-profile.php b/includes/core/um-actions-profile.php index e60e5ac8..3810847a 100644 --- a/includes/core/um-actions-profile.php +++ b/includes/core/um-actions-profile.php @@ -1318,11 +1318,11 @@ function um_profile_header( $args ) { } ?> -
+
common()->users()->get_status( um_user( 'ID' ), 'formatted' ) ) ); ?>
diff --git a/includes/core/um-actions-register.php b/includes/core/um-actions-register.php index 286ccf99..74bcf169 100644 --- a/includes/core/um-actions-register.php +++ b/includes/core/um-actions-register.php @@ -58,15 +58,6 @@ function um_after_insert_user( $user_id, $args, $form_data = null ) { UM()->user()->set_registration_details( $args['submitted'], $args, $form_data ); } - // Set user status. - $status = um_user( 'status' ); - if ( empty( $status ) ) { - um_fetch_user( $user_id ); - $status = um_user( 'status' ); - } - - UM()->common()->users()->set_status( $user_id, $status ); - // Create user uploads directory. UM()->uploader()->get_upload_user_base_dir( $user_id, true ); @@ -123,11 +114,12 @@ add_action( 'um_user_register', 'um_after_insert_user', 1, 3 ); */ function um_send_registration_notification( $user_id ) { um_fetch_user( $user_id ); + $registration_status = um_user( 'status' ); $emails = um_multi_admin_email(); if ( ! empty( $emails ) ) { foreach ( $emails as $email ) { - if ( 'pending' !== um_user( 'account_status' ) ) { + if ( 'pending' !== $registration_status ) { UM()->mail()->send( $email, 'notification_new_user', array( 'admin' => true ) ); } else { UM()->mail()->send( $email, 'notification_review', array( 'admin' => true ) ); @@ -145,7 +137,7 @@ add_action( 'um_registration_complete', 'um_send_registration_notification' ); * @param null|array $form_data */ function um_check_user_status( $user_id, $args, $form_data = null ) { - $status = um_user( 'account_status' ); + $registration_status = um_user( 'status' ); /** * Fires after complete UM user registration. * Where $status can be equal to 'approved', 'checkmail' or 'pending'. @@ -175,7 +167,7 @@ function um_check_user_status( $user_id, $args, $form_data = null ) { * } * add_action( 'um_post_registration_pending_hook', 'my_um_post_registration', 10, 3 ); */ - do_action( "um_post_registration_{$status}_hook", $user_id, $args, $form_data ); + do_action( "um_post_registration_{$registration_status}_hook", $user_id, $args, $form_data ); if ( is_null( $form_data ) || is_admin() ) { return; @@ -210,9 +202,9 @@ function um_check_user_status( $user_id, $args, $form_data = null ) { * } * add_action( 'track_pending_user_registration', 'my_um_post_registration', 10, 3 ); */ - do_action( "track_{$status}_user_registration", $user_id, $args, $form_data ); + do_action( "track_{$registration_status}_user_registration", $user_id, $args, $form_data ); - if ( 'approved' === $status ) { + if ( 'approved' === $registration_status ) { // Check if user is logged in because there can be the customized way when through 'um_registration_for_loggedin_users' hook the registration is enabled for the logged-in users (e.g. Administrator). if ( ! is_user_logged_in() ) { // Custom way if 'um_registration_for_loggedin_users' hook after custom callbacks returns true. Then don't make auto-login because user is already logged-in. @@ -255,7 +247,7 @@ function um_check_user_status( $user_id, $args, $form_data = null ) { } else { um_fetch_user( $user_id ); // required because there can be empty um_user. - if ( 'redirect_url' === um_user( $status . '_action' ) && '' !== um_user( $status . '_url' ) ) { + if ( 'redirect_url' === um_user( $registration_status . '_action' ) && '' !== um_user( $registration_status . '_url' ) ) { /** * Filters the redirect URL for pending user after registration. * @@ -275,13 +267,13 @@ function um_check_user_status( $user_id, $args, $form_data = null ) { * } * add_filter( 'um_registration_pending_user_redirect', 'my_registration_pending_user_redirect', 10, 3 ); */ - $redirect_url = apply_filters( 'um_registration_pending_user_redirect', um_user( $status . '_url' ), $status, um_user( 'ID' ) ); + $redirect_url = apply_filters( 'um_registration_pending_user_redirect', um_user( $registration_status . '_url' ), $registration_status, $user_id ); um_safe_redirect( $redirect_url ); } - if ( 'show_message' === um_user( $status . '_action' ) && '' !== um_user( $status . '_message' ) ) { + if ( 'show_message' === um_user( $registration_status . '_action' ) && '' !== um_user( $registration_status . '_message' ) ) { $url = UM()->permalinks()->get_current_url(); - $url = add_query_arg( 'message', esc_attr( $status ), $url ); + $url = add_query_arg( 'message', esc_attr( $registration_status ), $url ); // Add only priority role to URL. $url = add_query_arg( 'um_role', esc_attr( um_user( 'role' ) ), $url ); $url = add_query_arg( 'um_form_id', esc_attr( $form_data['form_id'] ), $url ); @@ -305,7 +297,7 @@ function um_check_user_status( $user_id, $args, $form_data = null ) { * } * add_filter( 'um_registration_show_message_redirect_url', 'my_um_registration_show_message_redirect_url', 10, 4 ); */ - $url = apply_filters( 'um_registration_show_message_redirect_url', $url, $status, um_user( 'ID' ), $form_data ); + $url = apply_filters( 'um_registration_show_message_redirect_url', $url, $registration_status, $user_id, $form_data ); // Not `um_safe_redirect()` because UM()->permalinks()->get_current_url() is situated on the same host. wp_safe_redirect( $url ); exit; diff --git a/includes/core/um-filters-login.php b/includes/core/um-filters-login.php index a5369469..7d7ba07f 100644 --- a/includes/core/um-filters-login.php +++ b/includes/core/um-filters-login.php @@ -66,8 +66,7 @@ function um_wp_form_errors_hook_logincheck( $user ) { } if ( isset( $user->ID ) ) { - um_fetch_user( $user->ID ); - $status = um_user( 'account_status' ); + $status = UM()->common()->users()->get_status( $user->ID ); $error = null; switch ( $status ) { From d4bd0a51331583fba01a29f0ab2d5bd109676d9b Mon Sep 17 00:00:00 2001 From: Mykyta Synelnikov Date: Fri, 11 Oct 2024 16:35:54 +0300 Subject: [PATCH 2/6] * fixed sanitizing for `activation_link_expiry_time` setting; --- includes/admin/class-admin.php | 7 +++++++ includes/admin/core/class-admin-settings.php | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/includes/admin/class-admin.php b/includes/admin/class-admin.php index 2f6f12d3..05995bad 100644 --- a/includes/admin/class-admin.php +++ b/includes/admin/class-admin.php @@ -1532,6 +1532,13 @@ if ( ! class_exists( 'um\admin\Admin' ) ) { $sanitized[ $k ] = absint( $v ); } break; + case 'empty_absint': + if ( is_array( $v ) ) { + $sanitized[ $k ] = array_map( 'absint', $v ); + } else { + $sanitized[ $k ] = ( '' !== $v ) ? absint( $v ) : ''; + } + break; case 'key': if ( is_array( $v ) ) { $sanitized[ $k ] = array_map( 'sanitize_key', $v ); diff --git a/includes/admin/core/class-admin-settings.php b/includes/admin/core/class-admin-settings.php index 6fd47efe..877d464c 100644 --- a/includes/admin/core/class-admin-settings.php +++ b/includes/admin/core/class-admin-settings.php @@ -769,7 +769,7 @@ if ( ! class_exists( 'um\admin\core\Admin_Settings' ) ) { 'sanitize' => 'bool', ), 'activation_link_expiry_time' => array( - 'sanitize' => 'absint', + 'sanitize' => 'empty_absint', ), 'account_tab_password' => array( 'sanitize' => 'bool', From 02745d804cad3a2cecdc82926bb466d84452ee3c Mon Sep 17 00:00:00 2001 From: Mykyta Synelnikov Date: Fri, 11 Oct 2024 16:43:05 +0300 Subject: [PATCH 3/6] * WPCS; * Better UI for role settings place; --- includes/admin/templates/role/register.php | 216 +++++++++++---------- 1 file changed, 112 insertions(+), 104 deletions(-) diff --git a/includes/admin/templates/role/register.php b/includes/admin/templates/role/register.php index 3952a31b..d2776d9a 100644 --- a/includes/admin/templates/role/register.php +++ b/includes/admin/templates/role/register.php @@ -1,113 +1,121 @@ - - +
- admin_forms( array( - 'class' => 'um-role-register um-half-column', - 'prefix_id' => 'role', - 'fields' => array( - array( - 'id' => '_um_status', - 'type' => 'select', - 'label' => __( 'Registration Status', 'ultimate-member' ), - 'tooltip' => __( 'Select the status you would like this user role to have after they register on your site', 'ultimate-member' ), - 'value' => ! empty( $role['_um_status'] ) ? __( $role['_um_status'] , 'ultimate-member' ) : array(), - 'options' => array( - 'approved' => __( 'Auto Approve', 'ultimate-member' ), - 'checkmail' => __( 'Require Email Activation', 'ultimate-member' ), - 'pending' => __( 'Require Admin Review', 'ultimate-member' ) + admin_forms( + array( + 'class' => 'um-role-register um-half-column', + 'prefix_id' => 'role', + 'fields' => array( + array( + 'id' => '_um_status', + 'type' => 'select', + 'label' => __( 'Registration Status', 'ultimate-member' ), + 'tooltip' => __( 'Select the status you would like this user role to have after they register on your site', 'ultimate-member' ), + 'value' => ! empty( $role_data['_um_status'] ) ? $role_data['_um_status'] : array(), + 'options' => array( + 'approved' => __( 'Auto Approve', 'ultimate-member' ), + 'checkmail' => __( 'Require Email Activation', 'ultimate-member' ), + 'pending' => __( 'Require Admin Review', 'ultimate-member' ), + ), ), - ), - array( - 'id' => '_um_auto_approve_act', - 'type' => 'select', - 'label' => __( 'Action to be taken after registration', 'ultimate-member' ), - 'tooltip' => __( 'Select what action is taken after a person registers on your site. Depending on the status you can redirect them to their profile, a custom url or show a custom message', 'ultimate-member' ), - 'value' => ! empty( $role['_um_auto_approve_act'] ) ? __( $role['_um_auto_approve_act'], 'ultimate-member' ) : array(), - 'options' => array( - 'redirect_profile' => __( 'Redirect to profile', 'ultimate-member' ), - 'redirect_url' => __( 'Redirect to URL', 'ultimate-member' ), + array( + 'id' => '_um_auto_approve_act', + 'type' => 'select', + 'label' => __( 'Action to be taken after registration', 'ultimate-member' ), + 'tooltip' => __( 'Select what action is taken after a person registers on your site. Depending on the status you can redirect them to their profile, a custom url or show a custom message', 'ultimate-member' ), + 'value' => ! empty( $role_data['_um_auto_approve_act'] ) ? $role_data['_um_auto_approve_act'] : array(), + 'options' => array( + 'redirect_profile' => __( 'Redirect to profile', 'ultimate-member' ), + 'redirect_url' => __( 'Redirect to URL', 'ultimate-member' ), + ), + 'conditional' => array( '_um_status', '=', 'approved' ), ), - 'conditional' => array( '_um_status', '=', 'approved' ) - ), - array( - 'id' => '_um_auto_approve_url', - 'type' => 'text', - 'label' => __( 'Set Custom Redirect URL', 'ultimate-member' ), - 'value' => ! empty( $role['_um_auto_approve_url'] ) ? __( $role['_um_auto_approve_url'], 'ultimate-member' ) : '', - 'conditional' => array( '_um_auto_approve_act', '=', 'redirect_url' ) - ), - array( - 'id' => '_um_login_email_activate', - 'type' => 'checkbox', - 'label' => __( 'Login user after validating the activation link?', 'ultimate-member' ), - 'tooltip' => __( 'Login the user after validating the activation link', 'ultimate-member' ), - 'value' => ! empty( $role['_um_login_email_activate'] ) ? __( $role['_um_login_email_activate'], 'ultimate-member' ) : 0, - 'conditional' => array( '_um_status', '=', 'checkmail' ) - ), - array( - 'id' => '_um_checkmail_action', - 'type' => 'select', - 'label' => __( 'Action to be taken after registration', 'ultimate-member' ), - 'tooltip' => __( 'Select what action is taken after a person registers on your site. Depending on the status you can redirect them to their profile, a custom url or show a custom message', 'ultimate-member' ), - 'value' => ! empty( $role['_um_checkmail_action'] ) ? __( $role['_um_checkmail_action'], 'ultimate-member' ) : array(), - 'options' => array( - 'show_message' => __( 'Show custom message', 'ultimate-member' ), - 'redirect_url' => __( 'Redirect to URL', 'ultimate-member' ), + array( + 'id' => '_um_auto_approve_url', + 'type' => 'text', + 'label' => __( 'Set Custom Redirect URL', 'ultimate-member' ), + 'value' => ! empty( $role_data['_um_auto_approve_url'] ) ? $role_data['_um_auto_approve_url'] : '', + 'conditional' => array( '_um_auto_approve_act', '=', 'redirect_url' ), ), - 'conditional' => array( '_um_status', '=', 'checkmail' ) - ), - array( - 'id' => '_um_checkmail_message', - 'type' => 'textarea', - 'label' => __( 'Personalize the custom message', 'ultimate-member' ), - 'value' => ! empty( $role['_um_checkmail_message'] ) ? __( $role['_um_checkmail_message'], 'ultimate-member' ) : __('Thank you for registering. Before you can login we need you to activate your account by clicking the activation link in the email we just sent you.','ultimate-member'), - 'conditional' => array( '_um_checkmail_action', '=', 'show_message' ) - ), - array( - 'id' => '_um_checkmail_url', - 'type' => 'text', - 'label' => __( 'Set Custom Redirect URL', 'ultimate-member' ), - 'value' => ! empty( $role['_um_checkmail_url'] ) ? __( $role['_um_checkmail_url'], 'ultimate-member' ) : '', - 'conditional' => array( '_um_checkmail_action', '=', 'redirect_url' ) - ), - array( - 'id' => '_um_url_email_activate', - 'type' => 'text', - 'label' => __( 'URL redirect after email activation', 'ultimate-member' ), - 'tooltip' => __( 'If you want users to go to a specific page other than login page after email activation, enter the URL here.', 'ultimate-member' ), - 'value' => ! empty( $role['_um_url_email_activate'] ) ? __( $role['_um_url_email_activate'], 'ultimate-member' ) : '', - 'conditional' => array( '_um_status', '=', 'checkmail' ), - ), - array( - 'id' => '_um_pending_action', - 'type' => 'select', - 'label' => __( 'Action to be taken after registration', 'ultimate-member' ), - 'tooltip' => __( 'Select what action is taken after a person registers on your site. Depending on the status you can redirect them to their profile, a custom url or show a custom message', 'ultimate-member' ), - 'value' => ! empty( $role['_um_pending_action'] ) ? __( $role['_um_pending_action'], 'ultimate-member' ) : array(), - 'options' => array( - 'show_message' => __( 'Show custom message', 'ultimate-member' ), - 'redirect_url' => __( 'Redirect to URL', 'ultimate-member' ), + array( + 'id' => '_um_checkmail_action', + 'type' => 'select', + 'label' => __( 'Action to be taken after registration', 'ultimate-member' ), + 'tooltip' => __( 'Select what action is taken after a person registers on your site. Depending on the status you can redirect them to their profile, a custom url or show a custom message', 'ultimate-member' ), + 'value' => ! empty( $role_data['_um_checkmail_action'] ) ? $role_data['_um_checkmail_action'] : array(), + 'options' => array( + 'show_message' => __( 'Show custom message', 'ultimate-member' ), + 'redirect_url' => __( 'Redirect to URL', 'ultimate-member' ), + ), + 'conditional' => array( '_um_status', '=', 'checkmail' ), + ), + array( + 'id' => '_um_checkmail_message', + 'type' => 'textarea', + 'label' => __( 'Personalize the custom message', 'ultimate-member' ), + 'value' => ! empty( $role_data['_um_checkmail_message'] ) ? $role_data['_um_checkmail_message'] : __( 'Thank you for registering. Before you can login we need you to activate your account by clicking the activation link in the email we just sent you.', 'ultimate-member' ), + 'conditional' => array( '_um_checkmail_action', '=', 'show_message' ), + ), + array( + 'id' => '_um_checkmail_url', + 'type' => 'text', + 'label' => __( 'Set Custom Redirect URL', 'ultimate-member' ), + 'value' => ! empty( $role_data['_um_checkmail_url'] ) ? $role_data['_um_checkmail_url'] : '', + 'conditional' => array( '_um_checkmail_action', '=', 'redirect_url' ), + ), + array( + 'id' => '_um_login_email_activate', + 'type' => 'checkbox', + 'label' => __( 'Login user after validating the activation link?', 'ultimate-member' ), + 'tooltip' => __( 'Login the user after validating the activation link', 'ultimate-member' ), + 'value' => ! empty( $role_data['_um_login_email_activate'] ) ? $role_data['_um_login_email_activate'] : 0, + 'conditional' => array( '_um_status', '=', 'checkmail' ), + ), + array( + 'id' => '_um_url_email_activate', + 'type' => 'text', + 'label' => __( 'URL redirect after email activation', 'ultimate-member' ), + 'tooltip' => __( 'If you want users to go to a specific page other than login page after email activation, enter the URL here.', 'ultimate-member' ), + 'value' => ! empty( $role_data['_um_url_email_activate'] ) ? $role_data['_um_url_email_activate'] : '', + 'conditional' => array( '_um_status', '=', 'checkmail' ), + ), + array( + 'id' => '_um_pending_action', + 'type' => 'select', + 'label' => __( 'Action to be taken after registration', 'ultimate-member' ), + 'tooltip' => __( 'Select what action is taken after a person registers on your site. Depending on the status you can redirect them to their profile, a custom url or show a custom message', 'ultimate-member' ), + 'value' => ! empty( $role_data['_um_pending_action'] ) ? $role_data['_um_pending_action'] : array(), + 'options' => array( + 'show_message' => __( 'Show custom message', 'ultimate-member' ), + 'redirect_url' => __( 'Redirect to URL', 'ultimate-member' ), + ), + 'conditional' => array( '_um_status', '=', 'pending' ), + ), + array( + 'id' => '_um_pending_message', + 'type' => 'textarea', + 'label' => __( 'Personalize the custom message', 'ultimate-member' ), + 'value' => ! empty( $role_data['_um_pending_message'] ) ? $role_data['_um_pending_message'] : __( 'Thank you for applying for membership to our site. We will review your details and send you an email letting you know whether your application has been successful or not.', 'ultimate-member' ), + 'conditional' => array( '_um_pending_action', '=', 'show_message' ), + ), + array( + 'id' => '_um_pending_url', + 'type' => 'text', + 'label' => __( 'Set Custom Redirect URL', 'ultimate-member' ), + 'conditional' => array( '_um_pending_action', '=', 'redirect_url' ), + 'value' => ! empty( $role_data['_um_pending_url'] ) ? $role_data['_um_pending_url'] : '', ), - 'conditional' => array( '_um_status', '=', 'pending' ) - ), - array( - 'id' => '_um_pending_message', - 'type' => 'textarea', - 'label' => __( 'Personalize the custom message', 'ultimate-member' ), - 'value' => ! empty( $role['_um_pending_message'] ) ? __( $role['_um_pending_message'], 'ultimate-member' ) : __('Thank you for applying for membership to our site. We will review your details and send you an email letting you know whether your application has been successful or not.','ultimate-member'), - 'conditional' => array( '_um_pending_action', '=', 'show_message' ) - ), - array( - 'id' => '_um_pending_url', - 'type' => 'text', - 'label' => __( 'Set Custom Redirect URL', 'ultimate-member' ), - 'conditional' => array( '_um_pending_action', '=', 'redirect_url' ), - 'value' => ! empty( $role['_um_pending_url'] ) ? __( $role['_um_pending_url'], 'ultimate-member' ) : '', ), ) - ) )->render_form(); ?> - + )->render_form(); + ?>
From 3c56190fa3dbc8ce60e3ed8948f59d740e69654e Mon Sep 17 00:00:00 2001 From: Mykyta Synelnikov Date: Fri, 11 Oct 2024 17:10:42 +0300 Subject: [PATCH 4/6] * fixed login form after recent updates * updated um_submit_form_{$mode} hook documentation --- includes/core/class-form.php | 9 +++++---- includes/core/um-actions-login.php | 13 +++++++++++-- includes/frontend/class-secure.php | 7 ++++++- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/includes/core/class-form.php b/includes/core/class-form.php index 7a39efbf..ae7234d9 100644 --- a/includes/core/class-form.php +++ b/includes/core/class-form.php @@ -682,6 +682,7 @@ if ( ! class_exists( 'um\core\Form' ) ) { /* Continue based on form mode - store data. */ /** * Fires for make main actions on UM login, registration or profile form submission. + * Where $mode equals login, registration or profile * * Internal Ultimate Member callbacks (Priority -> Callback name -> Excerpt): * ### um_submit_form_login: @@ -696,16 +697,16 @@ if ( ! class_exists( 'um\core\Form' ) ) { * * 10 - `um_submit_form_profile()` Profile form main handler. * * @since 1.3.x - * @hook um_submit_form_errors_hook + * @hook um_submit_form_{$mode} * * @param {array} $post $_POST Submission array. * @param {array} $form_data UM form data. Since 2.6.7 * - * @example Make any custom action. - * function my_custom_before_submit_form_post( $post, $form_data ) { + * @example Make any custom action on profile submission. + * function my_custom_submit_form_profile( $post, $form_data ) { * // your code here * } - * add_action( 'um_submit_form_errors_hook', 'my_custom_submit_form_errors_hook', 10, 2 ); + * add_action( 'um_submit_form_profile', 'my_custom_submit_form_profile', 10, 2 ); */ do_action( "um_submit_form_{$this->form_data['mode']}", $this->post_form, $this->form_data ); } diff --git a/includes/core/um-actions-login.php b/includes/core/um-actions-login.php index 816f53e7..42cac3e0 100644 --- a/includes/core/um-actions-login.php +++ b/includes/core/um-actions-login.php @@ -129,7 +129,7 @@ function um_submit_form_errors_hook_logincheck( $submitted_data, $form_data ) { wp_logout(); } - $user_id = ( isset( UM()->login()->auth_id ) ) ? UM()->login()->auth_id : ''; + $user_id = isset( UM()->login()->auth_id ) ? UM()->login()->auth_id : ''; $status = UM()->common()->users()->get_status( $user_id ); // account status switch ( $status ) { @@ -148,7 +148,6 @@ function um_submit_form_errors_hook_logincheck( $submitted_data, $form_data ) { wp_safe_redirect( um_get_core_page( 'login' ) ); exit; } - } add_action( 'um_submit_form_errors_hook_logincheck', 'um_submit_form_errors_hook_logincheck', 9999, 2 ); @@ -192,6 +191,16 @@ function um_user_login( $submitted_data ) { // phpcs:disable WordPress.Security.NonceVerification -- already verified here $rememberme = ( isset( $_REQUEST['rememberme'], $submitted_data['rememberme'] ) && 1 === (int) $submitted_data['rememberme'] ) ? 1 : 0; + $user_id = isset( UM()->login()->auth_id ) ? UM()->login()->auth_id : ''; + if ( empty( $user_id ) ) { + // refresh page if the user_id is empty + // Not `um_safe_redirect()` because UM()->permalinks()->get_current_url() is situated on the same host. + wp_safe_redirect( UM()->permalinks()->get_current_url() ); + exit; + } + + um_fetch_user( $user_id ); + // @todo check using the 'deny_admin_frontend_login' option if ( false !== strrpos( um_user( 'wp_roles' ), 'administrator' ) && ( ! isset( $_GET['provider'] ) && UM()->options()->get( 'deny_admin_frontend_login' ) ) ) { wp_die( esc_html__( 'This action has been prevented for security measures.', 'ultimate-member' ) ); diff --git a/includes/frontend/class-secure.php b/includes/frontend/class-secure.php index c3e05218..65304b1e 100644 --- a/includes/frontend/class-secure.php +++ b/includes/frontend/class-secure.php @@ -142,7 +142,12 @@ if ( ! class_exists( 'um\frontend\Secure' ) ) { */ public function login_validate_expired_pass() { if ( UM()->options()->get( 'display_login_form_notice' ) ) { - $expired_password_reset = get_user_meta( um_user( 'ID' ), 'um_secure_has_reset_password', true ); + $user_id = isset( UM()->login()->auth_id ) ? UM()->login()->auth_id : ''; + if ( empty( $user_id ) ) { + return; + } + + $expired_password_reset = get_user_meta( $user_id, 'um_secure_has_reset_password', true ); if ( ! $expired_password_reset ) { $login_url = add_query_arg( 'notice', 'expired_password', um_get_core_page( 'login' ) ); // Not `um_safe_redirect()` because predefined login page is situated on the same host. From 62cc39e2ef55626204a6556b2c6d4928d3a6f8e3 Mon Sep 17 00:00:00 2001 From: Mykyta Synelnikov Date: Fri, 11 Oct 2024 17:21:24 +0300 Subject: [PATCH 5/6] * updated single compare status to using `has_status` function; --- includes/core/class-user.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/includes/core/class-user.php b/includes/core/class-user.php index 14f7aa09..545d5434 100644 --- a/includes/core/class-user.php +++ b/includes/core/class-user.php @@ -650,8 +650,7 @@ if ( ! class_exists( 'um\core\User' ) ) { return; } - $status = UM()->common()->users()->get_status( get_current_user_id() ); - if ( 'rejected' === $status ) { + if ( UM()->common()->users()->has_status( get_current_user_id(), 'rejected' ) ) { wp_logout(); session_unset(); um_safe_redirect( um_get_core_page( 'login' ) ); @@ -1294,7 +1293,7 @@ if ( ! class_exists( 'um\core\User' ) ) { // add user meta foreach ( $this->usermeta as $k => $v ) { - if ( $k == 'display_name' ) { + if ( 'display_name' === $k ) { continue; } $this->profile[ $k ] = $v[0]; @@ -1599,7 +1598,7 @@ if ( ! class_exists( 'um\core\User' ) ) { public function delete( $send_mail = true ) { $this->send_mail_on_delete = $send_mail; // Don't send email notification to not approved user - if ( 'approved' !== UM()->common()->users()->get_status( $this->id ) ) { + if ( ! UM()->common()->users()->has_status( $this->id, 'approved' ) ) { $this->send_mail_on_delete = false; } From 1cbbb70a03c5115dba65008299e5163ff2f756e7 Mon Sep 17 00:00:00 2001 From: Mykyta Synelnikov Date: Fri, 11 Oct 2024 18:47:40 +0300 Subject: [PATCH 6/6] * added security condition to check that one logged-in user cannot activate another one user via email activation link; * fixed double handler of email activation link (wp_die doesn't stop the script for some reason); * added redirects to login page with error notices instead of wp_die text; --- includes/common/class-users.php | 2 ++ includes/core/class-permalinks.php | 22 +++++++++++----------- includes/core/class-user.php | 2 +- includes/core/um-actions-misc.php | 6 ++++++ 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/includes/common/class-users.php b/includes/common/class-users.php index 4bde40df..9884efa8 100644 --- a/includes/common/class-users.php +++ b/includes/common/class-users.php @@ -279,6 +279,8 @@ class Users { * @param {int} $expiration Expiration timestamp. Since 2.8.7. */ do_action( 'um_after_user_hash_is_changed', $user_id, $hash, $expiration ); + + $this->remove_cache( $user_id ); // Don't remove this line. It's required removing cache duplicate for the force case when re-send activation email. } /** diff --git a/includes/core/class-permalinks.php b/includes/core/class-permalinks.php index 3e494d16..1ce98f72 100644 --- a/includes/core/class-permalinks.php +++ b/includes/core/class-permalinks.php @@ -113,16 +113,24 @@ if ( ! class_exists( 'um\core\Permalinks' ) ) { isset( $_REQUEST['user_id'] ) && is_numeric( $_REQUEST['user_id'] ) ) { // valid token $user_id = absint( $_REQUEST['user_id'] ); + if ( is_user_logged_in() && get_current_user_id() !== $user_id ) { + // Cannot activate another user account. Please log out and try again. + wp_safe_redirect( um_user_profile_url( get_current_user_id() ) ); + exit; + } + delete_option( "um_cache_userdata_{$user_id}" ); $account_secret_hash = get_user_meta( $user_id, 'account_secret_hash', true ); if ( empty( $account_secret_hash ) || strtolower( sanitize_text_field( $_REQUEST['hash'] ) ) !== strtolower( $account_secret_hash ) ) { - wp_die( esc_html__( 'This activation link is expired or have already been used.', 'ultimate-member' ) ); + wp_safe_redirect( add_query_arg( 'err', 'activation_link_used', um_get_core_page( 'login' ) ) ); + exit; } $account_secret_hash_expiry = get_user_meta( $user_id, 'account_secret_hash_expiry', true ); if ( ! empty( $account_secret_hash_expiry ) && time() > $account_secret_hash_expiry ) { - wp_die( esc_html__( 'This activation link is expired.', 'ultimate-member' ) ); + wp_safe_redirect( add_query_arg( 'err', 'activation_link_expired', um_get_core_page( 'login' ) ) ); + exit; } $redirect = um_get_core_page( 'login', 'account_active' ); @@ -141,15 +149,7 @@ if ( ! class_exists( 'um\core\Permalinks' ) ) { // log in automatically $login = ! empty( $user_role_data['login_email_activate'] ); // Role setting "Login user after validating the activation link?" if ( ! is_user_logged_in() && $login ) { - $user = get_userdata( $user_id ); - - // update wp user - wp_set_current_user( $user_id, $user->user_login ); - wp_set_auth_cookie( $user_id ); - - ob_start(); - do_action( 'wp_login', $user->user_login, $user ); - ob_end_clean(); + UM()->user()->auto_login( $user_id ); } /** diff --git a/includes/core/class-user.php b/includes/core/class-user.php index 545d5434..f304d364 100644 --- a/includes/core/class-user.php +++ b/includes/core/class-user.php @@ -1362,7 +1362,7 @@ if ( ! class_exists( 'um\core\User' ) ) { user()->auto_login( 10, true ); ?> * */ - function auto_login( $user_id, $rememberme = 0 ) { + public function auto_login( $user_id, $rememberme = 0 ) { wp_set_current_user( $user_id ); diff --git a/includes/core/um-actions-misc.php b/includes/core/um-actions-misc.php index 9525b5a1..4c49617c 100644 --- a/includes/core/um-actions-misc.php +++ b/includes/core/um-actions-misc.php @@ -176,6 +176,12 @@ function um_add_update_notice( $args ) { case 'invalid_nonce': $err = __( 'An error has been encountered. Probably page was cached. Please try again.', 'ultimate-member' ); break; + case 'activation_link_used': + $err = __( 'This activation link is expired or have already been used.', 'ultimate-member' ); + break; + case 'activation_link_expired': + $err = __( 'This activation link is expired.', 'ultimate-member' ); + break; } } // phpcs:enable WordPress.Security.NonceVerification -- used for echo and already verified here.