2017-07-26 14:57:52 +03:00
< ? php
namespace um\core ;
2023-06-26 16:54:43 +03:00
if ( ! defined ( 'ABSPATH' ) ) {
exit ;
}
2019-05-06 17:22:57 +03:00
2018-03-26 01:27:46 +03:00
if ( ! class_exists ( 'um\core\Password' ) ) {
2017-07-26 14:57:52 +03:00
2018-03-20 13:24:38 +02:00
/**
* Class Password
* @package um\core
*/
class Password {
2017-07-26 14:57:52 +03:00
2023-06-22 12:05:23 +03:00
/**
* @var bool
*/
2023-06-26 16:54:43 +03:00
private $change_password = false ;
2017-07-26 14:57:52 +03:00
2018-03-20 13:24:38 +02:00
/**
* Password constructor.
*/
2023-06-26 16:54:43 +03:00
public function __construct () {
2018-09-16 00:26:32 +03:00
add_shortcode ( 'ultimatemember_password' , array ( & $this , 'ultimatemember_password' ) );
2017-07-26 14:57:52 +03:00
2018-09-16 00:26:32 +03:00
add_action ( 'template_redirect' , array ( & $this , 'form_init' ), 10001 );
2017-07-26 14:57:52 +03:00
2018-09-16 00:26:32 +03:00
add_action ( 'um_reset_password_errors_hook' , array ( & $this , 'um_reset_password_errors_hook' ) );
2023-06-26 16:54:43 +03:00
add_action ( 'um_reset_password_process_hook' , array ( & $this , 'um_reset_password_process_hook' ) );
2017-07-26 14:57:52 +03:00
2018-09-16 00:26:32 +03:00
add_action ( 'um_change_password_errors_hook' , array ( & $this , 'um_change_password_errors_hook' ) );
2023-06-26 16:54:43 +03:00
add_action ( 'um_change_password_process_hook' , array ( & $this , 'um_change_password_process_hook' ) );
2018-03-20 13:24:38 +02:00
}
2017-07-26 14:57:52 +03:00
2018-03-20 13:24:38 +02:00
/**
2018-09-16 00:26:32 +03:00
* Get Reset URL
*
2025-04-23 14:35:38 +03:00
* @param int|null $user_id
*
* @return string
2018-03-20 13:24:38 +02:00
*/
2025-04-23 14:35:38 +03:00
public function reset_url ( $user_id = null ) {
2024-02-22 22:01:07 +02:00
static $reset_key = null ;
2025-04-23 14:35:38 +03:00
if ( is_null ( $user_id ) ) {
$user_id = um_user ( 'ID' );
}
2017-07-26 14:57:52 +03:00
2018-09-16 00:26:32 +03:00
delete_option ( " um_cache_userdata_ { $user_id } " );
2017-07-26 14:57:52 +03:00
2024-02-22 22:01:07 +02:00
// New reset password key via WordPress native field. It maybe already exists here but generated twice to make sure that emailed with a proper and fresh hash.
// But doing that only once in 1 request using static variable. Different email placeholders can use reset_url() and we have to use 1 time generated to avoid invalid keys.
2018-09-16 00:26:32 +03:00
$user_data = get_userdata ( $user_id );
2025-04-22 17:16:55 +03:00
if ( empty ( $user_data ) ) {
return '' ;
}
2024-02-22 22:01:07 +02:00
if ( empty ( $reset_key ) ) {
$reset_key = UM () -> user () -> maybe_generate_password_reset_key ( $user_data );
}
2022-08-11 21:49:19 +03:00
// this link looks like WordPress native link e.g. wp-login.php?action=rp&key={hash}&login={user_login}
$url = add_query_arg (
array (
'act' => 'reset_password' ,
2024-02-22 22:01:07 +02:00
'hash' => $reset_key ,
2024-04-01 16:37:33 +03:00
'login' => rawurlencode ( $user_data -> user_login ),
2022-08-11 21:49:19 +03:00
),
um_get_core_page ( 'password-reset' )
);
2018-09-16 00:26:32 +03:00
return $url ;
}
2017-07-26 14:57:52 +03:00
2018-09-16 00:26:32 +03:00
/**
* Add class based on shortcode
*
* @param string $mode
*
* @return string
*/
function get_class ( $mode ) {
2017-07-26 14:57:52 +03:00
2018-09-16 00:26:32 +03:00
$classes = 'um-' . $mode ;
2017-07-26 14:57:52 +03:00
2018-09-16 00:26:32 +03:00
if ( is_admin () ) {
$classes .= ' um-in-admin' ;
}
2018-03-20 13:24:38 +02:00
2023-08-15 03:49:13 +03:00
if ( true === UM () -> fields () -> editing ) {
2018-09-16 00:26:32 +03:00
$classes .= ' um-editing' ;
2018-03-20 13:24:38 +02:00
}
2023-08-15 03:49:13 +03:00
if ( true === UM () -> fields () -> viewing ) {
2018-09-16 00:26:32 +03:00
$classes .= ' um-viewing' ;
}
/**
* UM hook
*
* @type filter
* @title um_form_official_classes__hook
* @description Change form additional classes
* @input_vars
* [{"var":"$classes","type":"string","desc":"Form additional classes"}]
* @change_log
* ["Since: 2.0"]
* @usage
* <?php add_filter( 'um_form_official_classes__hook', 'function_name', 10, 1 ); ?>
* @example
* <?php
* add_filter( 'um_form_official_classes__hook', 'my_form_official_classes', 10, 1 );
* function my_form_official_classes( $classes ) {
* // your code here
* return $classes;
* }
* ?>
*/
$classes = apply_filters ( 'um_form_official_classes__hook' , $classes );
return $classes ;
2018-03-20 13:24:38 +02:00
}
/**
2018-09-16 00:26:32 +03:00
* Shortcode
2018-03-20 13:24:38 +02:00
*
2018-09-16 00:26:32 +03:00
* @param array $args
*
* @return string
2018-03-20 13:24:38 +02:00
*/
2023-06-22 12:50:44 +03:00
public function ultimatemember_password ( $args = array () ) {
2023-06-26 16:54:43 +03:00
/** There is possible to use 'shortcode_atts_ultimatemember_password' filter for getting customized $atts. This filter is documented in wp-includes/shortcodes.php "shortcode_atts_{$shortcode}" */
$args = shortcode_atts (
array (
'template' => 'password-reset' ,
'mode' => 'password' ,
'form_id' => 'um_password_id' ,
'max_width' => '450px' ,
'align' => 'center' ,
),
$args ,
'ultimatemember_password'
2018-09-16 00:26:32 +03:00
);
2018-03-20 13:24:38 +02:00
2018-09-16 00:26:32 +03:00
if ( empty ( $args [ 'use_custom_settings' ] ) ) {
$args = array_merge ( $args , UM () -> shortcodes () -> get_css_args ( $args ) );
} else {
$args = array_merge ( UM () -> shortcodes () -> get_css_args ( $args ), $args );
}
/**
2023-06-22 12:50:44 +03:00
* Filters extend Reset Password Arguments
2018-09-16 00:26:32 +03:00
*
2023-06-26 16:54:43 +03:00
* @since 1.3.x
2023-06-22 12:50:44 +03:00
* @hook um_reset_password_shortcode_args_filter
*
2023-06-26 16:54:43 +03:00
* @param {array} $args Shortcode arguments.
2023-06-22 12:50:44 +03:00
*
2023-06-26 16:54:43 +03:00
* @return {array} Shortcode arguments.
2023-06-22 12:50:44 +03:00
*
* @example <caption>Extend Reset Password Arguments.</caption>
2018-09-16 00:26:32 +03:00
* function my_reset_password_shortcode_args( $args ) {
* // your code here
* return $args;
* }
2023-06-22 12:50:44 +03:00
* add_filter( 'um_reset_password_shortcode_args_filter', 'my_reset_password_shortcode_args', 10, 1 );
2018-09-16 00:26:32 +03:00
*/
$args = apply_filters ( 'um_reset_password_shortcode_args_filter' , $args );
2023-06-26 16:54:43 +03:00
if ( false !== $this -> change_password ) {
2022-08-11 21:49:19 +03:00
// then COOKIE are valid then get data from them and populate hidden fields for the password reset form
2024-01-17 16:06:58 +02:00
$args [ 'rp_mode' ] = 'pw_change' ;
2018-09-16 00:26:32 +03:00
$args [ 'template' ] = 'password-change' ;
2022-08-11 21:49:19 +03:00
$args [ 'rp_key' ] = '' ;
2023-06-22 12:50:44 +03:00
$rp_cookie = 'wp-resetpass-' . COOKIEHASH ;
2018-09-16 00:26:32 +03:00
if ( isset ( $_COOKIE [ $rp_cookie ] ) && 0 < strpos ( $_COOKIE [ $rp_cookie ], ':' ) ) {
list ( $rp_login , $rp_key ) = explode ( ':' , wp_unslash ( $_COOKIE [ $rp_cookie ] ), 2 );
2022-08-11 21:49:19 +03:00
$args [ 'login' ] = $rp_login ;
2018-09-16 00:26:32 +03:00
$args [ 'rp_key' ] = $rp_key ;
2024-01-17 16:06:58 +02:00
$rp_user_obj = get_user_by ( 'login' , $rp_login );
if ( false !== $rp_user_obj ) {
$set_password_required = get_user_meta ( $rp_user_obj -> ID , 'um_set_password_required' , true );
if ( ! empty ( $set_password_required ) ) {
$args [ 'rp_mode' ] = 'pw_set' ;
}
}
2018-09-16 00:26:32 +03:00
}
}
2018-03-20 13:24:38 +02:00
2023-06-26 16:54:43 +03:00
if ( empty ( $args [ 'mode' ] ) || empty ( $args [ 'template' ] ) ) {
return '' ;
2023-06-22 12:50:44 +03:00
}
2018-03-20 13:24:38 +02:00
2023-08-23 15:00:21 +03:00
UM () -> fields () -> set_id = absint ( $args [ 'form_id' ] );
2023-06-22 12:50:44 +03:00
2023-06-26 16:54:43 +03:00
ob_start ();
2023-06-22 12:50:44 +03:00
2023-06-26 16:54:43 +03:00
/** This filter is documented in includes/core/class-shortcodes.php */
do_action ( " um_pre_ { $args [ 'mode' ] } _shortcode " , $args );
/** This filter is documented in includes/core/class-shortcodes.php */
do_action ( 'um_before_form_is_loaded' , $args );
/** This filter is documented in includes/core/class-shortcodes.php */
do_action ( " um_before_ { $args [ 'mode' ] } _form_is_loaded " , $args );
2018-09-16 00:26:32 +03:00
2023-06-26 16:54:43 +03:00
UM () -> shortcodes () -> template_load ( $args [ 'template' ], $args );
2018-03-20 13:24:38 +02:00
2018-09-16 00:26:32 +03:00
if ( ! is_admin () && ! defined ( 'DOING_AJAX' ) ) {
UM () -> shortcodes () -> dynamic_css ( $args );
}
2023-06-26 16:54:43 +03:00
return ob_get_clean ();
2018-03-20 13:24:38 +02:00
}
/**
2018-09-16 00:26:32 +03:00
* Check if a legitimate password reset request is in action
*
* @return bool
2018-03-20 13:24:38 +02:00
*/
2025-05-01 13:14:46 +03:00
public function is_reset_request () {
// phpcs:ignore WordPress.Security.NonceVerification -- already verified here
2025-05-12 15:39:52 +03:00
return ! empty ( $_POST [ '_um_password_reset' ] );
2018-09-16 00:26:32 +03:00
}
2018-03-20 13:24:38 +02:00
2018-09-16 00:26:32 +03:00
/**
* Check if a legitimate password change request is in action
*
2022-08-11 21:49:19 +03:00
* works both for the Account > Password form and the Reset Password shortcode form
2018-09-16 00:26:32 +03:00
*
* @return bool
*/
2025-05-12 15:39:52 +03:00
public function is_change_request () {
// phpcs:ignore WordPress.Security.NonceVerification -- already verified here
if ( ! empty ( $_POST [ '_um_account' ] ) && isset ( $_POST [ '_um_account_tab' ] ) && 'password' === sanitize_key ( $_POST [ '_um_account_tab' ] ) ) {
2018-09-16 00:26:32 +03:00
return true ;
2025-05-12 15:39:52 +03:00
}
if ( ! empty ( $_POST [ '_um_password_change' ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification -- already verified here
2018-09-16 00:26:32 +03:00
return true ;
2018-03-20 13:24:38 +02:00
}
2018-09-16 00:26:32 +03:00
return false ;
2018-03-20 13:24:38 +02:00
}
/**
* Password page form
*/
2021-06-29 02:51:54 +03:00
public function form_init () {
2018-09-16 00:26:32 +03:00
if ( um_is_core_page ( 'password-reset' ) ) {
UM () -> fields () -> set_mode = 'password' ;
}
2022-08-11 21:49:19 +03:00
// validate $rp_cookie and hash via check_password_reset_key
2021-06-29 02:51:54 +03:00
if ( um_is_core_page ( 'password-reset' ) && isset ( $_REQUEST [ 'act' ] ) && 'reset_password' === sanitize_key ( $_REQUEST [ 'act' ] ) ) {
2019-03-22 14:12:44 +02:00
wp_fix_server_vars ();
2018-09-16 00:26:32 +03:00
$rp_cookie = 'wp-resetpass-' . COOKIEHASH ;
2019-03-22 14:12:44 +02:00
2022-08-11 21:49:19 +03:00
if ( isset ( $_GET [ 'hash' ] ) && isset ( $_GET [ 'login' ] ) ) {
$value = sprintf ( '%s:%s' , wp_unslash ( $_GET [ 'login' ] ), wp_unslash ( $_GET [ 'hash' ] ) );
$this -> setcookie ( $rp_cookie , $value );
2023-07-18 12:06:17 +03:00
// Not `um_safe_redirect()` because password-reset page is predefined page and is situated on the same host.
2022-08-11 21:49:19 +03:00
wp_safe_redirect ( remove_query_arg ( array ( 'hash' , 'login' ) ) );
2018-09-16 00:26:32 +03:00
exit ;
}
if ( isset ( $_COOKIE [ $rp_cookie ] ) && 0 < strpos ( $_COOKIE [ $rp_cookie ], ':' ) ) {
list ( $rp_login , $rp_key ) = explode ( ':' , wp_unslash ( $_COOKIE [ $rp_cookie ] ), 2 );
2022-08-11 21:49:19 +03:00
2018-09-16 00:26:32 +03:00
$user = check_password_reset_key ( $rp_key , $rp_login );
2022-08-11 21:49:19 +03:00
if ( isset ( $_POST [ 'user_password' ] ) && ! hash_equals ( $rp_key , $_POST [ 'rp_key' ] ) ) {
$user = false ;
}
2018-09-16 00:26:32 +03:00
} else {
$user = false ;
}
2022-08-11 21:49:19 +03:00
if ( ! $user || is_wp_error ( $user ) ) {
2019-04-01 17:24:45 +03:00
$this -> setcookie ( $rp_cookie , false );
2022-08-11 21:49:19 +03:00
if ( $user && 'expired_key' === $user -> get_error_code () ) {
wp_redirect ( add_query_arg ( array ( 'updated' => 'expiredkey' ), um_get_core_page ( 'password-reset' ) ) );
2018-09-16 00:26:32 +03:00
} else {
2022-08-11 21:49:19 +03:00
wp_redirect ( add_query_arg ( array ( 'updated' => 'invalidkey' ), um_get_core_page ( 'password-reset' ) ) );
2018-09-16 00:26:32 +03:00
}
exit ;
}
2022-08-11 21:49:19 +03:00
// this variable is used for populating the reset password form via the hash and login
2018-09-16 00:26:32 +03:00
$this -> change_password = true ;
}
if ( $this -> is_reset_request () ) {
2023-07-04 16:47:32 +03:00
$form_data = array (
'mode' => 'password' ,
);
2023-03-01 14:54:30 +02:00
UM () -> form () -> post_form = wp_unslash ( $_POST );
2018-03-20 13:24:38 +02:00
2018-06-21 17:27:36 +03:00
if ( empty ( UM () -> form () -> post_form [ 'mode' ] ) ) {
UM () -> form () -> post_form [ 'mode' ] = 'password' ;
}
2018-03-20 13:24:38 +02:00
/**
2023-07-04 16:47:32 +03:00
* Fires for handle validate errors on the reset password form submit.
2018-03-20 13:24:38 +02:00
*
2023-07-04 16:47:32 +03:00
* @since 1.3.x
* @since 2.6.8 Added $form_data attribute.
*
* @hook um_reset_password_errors_hook
*
* @param {array} $submission_data Form submitted data.
* @param {array} $form_data Form data. Since 2.6.8
*
* @example <caption>Make any custom validation on password reset form.</caption>
* function my_reset_password_errors( $submission_data, $form_data ) {
2018-03-20 13:24:38 +02:00
* // your code here
* }
2023-07-04 16:47:32 +03:00
* add_action( 'um_reset_password_errors_hook', 'my_reset_password_errors', 10, 2 );
2018-03-20 13:24:38 +02:00
*/
2023-07-04 16:47:32 +03:00
do_action ( 'um_reset_password_errors_hook' , UM () -> form () -> post_form , $form_data );
2018-03-20 13:24:38 +02:00
if ( ! isset ( UM () -> form () -> errors ) ) {
/**
2023-07-04 16:47:32 +03:00
* Fires for handle the reset password form when submitted data is valid.
*
* @since 1.3.x
* @since 2.6.8 Added $form_data attribute.
*
* @hook um_reset_password_process_hook
*
* @param {array} $submission_data Form submitted data.
* @param {array} $form_data Form data. Since 2.6.8
2018-03-20 13:24:38 +02:00
*
2023-07-04 16:47:32 +03:00
* @example <caption>Make any custom action when password reset form is submitted.</caption>
* function my_reset_password_process( $submission_data, $form_data ) {
2018-03-20 13:24:38 +02:00
* // your code here
* }
2023-07-04 16:47:32 +03:00
* add_action( 'um_reset_password_process_hook', 'my_reset_password_process', 10, 2 );
2018-03-20 13:24:38 +02:00
*/
2023-07-04 16:47:32 +03:00
do_action ( 'um_reset_password_process_hook' , UM () -> form () -> post_form , $form_data );
2018-03-20 13:24:38 +02:00
}
}
2018-09-16 00:26:32 +03:00
if ( $this -> is_change_request () ) {
2025-02-04 23:13:49 +02:00
$formdata = wp_unslash ( $_POST );
2025-02-12 17:47:19 +02:00
// Don't un-slash passwords in manner of WordPress native password field.
$fields_map = array (
'user_password' ,
'confirm_user_password' ,
);
$formdata = UM () -> form () :: ignore_formdata_unslash ( $formdata , $fields_map );
2025-02-04 23:13:49 +02:00
UM () -> form () -> post_form = $formdata ;
2018-03-20 13:24:38 +02:00
/**
* UM hook
*
* @type action
* @title um_change_password_errors_hook
* @description Action on change password submit form
* @input_vars
* [{"var":"$post","type":"array","desc":"Form submitted"}]
* @change_log
* ["Since: 2.0"]
* @usage add_action( 'um_change_password_errors_hook', 'function_name', 10, 1 );
* @example
* <?php
* add_action( 'um_change_password_errors_hook', 'my_change_password_errors', 10, 1 );
* function my_change_password_errors( $post ) {
* // your code here
* }
* ?>
*/
do_action ( 'um_change_password_errors_hook' , UM () -> form () -> post_form );
if ( ! isset ( UM () -> form () -> errors ) ) {
/**
* UM hook
*
* @type action
* @title um_change_password_process_hook
* @description Action on change password success submit form
* @input_vars
* [{"var":"$post","type":"array","desc":"Form submitted"}]
* @change_log
* ["Since: 2.0"]
* @usage add_action( 'um_change_password_process_hook', 'function_name', 10, 1 );
* @example
* <?php
* add_action( 'um_change_password_process_hook', 'my_change_password_process', 10, 1 );
* function my_change_password_process( $post ) {
* // your code here
* }
* ?>
*/
do_action ( 'um_change_password_process_hook' , UM () -> form () -> post_form );
}
}
}
/**
2018-09-16 00:26:32 +03:00
* Error handler: reset password
2018-03-20 13:24:38 +02:00
*
2018-09-16 00:26:32 +03:00
* @param $args
2018-03-20 13:24:38 +02:00
*/
2021-06-29 02:51:54 +03:00
public function um_reset_password_errors_hook ( $args ) {
2023-01-10 13:11:18 +01:00
if ( isset ( $args [ UM () -> honeypot ] ) && '' !== $args [ UM () -> honeypot ] ) {
2021-06-29 02:51:54 +03:00
wp_die ( esc_html__ ( 'Hello, spam bot!' , 'ultimate-member' ) );
2019-03-26 12:55:57 +02:00
}
2018-03-20 13:24:38 +02:00
2021-06-29 02:51:54 +03:00
$user = '' ;
foreach ( $args as $key => $val ) {
if ( strstr ( $key , 'username_b' ) ) {
$user = trim ( sanitize_text_field ( $val ) );
2018-09-16 00:26:32 +03:00
}
2018-03-20 13:24:38 +02:00
}
2018-09-16 00:26:32 +03:00
if ( empty ( $user ) ) {
2021-06-29 02:51:54 +03:00
UM () -> form () -> add_error ( 'username_b' , __ ( 'Please provide your username or email' , 'ultimate-member' ) );
2018-03-20 13:24:38 +02:00
}
2021-12-14 18:31:47 +02:00
if ( ( ! is_email ( $user ) && username_exists ( $user ) ) || ( is_email ( $user ) && email_exists ( $user ) ) ) {
2018-09-16 00:26:32 +03:00
if ( is_email ( $user ) ) {
$user_id = email_exists ( $user );
} else {
$user_id = username_exists ( $user );
}
2019-03-26 12:55:57 +02:00
$attempts = ( int ) get_user_meta ( $user_id , 'password_rst_attempts' , true );
2021-06-29 02:51:54 +03:00
$is_admin = user_can ( absint ( $user_id ), 'manage_options' );
2018-09-16 00:26:32 +03:00
if ( UM () -> options () -> get ( 'enable_reset_password_limit' ) ) { // if reset password limit is set
2021-06-29 02:51:54 +03:00
if ( ! ( UM () -> options () -> get ( 'disable_admin_reset_password_limit' ) && $is_admin ) ) {
// Doesn't trigger this when a user has admin capabilities and when reset password limit is disabled for admins
2018-09-16 00:26:32 +03:00
$limit = UM () -> options () -> get ( 'reset_password_limit_number' );
if ( $attempts >= $limit ) {
2021-06-29 02:51:54 +03:00
UM () -> form () -> add_error ( 'username_b' , __ ( 'You have reached the limit for requesting password change for this user already. Contact support if you cannot open the email' , 'ultimate-member' ) );
2018-09-16 00:26:32 +03:00
} else {
update_user_meta ( $user_id , 'password_rst_attempts' , $attempts + 1 );
}
}
}
2018-03-20 13:24:38 +02:00
}
}
2018-09-16 00:26:32 +03:00
2018-03-20 13:24:38 +02:00
/**
2018-09-16 00:26:32 +03:00
* Process a new request
2018-03-20 13:24:38 +02:00
*
2018-09-16 00:26:32 +03:00
* @param $args
2018-03-20 13:24:38 +02:00
*/
2021-06-29 02:51:54 +03:00
public function um_reset_password_process_hook ( $args ) {
2018-09-16 00:26:32 +03:00
$user = null ;
2021-06-29 02:51:54 +03:00
foreach ( $args as $key => $val ) {
if ( strstr ( $key , 'username_b' ) ) {
$user = trim ( sanitize_text_field ( $val ) );
2018-09-16 00:26:32 +03:00
}
}
if ( username_exists ( $user ) ) {
$data = get_user_by ( 'login' , $user );
} elseif ( email_exists ( $user ) ) {
$data = get_user_by ( 'email' , $user );
}
2021-12-15 02:46:47 +02:00
if ( isset ( $data ) && is_a ( $data , '\WP_User' ) ) {
um_fetch_user ( $data -> ID );
2024-12-19 17:24:52 +02:00
if ( false === UM () -> options () -> get ( 'only_approved_user_reset_password' ) || UM () -> common () -> users () -> has_status ( $data -> ID , 'approved' ) ) {
2025-04-22 17:16:55 +03:00
UM () -> user () -> password_reset ( $data -> ID );
2024-12-19 17:24:52 +02:00
}
2021-12-15 02:46:47 +02:00
}
2018-09-16 00:26:32 +03:00
2024-12-19 17:24:52 +02:00
wp_safe_redirect ( um_get_core_page ( 'password-reset' , 'checkemail' ) );
2022-08-11 21:49:19 +03:00
exit ;
2018-03-20 13:24:38 +02:00
}
/**
2018-09-16 00:26:32 +03:00
* Error handler: changing password
2018-03-20 13:24:38 +02:00
*
2022-08-11 21:49:19 +03:00
* It works both for the Reset Password Shortcode and Account > Change password form
*
2018-03-20 13:24:38 +02:00
* @param $args
*/
2021-06-29 02:51:54 +03:00
public function um_change_password_errors_hook ( $args ) {
if ( isset ( $args [ UM () -> honeypot ] ) && '' !== $args [ UM () -> honeypot ] ) {
wp_die ( esc_html__ ( 'Hello, spam bot!' , 'ultimate-member' ) );
2018-09-16 00:26:32 +03:00
}
2018-03-20 13:24:38 +02:00
2025-05-12 15:39:52 +03:00
if ( ! empty ( $args [ '_um_account' ] ) && isset ( $args [ '_um_account_tab' ] ) && 'password' === sanitize_key ( $args [ '_um_account_tab' ] ) ) {
2022-08-11 21:49:19 +03:00
// validate for security on the account change password page
if ( ! is_user_logged_in () ) {
wp_die ( esc_html__ ( 'This is not possible for security reasons.' , 'ultimate-member' ) );
}
2018-09-16 00:26:32 +03:00
}
2018-03-20 13:24:38 +02:00
2022-12-13 14:53:35 +02:00
if ( ! empty ( $args [ 'user_password' ] ) && UM () -> options () -> get ( 'change_password_request_limit' ) && is_user_logged_in () ) {
$transient_id = '_um_change_password_rate_limit__' . um_user ( 'ID' );
$last_request = get_transient ( $transient_id );
$request_limit_time = apply_filters ( 'um_change_password_attempt_limit_interval' , 30 * MINUTE_IN_SECONDS );
if ( ! $last_request ) {
set_transient ( $transient_id , time (), $request_limit_time );
} else {
UM () -> form () -> add_error ( 'user_password' , __ ( 'Unable to change password because of password change limit. Please try again later.' , 'ultimate-member' ) );
return ;
}
}
2018-09-16 00:26:32 +03:00
if ( isset ( $args [ 'user_password' ] ) && empty ( $args [ 'user_password' ] ) ) {
2020-08-03 18:06:26 +03:00
UM () -> form () -> add_error ( 'user_password' , __ ( 'You must enter a new password' , 'ultimate-member' ) );
2024-02-28 20:18:51 +02:00
return ;
2018-03-20 13:24:38 +02:00
}
2021-06-29 02:51:54 +03:00
if ( isset ( $args [ 'user_password' ] ) ) {
2022-06-10 01:53:35 +03:00
$args [ 'user_password' ] = trim ( $args [ 'user_password' ] );
2021-06-29 02:51:54 +03:00
}
2022-08-11 21:49:19 +03:00
2021-06-29 02:51:54 +03:00
if ( isset ( $args [ 'confirm_user_password' ] ) ) {
2022-06-10 01:53:35 +03:00
$args [ 'confirm_user_password' ] = trim ( $args [ 'confirm_user_password' ] );
}
// Check for "\" in password.
if ( false !== strpos ( wp_unslash ( $args [ 'user_password' ] ), '\\' ) ) {
UM () -> form () -> add_error ( 'user_password' , __ ( 'Passwords may not contain the character "\\".' , 'ultimate-member' ) );
2021-06-29 02:51:54 +03:00
}
2021-12-14 17:44:07 +02:00
if ( UM () -> options () -> get ( 'require_strongpass' ) ) {
2022-12-13 15:25:32 +02:00
wp_fix_server_vars ();
$rp_cookie = 'wp-resetpass-' . COOKIEHASH ;
if ( ! is_user_logged_in () && isset ( $_COOKIE [ $rp_cookie ] ) && 0 < strpos ( $_COOKIE [ $rp_cookie ], ':' ) ) {
list ( $rp_login , $rp_key ) = explode ( ':' , wp_unslash ( $_COOKIE [ $rp_cookie ] ), 2 );
$user = check_password_reset_key ( $rp_key , $rp_login );
um_fetch_user ( $user -> ID );
} elseif ( is_user_logged_in () ) {
um_fetch_user ( get_current_user_id () );
}
2021-09-21 13:25:49 +03:00
$min_length = UM () -> options () -> get ( 'password_min_chars' );
$min_length = ! empty ( $min_length ) ? $min_length : 8 ;
$max_length = UM () -> options () -> get ( 'password_max_chars' );
$max_length = ! empty ( $max_length ) ? $max_length : 30 ;
2022-12-13 15:25:32 +02:00
$user_login = um_user ( 'user_login' );
$user_email = um_user ( 'user_email' );
2021-09-21 13:25:49 +03:00
2022-06-10 01:53:35 +03:00
if ( mb_strlen ( wp_unslash ( $args [ 'user_password' ] ) ) < $min_length ) {
2023-07-13 11:36:29 +03:00
// translators: %s: min length.
2021-09-21 18:26:57 +03:00
UM () -> form () -> add_error ( 'user_password' , sprintf ( __ ( 'Your password must contain at least %d characters' , 'ultimate-member' ), $min_length ) );
2018-09-16 00:26:32 +03:00
}
2018-03-20 13:24:38 +02:00
2022-06-10 01:53:35 +03:00
if ( mb_strlen ( wp_unslash ( $args [ 'user_password' ] ) ) > $max_length ) {
2023-07-13 11:36:29 +03:00
// translators: %s: max length.
2021-09-21 18:26:57 +03:00
UM () -> form () -> add_error ( 'user_password' , sprintf ( __ ( 'Your password must contain less than %d characters' , 'ultimate-member' ), $max_length ) );
2018-09-16 00:26:32 +03:00
}
2022-12-13 15:25:32 +02:00
if ( strpos ( strtolower ( $user_login ), strtolower ( $args [ 'user_password' ] ) ) > - 1 ) {
UM () -> form () -> add_error ( 'user_password' , __ ( 'Your password cannot contain the part of your username' , 'ultimate-member' ) );
}
if ( strpos ( strtolower ( $user_email ), strtolower ( $args [ 'user_password' ] ) ) > - 1 ) {
UM () -> form () -> add_error ( 'user_password' , __ ( 'Your password cannot contain the part of your email address' , 'ultimate-member' ) );
}
2018-09-16 00:26:32 +03:00
if ( ! UM () -> validation () -> strong_pass ( $args [ 'user_password' ] ) ) {
2020-08-03 18:06:26 +03:00
UM () -> form () -> add_error ( 'user_password' , __ ( 'Your password must contain at least one lowercase letter, one capital letter and one number' , 'ultimate-member' ) );
2018-09-16 00:26:32 +03:00
}
2018-03-20 13:24:38 +02:00
}
2018-09-16 00:26:32 +03:00
if ( isset ( $args [ 'confirm_user_password' ] ) && empty ( $args [ 'confirm_user_password' ] ) ) {
2020-08-03 18:06:26 +03:00
UM () -> form () -> add_error ( 'confirm_user_password' , __ ( 'You must confirm your new password' , 'ultimate-member' ) );
2018-09-16 00:26:32 +03:00
}
2021-06-29 02:51:54 +03:00
if ( isset ( $args [ 'user_password' ] ) && isset ( $args [ 'confirm_user_password' ] ) && $args [ 'user_password' ] !== $args [ 'confirm_user_password' ] ) {
2020-08-03 18:06:26 +03:00
UM () -> form () -> add_error ( 'confirm_user_password' , __ ( 'Your passwords do not match' , 'ultimate-member' ) );
2018-09-16 00:26:32 +03:00
}
}
/**
* Process a change request
*
* @param $args
*/
2021-06-29 02:51:54 +03:00
public function um_change_password_process_hook ( $args ) {
if ( isset ( $args [ '_um_password_change' ] ) && $args [ '_um_password_change' ] == 1 ) {
2022-08-11 21:49:19 +03:00
// it only works on the Password Reset Shortcode form
2019-03-26 12:55:57 +02:00
$rp_cookie = 'wp-resetpass-' . COOKIEHASH ;
2019-04-01 17:24:45 +03:00
2019-03-26 12:55:57 +02:00
if ( isset ( $_COOKIE [ $rp_cookie ] ) && 0 < strpos ( $_COOKIE [ $rp_cookie ], ':' ) ) {
list ( $rp_login , $rp_key ) = explode ( ':' , wp_unslash ( $_COOKIE [ $rp_cookie ] ), 2 );
2022-08-11 21:49:19 +03:00
$user = check_password_reset_key ( $rp_key , $rp_login );
if ( isset ( $args [ 'user_password' ] ) && ! hash_equals ( $rp_key , $args [ 'rp_key' ] ) ) {
2019-03-26 12:55:57 +02:00
$user = false ;
}
} else {
$user = false ;
}
if ( ! $user || is_wp_error ( $user ) ) {
2019-04-01 17:24:45 +03:00
$this -> setcookie ( $rp_cookie , false );
2022-08-11 21:49:19 +03:00
if ( $user && 'expired_key' === $user -> get_error_code () ) {
wp_redirect ( add_query_arg ( array ( 'updated' => 'expiredkey' ), um_get_core_page ( 'password-reset' ) ) );
2019-03-26 12:55:57 +02:00
} else {
2022-08-11 21:49:19 +03:00
wp_redirect ( add_query_arg ( array ( 'updated' => 'invalidkey' ), um_get_core_page ( 'password-reset' ) ) );
2019-03-26 12:55:57 +02:00
}
exit ;
}
2018-09-17 16:53:40 +03:00
$errors = new \WP_Error ();
2022-08-11 21:49:19 +03:00
/** This action is documented in wp-login.php */
2018-09-17 16:53:40 +03:00
do_action ( 'validate_password_reset' , $errors , $user );
if ( ( ! $errors -> get_error_code () ) ) {
2022-06-10 01:53:35 +03:00
reset_password ( $user , trim ( $args [ 'user_password' ] ) );
2021-02-24 15:51:52 +02:00
// send the Password Changed Email
2022-08-11 21:49:19 +03:00
UM () -> user () -> password_changed ( $user -> ID );
2021-02-24 15:51:52 +02:00
// clear temporary data
2021-03-03 17:55:12 +02:00
$attempts = ( int ) get_user_meta ( $user -> ID , 'password_rst_attempts' , true );
if ( $attempts ) {
update_user_meta ( $user -> ID , 'password_rst_attempts' , 0 );
}
2019-04-01 17:24:45 +03:00
$this -> setcookie ( $rp_cookie , false );
2021-02-24 15:51:52 +02:00
2024-01-18 11:30:49 +02:00
$set_password_required = get_user_meta ( $user -> ID , 'um_set_password_required' , true );
if ( ! empty ( $set_password_required ) ) {
2024-01-17 16:06:58 +02:00
delete_user_meta ( $user -> ID , 'um_set_password_required' );
2024-01-16 14:00:22 +02:00
}
2019-03-06 19:44:33 +02:00
/**
* UM hook
*
* @type action
* @title um_after_changing_user_password
* @description Hook that runs after user change their password
* @input_vars
* [{"var":"$user_id","type":"int","desc":"User ID"}]
* @change_log
* ["Since: 2.0"]
* @usage add_action( 'um_after_changing_user_password', 'function_name', 10, 1 );
* @example
* <?php
* add_action( 'um_after_changing_user_password', 'my_after_changing_user_password', 10, 1 );
* function my_user_login_extra( $user_id ) {
* // your code here
* }
* ?>
*/
2022-08-11 21:49:19 +03:00
do_action ( 'um_after_changing_user_password' , $user -> ID );
2019-03-06 19:44:33 +02:00
2022-08-11 21:49:19 +03:00
if ( ! is_user_logged_in () ) {
$url = um_get_core_page ( 'login' , 'password_changed' );
} else {
$url = um_get_core_page ( 'password-reset' , 'password_changed' );
}
wp_redirect ( $url );
exit ;
2018-09-17 16:53:40 +03:00
}
2018-09-16 00:26:32 +03:00
}
2018-03-20 13:24:38 +02:00
}
2019-04-01 17:24:45 +03:00
/**
* Disable page caching and set or clear cookie
*
* @param string $name
* @param string $value
* @param int $expire
* @param string $path
*/
public function setcookie ( $name , $value = '' , $expire = 0 , $path = '' ) {
if ( empty ( $value ) ) {
$expire = time () - YEAR_IN_SECONDS ;
}
if ( empty ( $path ) ) {
list ( $path ) = explode ( '?' , wp_unslash ( $_SERVER [ 'REQUEST_URI' ] ) );
}
$levels = ob_get_level ();
for ( $i = 0 ; $i < $levels ; $i ++ ) {
@ ob_end_clean ();
}
nocache_headers ();
setcookie ( $name , $value , $expire , $path , COOKIE_DOMAIN , is_ssl (), true );
}
2019-05-06 17:22:57 +03:00
/**
* UM Placeholders for reset password
*
* @param $placeholders
*
* @return array
*/
function add_placeholder ( $placeholders ) {
$placeholders [] = '{password_reset_link}' ;
$placeholders [] = '{password}' ;
return $placeholders ;
}
/**
* UM Replace Placeholders for reset password
*
* @param $replace_placeholders
*
* @return array
*/
function add_replace_placeholder ( $replace_placeholders ) {
$replace_placeholders [] = um_user ( 'password_reset_link' );
$replace_placeholders [] = esc_html__ ( 'Your set password' , 'ultimate-member' );
return $replace_placeholders ;
}
2018-03-20 13:24:38 +02:00
}
2021-06-29 02:51:54 +03:00
}