From a6bcc5eff8ab3c2241f5c4e03af9749fc0397cd7 Mon Sep 17 00:00:00 2001 From: Ariful Hoque Date: Thu, 30 Apr 2026 11:14:22 +0600 Subject: [PATCH] Add change password UI and AJAX handler Introduce a new Change Password account section and full AJAX flow. Changes include: - Register a new account section key ('change-password') in wpuf_get_account_sections(). - Add a change-password dashboard template (templates/dashboard/change-password.php) with password strength meter, eye toggle, nonce, and AJAX submission UI. Enqueues zxcvbn/password-strength-meter and uses an eye icon asset when available. - Add Frontend_Account::change_password_section() to load the template and Frontend_Account::change_password() to handle the AJAX request: nonce and auth checks, input validation, current password verification, wp_update_user call, and JSON success/error responses. - Update includes/Ajax.php to instantiate Frontend_Account once and register the new wpuf_account_change_password AJAX action (logged-in only). - Add a menu icon for the change-password section in templates/account.php. This implements a complete frontend flow for users to change their password securely. --- includes/Ajax.php | 4 +- includes/Frontend/Frontend_Account.php | 82 +++++++++ templates/account.php | 5 + templates/dashboard/change-password.php | 219 ++++++++++++++++++++++++ wpuf-functions.php | 1 + 5 files changed, 310 insertions(+), 1 deletion(-) create mode 100644 templates/dashboard/change-password.php diff --git a/includes/Ajax.php b/includes/Ajax.php index 07e1e7064..3e4a2a4bc 100644 --- a/includes/Ajax.php +++ b/includes/Ajax.php @@ -44,7 +44,9 @@ public function __construct() { $this->register_ajax( 'wpuf_draft_post', [ new Frontend\Frontend_Form(), 'draft_post' ] ); $this->register_ajax( 'wpuf_delete_user_package', [ new Admin\Admin_Subscription(), 'delete_user_package' ], $this->logged_in_only ); $this->register_ajax( 'wpuf_address_ajax_action', [ new Ajax\Address_Form_Ajax(), 'ajax_form_action' ] ); - $this->register_ajax( 'wpuf_account_update_profile', [ new Frontend\Frontend_Account(), 'update_profile' ], $this->logged_in_only ); + $frontend_account = new Frontend\Frontend_Account(); + $this->register_ajax( 'wpuf_account_update_profile', [ $frontend_account, 'update_profile' ], $this->logged_in_only ); + $this->register_ajax( 'wpuf_account_change_password', [ $frontend_account, 'change_password' ], $this->logged_in_only ); $this->register_ajax( 'wpuf_import_forms', [ new Admin\Admin_Tools(), 'import_forms' ], $this->logged_in_only ); $this->register_ajax( 'wpuf_get_child_cat', 'wpuf_get_child_cats' ); $this->register_ajax( 'wpuf_ajax_address', 'wpuf_ajax_get_states_field' ); diff --git a/includes/Frontend/Frontend_Account.php b/includes/Frontend/Frontend_Account.php index f3fbab37c..a4ef38087 100644 --- a/includes/Frontend/Frontend_Account.php +++ b/includes/Frontend/Frontend_Account.php @@ -22,6 +22,7 @@ public function __construct() { } add_action( 'wpuf_account_content_subscription', [ $this, 'subscription_section' ], 10, 2 ); add_action( 'wpuf_account_content_edit-profile', [ $this, 'edit_profile_section' ], 10, 2 ); + add_action( 'wpuf_account_content_change-password', [ $this, 'change_password_section' ], 10, 2 ); add_action( 'wpuf_account_content_billing-address', [ $this, 'billing_address_section' ], 10, 2 ); // add_filter( 'wpuf_options_wpuf_my_account', [ $this, 'add_settings_options' ] ); @@ -282,6 +283,87 @@ public function edit_profile_section( $sections, $current_section ) { ] ); } + /** + * Display the change password section. + * + * @since WPUF_SINCE + * + * @param array $sections Account sections. + * @param string $current_section Active section slug. + * + * @return void + */ + public function change_password_section( $sections, $current_section ) { + wpuf_load_template( 'dashboard/change-password.php', [ + 'sections' => $sections, + 'current_section' => $current_section, + ] ); + } + + /** + * Handle change password AJAX request. + * + * @since WPUF_SINCE + * + * @return void Sends JSON response. + */ + public function change_password() { + $nonce = isset( $_POST['_wpnonce'] ) ? sanitize_key( wp_unslash( $_POST['_wpnonce'] ) ) : ''; + + if ( ! wp_verify_nonce( $nonce, 'wpuf-account-change-password' ) ) { + wp_send_json_error( __( 'Security check failed.', 'wp-user-frontend' ) ); + wp_die(); + } + + if ( ! is_user_logged_in() ) { + wp_send_json_error( __( 'You must be logged in.', 'wp-user-frontend' ) ); + wp_die(); + } + + global $current_user; + + $current_password = ! empty( $_POST['current_password'] ) ? wp_unslash( $_POST['current_password'] ) : ''; + $pass1 = ! empty( $_POST['pass1'] ) ? wp_unslash( $_POST['pass1'] ) : ''; + $pass2 = ! empty( $_POST['pass2'] ) ? wp_unslash( $_POST['pass2'] ) : ''; + + if ( empty( $current_password ) ) { + wp_send_json_error( __( 'Please enter your current password.', 'wp-user-frontend' ) ); + return; + } + + if ( empty( $pass1 ) ) { + wp_send_json_error( __( 'Please enter a new password.', 'wp-user-frontend' ) ); + return; + } + + if ( empty( $pass2 ) ) { + wp_send_json_error( __( 'Please confirm your new password.', 'wp-user-frontend' ) ); + return; + } + + if ( $pass1 !== $pass2 ) { + wp_send_json_error( __( 'New passwords do not match.', 'wp-user-frontend' ) ); + return; + } + + if ( ! wp_check_password( $current_password, $current_user->user_pass, $current_user->ID ) ) { + wp_send_json_error( __( 'Your current password is incorrect.', 'wp-user-frontend' ) ); + return; + } + + $result = wp_update_user( [ + 'ID' => $current_user->ID, + 'user_pass' => $pass1, + ] ); + + if ( is_wp_error( $result ) ) { + wp_send_json_error( __( 'Could not update password. Please try again.', 'wp-user-frontend' ) ); + return; + } + + wp_send_json_success( __( 'Password updated successfully!', 'wp-user-frontend' ) ); + } + /** * Display the billing address section * diff --git a/templates/account.php b/templates/account.php index 8b87705c5..ae3169793 100644 --- a/templates/account.php +++ b/templates/account.php @@ -100,6 +100,11 @@ class="wpuf-rounded-full wpuf-object-cover" case 'edit-profile': $icon = ''; break; + case 'change-password': + $icon = ' + + '; + break; case 'billing-address': $icon = ''; break; diff --git a/templates/dashboard/change-password.php b/templates/dashboard/change-password.php new file mode 100644 index 000000000..88c095634 --- /dev/null +++ b/templates/dashboard/change-password.php @@ -0,0 +1,219 @@ + + +
+ +
+

+ +

+
+ +
+

+ +

+
+ + +
+
+ + + + + +
+ +
+ + + + +
+
+ + +
+ +
+ + + + +
+ +
+ + +
+ +
+ + + + +
+
+ + +
+ + + + +
+ + + +
+
+
+ + diff --git a/wpuf-functions.php b/wpuf-functions.php index 7aa1fa051..37961d454 100644 --- a/wpuf-functions.php +++ b/wpuf-functions.php @@ -2298,6 +2298,7 @@ function wpuf_get_countries( $type = 'array' ) { function wpuf_get_account_sections() { $sections = [ 'edit-profile' => __( 'Edit Profile', 'wp-user-frontend' ), + 'change-password' => __( 'Change Password', 'wp-user-frontend' ), 'subscription' => __( 'Subscription', 'wp-user-frontend' ), 'billing-address' => __( 'Billing Address', 'wp-user-frontend' ), ];