Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion includes/Ajax.php
Original file line number Diff line number Diff line change
Expand Up @@ -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' );
Expand Down
82 changes: 82 additions & 0 deletions includes/Frontend/Frontend_Account.php
Original file line number Diff line number Diff line change
Expand Up @@ -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' ] );
Expand Down Expand Up @@ -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
*
Expand Down
5 changes: 5 additions & 0 deletions templates/account.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@
<?php if ( $avatar_data['url'] ) : ?>
<!-- Show avatar image (custom photo or Gravatar) -->
<img src="<?php echo esc_url( $avatar_data['url'] ); ?>"
alt="<?php echo esc_attr( $current_user->display_name ); ?>"

Check warning on line 19 in templates/account.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Found precision alignment of 1 spaces.
class="wpuf-rounded-full wpuf-object-cover"

Check warning on line 20 in templates/account.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Found precision alignment of 1 spaces.
width="<?php echo esc_attr( $avatar_size ); ?>"

Check warning on line 21 in templates/account.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Found precision alignment of 1 spaces.
height="<?php echo esc_attr( $avatar_size ); ?>"

Check warning on line 22 in templates/account.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Found precision alignment of 1 spaces.
style="width: <?php echo esc_attr( $avatar_size ); ?>px; height: <?php echo esc_attr( $avatar_size ); ?>px; object-fit: cover;" />

Check warning on line 23 in templates/account.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Found precision alignment of 1 spaces.
<?php else : ?>
<!-- Show initials (no image available) -->
<div class="wpuf-avatar-initials wpuf-rounded-full wpuf-bg-gray-400 wpuf-text-white wpuf-flex wpuf-items-center wpuf-justify-center wpuf-font-semibold"
style="width: <?php echo esc_attr( $avatar_size ); ?>px; height: <?php echo esc_attr( $avatar_size ); ?>px; font-size: <?php echo esc_attr( $avatar_data['font_size'] ); ?>px;">

Check warning on line 27 in templates/account.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Found precision alignment of 1 spaces.
<?php echo esc_html( $avatar_data['initials'] ); ?>
</div>
<?php endif; ?>
Expand All @@ -49,21 +49,21 @@
<nav class="wpuf-account-nav">
<ul class="wpuf-space-y-1">
<?php
if ( is_user_logged_in() ) {

Check failure on line 52 in templates/account.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Line indented incorrectly; expected 4 tabs, found 5
$section_param = isset( $_GET['section'] ) ? sanitize_text_field( wp_unslash( $_GET['section'] ) ) : null;

Check warning on line 53 in templates/account.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Processing form data without nonce verification.

Check warning on line 53 in templates/account.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Processing form data without nonce verification.

foreach ( $sections as $section => $label ) {

Check failure on line 55 in templates/account.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Line indented incorrectly; expected 5 tabs, found 6
// backward compatibility
if ( is_array( $label ) ) {

Check failure on line 57 in templates/account.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Line indented incorrectly; expected 6 tabs, found 7
$section = $label['slug'];
$label = $label['label'];
}

Check failure on line 60 in templates/account.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Line indented incorrectly; expected 6 tabs, found 7

if ( 'subscription' == $section ) {

Check warning on line 62 in templates/account.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Loose comparisons are not allowed. Expected: "==="; Found: "=="

Check failure on line 62 in templates/account.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Line indented incorrectly; expected 6 tabs, found 7
if ( 'off' == wpuf_get_option( 'show_subscriptions', 'wpuf_my_account', 'on' ) || 'on' != wpuf_get_option( 'enable_payment',

Check failure on line 63 in templates/account.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Opening parenthesis of a multi-line function call must be the last content on the line

Check warning on line 63 in templates/account.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Loose comparisons are not allowed. Expected: "==="; Found: "=="

Check failure on line 63 in templates/account.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Line indented incorrectly; expected 7 tabs, found 8
'wpuf_payment', 'on' ) ) {

Check failure on line 64 in templates/account.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Closing parenthesis of a multi-line function call must be on a line by itself

Check failure on line 64 in templates/account.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Multi-line function call not indented correctly; expected 32 spaces but found 139
continue;
}

Check failure on line 66 in templates/account.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Line indented incorrectly; expected 7 tabs, found 8
}

if ( 'billing-address' == $section ) {
Expand Down Expand Up @@ -100,6 +100,11 @@
case 'edit-profile':
$icon = '<svg class="wpuf-w-5 wpuf-h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path></svg>';
break;
case 'change-password':
$icon = '<svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.75 10.7857L9 13.0357L12.75 7.78574M9.75 0.75C7.5995 2.78662 4.69563 4.03575 1.5 4.03575C1.44922 4.03575 1.39852 4.03543 1.34789 4.03481C0.959898 5.21491 0.75 6.47584 0.75 7.7858C0.75 13.3773 4.57432 18.0756 9.75 19.4077C14.9257 18.0756 18.75 13.3773 18.75 7.7858C18.75 6.47584 18.5401 5.21491 18.1521 4.03481C18.1015 4.03543 18.0508 4.03575 18 4.03575C14.8044 4.03575 11.9005 2.78662 9.75 0.75Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>';
break;
case 'billing-address':
$icon = '<svg class="wpuf-w-5 wpuf-h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"></path></svg>';
break;
Expand Down
219 changes: 219 additions & 0 deletions templates/dashboard/change-password.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
<?php

ob_start();

$eye_icon_src = file_exists( WPUF_ROOT . '/assets/images/eye.svg' ) ? WPUF_ASSET_URI . '/images/eye.svg' : '';
wp_enqueue_script( 'zxcvbn' );
wp_enqueue_script( 'password-strength-meter' );
?>

<div class="wpuf-edit-profile-container">
<!-- Page Title -->
<div class="wpuf-bg-transparent wpuf-rounded-t-lg wpuf-mb-3">
<h2 class="wpuf-text-gray-700 wpuf-font-bold wpuf-text-[32px] wpuf-leading-[48px] wpuf-tracking-[0.13px] wpuf-m-0">
<?php esc_html_e( 'Change Password', 'wp-user-frontend' ); ?>
</h2>
</div>

<div class="wpuf-bg-transparent wpuf-mb-[48px]">
<p class="wpuf-text-gray-400 wpuf-font-normal wpuf-text-[18px] wpuf-leading-[24px] wpuf-tracking-[0.13px] wpuf-m-0">
<?php esc_html_e( 'Update your account password. Choose a strong, unique password to keep your account secure.', 'wp-user-frontend' ); ?>
</p>
</div>

<!-- Form Wrapper -->
<div style="border: 1px solid #E1E5E8; border-radius: 24px; padding: 48px;">
<form class="wpuf-form wpuf-change-password-form" action="" method="post">

<div style="display: none;" class="wpuf-success wpuf-bg-green-50 wpuf-border wpuf-border-green-200 wpuf-text-green-800 wpuf-rounded-lg wpuf-p-4"></div>
<div style="display: none;" class="wpuf-error wpuf-bg-red-50 wpuf-border wpuf-border-red-200 wpuf-text-red-800 wpuf-rounded-lg wpuf-p-4"></div>

<!-- Current Password -->
<div class="wpuf-form-group">
<label for="wpuf_current_password" class="wpuf-form-label">
<?php esc_html_e( 'Current Password', 'wp-user-frontend' ); ?>
<span class="wpuf-help-tip" title="<?php esc_attr_e( 'Required to verify your identity before changing the password.', 'wp-user-frontend' ); ?>">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display:inline-block;vertical-align:middle;margin-left:4px;cursor:help;color:#9CA3AF;">
<circle cx="12" cy="12" r="10"></circle>
<line x1="12" y1="16" x2="12" y2="12"></line>
<line x1="12" y1="8" x2="12.01" y2="8"></line>
</svg>
</span>
</label>
<div class="wpuf-password-field">
<input
type="password"
name="current_password"
id="wpuf_current_password"
placeholder="<?php esc_attr_e( 'Enter current password', 'wp-user-frontend' ); ?>"
class="wpuf-form-input"
autocomplete="current-password"
/>
<?php if ( $eye_icon_src ) : ?>
<img class="wpuf-eye wpuf-password-toggle" src="<?php echo esc_url( $eye_icon_src ); ?>" alt="">
<?php endif; ?>
</div>
</div>

<!-- New Password -->
<div class="wpuf-form-group">
<label for="wpuf_pass1" class="wpuf-form-label">
<?php esc_html_e( 'New Password', 'wp-user-frontend' ); ?>
<span class="wpuf-help-tip" title="<?php esc_attr_e( 'Must be at least 8 characters. Use a mix of letters, numbers, and symbols for a stronger password.', 'wp-user-frontend' ); ?>">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display:inline-block;vertical-align:middle;margin-left:4px;cursor:help;color:#9CA3AF;">
<circle cx="12" cy="12" r="10"></circle>
<line x1="12" y1="16" x2="12" y2="12"></line>
<line x1="12" y1="8" x2="12.01" y2="8"></line>
</svg>
</span>
</label>
<div class="wpuf-password-field">
<input
type="password"
name="pass1"
id="wpuf_pass1"
placeholder="<?php esc_attr_e( 'Enter new password', 'wp-user-frontend' ); ?>"
class="wpuf-form-input"
autocomplete="new-password"
/>
<?php if ( $eye_icon_src ) : ?>
<img class="wpuf-eye wpuf-password-toggle" src="<?php echo esc_url( $eye_icon_src ); ?>" alt="">
<?php endif; ?>
</div>
<span class="wpuf-password-strength" id="wpuf-cp-pass-strength-result"><?php esc_html_e( 'Strength indicator', 'wp-user-frontend' ); ?></span>
</div>

<!-- Confirm New Password -->
<div class="wpuf-form-group">
<label for="wpuf_pass2" class="wpuf-form-label">
<?php esc_html_e( 'Confirm New Password', 'wp-user-frontend' ); ?>
<span class="wpuf-help-tip" title="<?php esc_attr_e( 'Must match the new password entered above.', 'wp-user-frontend' ); ?>">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display:inline-block;vertical-align:middle;margin-left:4px;cursor:help;color:#9CA3AF;">
<circle cx="12" cy="12" r="10"></circle>
<line x1="12" y1="16" x2="12" y2="12"></line>
<line x1="12" y1="8" x2="12.01" y2="8"></line>
</svg>
</span>
</label>
<div class="wpuf-password-field">
<input
type="password"
name="pass2"
id="wpuf_pass2"
placeholder="<?php esc_attr_e( 'Re-enter new password', 'wp-user-frontend' ); ?>"
class="wpuf-form-input"
autocomplete="new-password"
/>
<?php if ( $eye_icon_src ) : ?>
<img class="wpuf-eye wpuf-password-toggle" src="<?php echo esc_url( $eye_icon_src ); ?>" alt="">
<?php endif; ?>
</div>
</div>

<!-- Submit Buttons -->
<div class="wpuf-form-actions">
<?php wp_nonce_field( 'wpuf-account-change-password' ); ?>
<input type="hidden" name="action" value="wpuf_account_change_password">
<button
type="submit"
id="wpuf-change-password-submit"
class="wpuf-btn wpuf-btn-primary"
>
<?php esc_html_e( 'Update Password', 'wp-user-frontend' ); ?>
</button>
<button
type="button"
class="wpuf-btn wpuf-btn-secondary"
onclick="window.location.reload();"
>
<?php esc_html_e( 'Cancel', 'wp-user-frontend' ); ?>
</button>
</div>

<script type="text/javascript">
jQuery(function($) {
// Password strength meter
function wpuf_cp_check_pass_strength() {
var pass1 = $('#wpuf_pass1').val(),
pass2 = $('#wpuf_pass2').val(),
strength;

var pwsL10n = {
empty: '<?php echo esc_js( __( 'Strength indicator', 'wp-user-frontend' ) ); ?>',
short: '<?php echo esc_js( __( 'Very weak', 'wp-user-frontend' ) ); ?>',
bad: '<?php echo esc_js( __( 'Weak', 'wp-user-frontend' ) ); ?>',
good: '<?php echo esc_js( __( 'Medium', 'wp-user-frontend' ) ); ?>',
strong: '<?php echo esc_js( __( 'Strong', 'wp-user-frontend' ) ); ?>',
mismatch: '<?php echo esc_js( __( 'Mismatch', 'wp-user-frontend' ) ); ?>'
};

$('#wpuf-cp-pass-strength-result').removeClass('short bad good strong');

if ( ! pass1 ) {
$('#wpuf-cp-pass-strength-result').html(pwsL10n.empty);
return;
}

strength = wp.passwordStrength.meter(pass1, wp.passwordStrength.userInputBlacklist(), pass2);

switch (strength) {
case 2:
$('#wpuf-cp-pass-strength-result').addClass('bad').html(pwsL10n.bad);
break;
case 3:
$('#wpuf-cp-pass-strength-result').addClass('good').html(pwsL10n.good);
break;
case 4:
$('#wpuf-cp-pass-strength-result').addClass('strong').html(pwsL10n.strong);
break;
case 5:
$('#wpuf-cp-pass-strength-result').addClass('short').html(pwsL10n.mismatch);
break;
default:
$('#wpuf-cp-pass-strength-result').addClass('short').html(pwsL10n.short);
}
}

$('#wpuf_pass1').val('').on('keyup', wpuf_cp_check_pass_strength);
$('#wpuf_pass2').val('').on('keyup', wpuf_cp_check_pass_strength);
$('#wpuf-cp-pass-strength-result').show();

// AJAX form submit
$('.wpuf-change-password-form').on('submit', function(e) {
e.preventDefault();

var $form = $(this);
var $btn = $form.find('#wpuf-change-password-submit');
var $success = $form.find('.wpuf-success');
var $error = $form.find('.wpuf-error');

$success.hide();
$error.hide();
$btn.prop('disabled', true);

$.post(
wpuf_frontend.ajaxurl,
$form.serialize(),
function(response) {
$btn.prop('disabled', false);
if ( response.success ) {
$success.text(response.data).show();
$form.find('input[type="password"]').val('');
$('#wpuf-cp-pass-strength-result').html('<?php echo esc_js( __( 'Strength indicator', 'wp-user-frontend' ) ); ?>').removeClass('short bad good strong');
} else {
$error.text(response.data).show();
}
}
);
});
});
</script>

</form>
</div><!-- Close form wrapper -->
</div>

<?php
$output = ob_get_clean();
echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
?>
1 change: 1 addition & 0 deletions wpuf-functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -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' ),
];
Expand Down
Loading