Reset password form template
Overview
The reset password form template (lost_password_reset_form.php) is where users enter their new password after clicking the reset link in their email. This template includes real-time password validation, visual feedback for password requirements, and an optional password visibility toggle.
File location: templates/lost_password_reset_form.php
Stage: 2 (Reset)
When displayed: When users click the reset link in their email. The URL contains somresetpass=true, key, and uid parameters.
Template structure
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// Get design settings for eye toggle
$design_options = get_option( 'somfrp_design_settings' );
$somfrp_enable_eye = ( ! isset( $design_options['somfrp_enable_eye_toggle'] )
|| $design_options['somfrp_enable_eye_toggle'] === 'on' );
?>
<div id="password-lost-form-wrap">
<!-- Error messages -->
<form id="resetpasswordform" method="post">
<fieldset>
<legend><?php echo $form_title; ?></legend>
<!-- Form text -->
<!-- New password input with eye toggle -->
<!-- Confirm password input with eye toggle -->
<!-- Password requirements list -->
<!-- Hidden fields (nonce, action, key, uid) -->
<!-- Submit button -->
</fieldset>
</form>
</div>
<!-- JavaScript for validation and eye toggle -->
Available variables
The template receives these variables from the plugin:
$form_title
Type: String
Source: General settings (somfrp_form_title)
Default: "Reset Password"
Purpose: Heading displayed at the top of the form
Usage: <legend><?php echo $form_title; ?></legend>
$reset_text_output
Type: String (HTML allowed)
Source: General settings (somfrp_reset_password_message)
Default: "Enter your new password below."
Purpose: Instruction text explaining what users should do
Usage: <?php echo $reset_text_output; ?>
$button_text
Type: String
Source: General settings (somfrp_button_text)
Default: "Reset Password"
Purpose: Label for the submit button
Usage: <button type="submit"><?php echo $button_text; ?></button>
$errors
Type: Array or null
Source: Form validation errors
Purpose: Error messages to display if validation fails
Usage:
<?php if ( ! empty( $errors ) && is_array( $errors ) ) : ?>
<?php foreach ( $errors as $error ) : ?>
<p class="som-password-error-message">
<?php echo esc_html( $error ); ?>
</p>
<?php endforeach; ?>
<?php endif; ?>
$sec_options
Type: Array
Source: Security settings (somfrp_security_settings)
Purpose: Contains password requirement settings
Keys:
somfrp_min_length- Minimum password length (default: 8)somfrp_require_lowercase- Require lowercase letter (on/off)somfrp_require_uppercase- Require uppercase letter (on/off)somfrp_require_number- Require number (on/off)somfrp_require_special- Require special character (on/off)
Usage: Used to display password requirements list
$somfrp_enable_eye
Type: Boolean
Source: Design settings (somfrp_enable_eye_toggle)
Default: true
Purpose: Controls whether password visibility toggle buttons are displayed
Usage: Conditional display of eye toggle buttons
Form fields
New Password Input
Field name: som_new_user_pass
Field ID: som_new_user_pass
Type: Password input
Required: Yes
Autocomplete: new-password
Purpose: User enters their new password
HTML:
<input
type="password"
name="som_new_user_pass"
id="som_new_user_pass"
class="som-password-input"
required
autocomplete="new-password"
>
Confirm Password Input
Field name: som_new_user_pass_again
Field ID: som_new_user_pass_again
Type: Password input
Required: Yes
Autocomplete: new-password
Purpose: User confirms their new password
HTML:
<input
type="password"
name="som_new_user_pass_again"
id="som_new_user_pass_again"
class="som-password-input"
required
autocomplete="new-password"
>
Hidden Fields
Nonce field:
<?php wp_nonce_field( 'somfrp_reset_pass', 'somfrp_nonce' ); ?>
Action identifier:
<input type="hidden" name="somfrp_action" value="somfrp_reset_pass">
Reset key (from URL):
<input type="hidden" name="somfrp_key" value="<?php echo esc_attr( $_GET['key'] ); ?>">
User ID (from URL):
<input type="hidden" name="somfrp_uid" value="<?php echo esc_attr( $_GET['uid'] ); ?>">
Do not remove or modify hidden fields. They are required for form processing, security validation, and user identification.
Password requirements display
The template displays a dynamic list of password requirements based on security settings:
<ul class="password-requirements">
<?php if ( isset( $sec_options['somfrp_min_length'] ) ) : ?>
<li class="requirement" data-requirement="length">
At least <?php echo esc_html( $sec_options['somfrp_min_length'] ); ?> characters
</li>
<?php endif; ?>
<?php if ( isset( $sec_options['somfrp_require_lowercase'] ) && $sec_options['somfrp_require_lowercase'] === 'on' ) : ?>
<li class="requirement" data-requirement="lowercase">
One lowercase letter
</li>
<?php endif; ?>
<?php if ( isset( $sec_options['somfrp_require_uppercase'] ) && $sec_options['somfrp_require_uppercase'] === 'on' ) : ?>
<li class="requirement" data-requirement="uppercase">
One uppercase letter
</li>
<?php endif; ?>
<?php if ( isset( $sec_options['somfrp_require_number'] ) && $sec_options['somfrp_require_number'] === 'on' ) : ?>
<li class="requirement" data-requirement="number">
One number
</li>
<?php endif; ?>
<?php if ( isset( $sec_options['somfrp_require_special'] ) && $sec_options['somfrp_require_special'] === 'on' ) : ?>
<li class="requirement" data-requirement="special">
One special character
</li>
<?php endif; ?>
<li class="requirement" data-requirement="match">
Passwords match
</li>
</ul>
Each requirement has a data-requirement attribute used by JavaScript for validation feedback.
Real-time validation
The template includes JavaScript that validates passwords as users type:
document.addEventListener('DOMContentLoaded', function() {
const newPass = document.getElementById('som_new_user_pass');
const confirmPass = document.getElementById('som_new_user_pass_again');
function validatePassword() {
const password = newPass.value;
const confirmPassword = confirmPass.value;
// Check length
const lengthReq = document.querySelector('[data-requirement="length"]');
if (lengthReq) {
const minLength = parseInt(lengthReq.textContent.match(/\d+/)[0]);
if (password.length >= minLength) {
lengthReq.classList.add('valid');
lengthReq.classList.remove('invalid');
} else {
lengthReq.classList.add('invalid');
lengthReq.classList.remove('valid');
}
}
// Check lowercase
const lowercaseReq = document.querySelector('[data-requirement="lowercase"]');
if (lowercaseReq) {
if (/[a-z]/.test(password)) {
lowercaseReq.classList.add('valid');
lowercaseReq.classList.remove('invalid');
} else {
lowercaseReq.classList.add('invalid');
lowercaseReq.classList.remove('valid');
}
}
// Similar checks for uppercase, number, special character
// ...
// Check passwords match
const matchReq = document.querySelector('[data-requirement="match"]');
if (matchReq) {
if (password && confirmPassword && password === confirmPassword) {
matchReq.classList.add('valid');
matchReq.classList.remove('invalid');
} else if (confirmPassword) {
matchReq.classList.add('invalid');
matchReq.classList.remove('valid');
}
}
}
newPass.addEventListener('input', validatePassword);
confirmPass.addEventListener('input', validatePassword);
});
Password visibility toggle
If enabled in design settings, the template includes eye toggle buttons:
<?php if ( $somfrp_enable_eye ) : ?>
<button type="button" class="somfrp-eye-toggle" data-target="som_new_user_pass">
<span class="somfrp-eye">👁</span>
<span class="somfrp-eye-off" style="display:none;">👁🗨</span>
</button>
<?php endif; ?>
JavaScript handles the toggle functionality:
document.querySelectorAll('.somfrp-eye-toggle').forEach(function(button) {
button.addEventListener('click', function() {
const targetId = this.getAttribute('data-target');
const input = document.getElementById(targetId);
const eyeOn = this.querySelector('.somfrp-eye');
const eyeOff = this.querySelector('.somfrp-eye-off');
if (input.type === 'password') {
input.type = 'text';
eyeOn.style.display = 'none';
eyeOff.style.display = 'inline';
} else {
input.type = 'password';
eyeOn.style.display = 'inline';
eyeOff.style.display = 'none';
}
});
});
CSS classes and IDs
Main wrapper
ID: #password-lost-form-wrap
Purpose: Container for entire form and messages
Form
ID: #resetpasswordform
Purpose: Main form element
Password inputs
Class: .som-password-input
Purpose: Styling for password input fields
Requirements list
Class: .password-requirements
Purpose: Container for requirements list
Item class: .requirement
Valid state: .requirement.valid
Invalid state: .requirement.invalid
Eye toggle
Button class: .somfrp-eye-toggle
Eye icon: .somfrp-eye
Eye-off icon: .somfrp-eye-off
Messages
Error message: .som-password-error-message
Form processing flow
- User clicks email link: URL contains reset key and user ID
- Plugin validates key: Checks key is valid and not expired
- Template loads: Displays password entry form
- User enters passwords: Types in both fields
- JavaScript validates: Real-time feedback on requirements
- User submits form: Clicks submit button
- Plugin validates server-side:
- Verifies nonce
- Validates reset key again
- Checks password meets requirements
- Verifies passwords match
- On success:
- Updates user password using
reset_password() - Redirects to completion page with
som_password_reset=true
- Updates user password using
- On error:
- Reloads form with
$errorsarray populated - Displays error messages
- Reloads form with
Customization examples
Change requirements display
<div class="password-strength-meter">
<ul class="requirements-list">
<!-- Custom requirement display -->
</ul>
</div>
Add password strength indicator
function calculateStrength(password) {
let strength = 0;
if (password.length >= 8) strength++;
if (password.length >= 12) strength++;
if (/[a-z]/.test(password)) strength++;
if (/[A-Z]/.test(password)) strength++;
if (/[0-9]/.test(password)) strength++;
if (/[^a-zA-Z0-9]/.test(password)) strength++;
return strength;
}
// Display strength meter
const strength = calculateStrength(password);
strengthMeter.style.width = (strength / 6 * 100) + '%';
Customize eye toggle icons
Replace emoji icons with Font Awesome or custom SVG:
<button type="button" class="somfrp-eye-toggle">
<i class="fa fa-eye somfrp-eye"></i>
<i class="fa fa-eye-slash somfrp-eye-off" style="display:none;"></i>
</button>
Add help tooltips
<div class="password-field-wrapper">
<input type="password" name="som_new_user_pass" id="som_new_user_pass">
<span class="help-tooltip" title="Choose a strong, unique password">
<i class="fa fa-question-circle"></i>
</span>
</div>
Common issues
Validation doesn't work
Problem: Requirements list doesn't update as user types.
Causes:
- JavaScript error in console
- Changed input IDs or requirement data attributes
- JavaScript not loaded
Solution: Check browser console for errors. Verify input IDs match JavaScript selectors. Ensure JavaScript is at bottom of template.
Eye toggle doesn't work
Problem: Clicking eye icon doesn't show/hide password.
Causes:
- JavaScript error
- Changed button class or data-target attribute
- CSS hiding the button
Solution: Check console for errors. Verify button has somfrp-eye-toggle class and correct data-target. Check CSS isn't hiding button.
Form submits with invalid password
Problem: Form submits even when requirements aren't met.
Causes:
- Client-side validation is only visual feedback
- Server-side validation is the actual enforcement
- JavaScript disabled
Solution: This is expected behavior. Server-side validation will catch invalid passwords. JavaScript validation is for user experience only.
Reset key expired
Problem: Form displays "Invalid or expired reset key" error.
Causes:
- User waited too long to click email link
- Reset key already used
- Key parameter corrupted in URL
Solution: User must request a new password reset. Keys expire after 24 hours by default (WordPress core behavior).
Accessibility considerations
Labels
Always include labels for password fields:
<label for="som_new_user_pass">
<?php _e( 'New Password', 'frontend-reset-password' ); ?>
</label>
ARIA attributes
Add ARIA attributes for screen readers:
<input
type="password"
id="som_new_user_pass"
aria-label="<?php esc_attr_e( 'New Password', 'frontend-reset-password' ); ?>"
aria-describedby="password-requirements"
aria-required="true"
>
<ul id="password-requirements" class="password-requirements">
<!-- Requirements list -->
</ul>
Live regions for validation
Use ARIA live regions for validation feedback:
<div role="status" aria-live="polite" aria-atomic="true">
<span class="sr-only" id="validation-status"></span>
</div>
<script>
// Update validation status for screen readers
function updateValidationStatus() {
const validCount = document.querySelectorAll('.requirement.valid').length;
const totalCount = document.querySelectorAll('.requirement').length;
document.getElementById('validation-status').textContent =
validCount + ' of ' + totalCount + ' requirements met';
}
</script>
Keyboard navigation
Ensure eye toggle buttons are keyboard accessible:
<button
type="button"
class="somfrp-eye-toggle"
aria-label="<?php esc_attr_e( 'Toggle password visibility', 'frontend-reset-password' ); ?>"
tabindex="0"
>
Security best practices
Always escape output
// Good
<?php echo esc_html( $sec_options['somfrp_min_length'] ); ?>
<?php echo esc_attr( $_GET['key'] ); ?>
// Bad
<?php echo $sec_options['somfrp_min_length']; ?>
<?php echo $_GET['key']; ?>
Preserve nonce and key validation
Never remove or modify security fields:
<?php wp_nonce_field( 'somfrp_reset_pass', 'somfrp_nonce' ); ?>
<input type="hidden" name="somfrp_key" value="<?php echo esc_attr( $_GET['key'] ); ?>">
<input type="hidden" name="somfrp_uid" value="<?php echo esc_attr( $_GET['uid'] ); ?>">
Use autocomplete attributes
Help password managers:
<input autocomplete="new-password">
Don't weaken validation
Don't modify JavaScript to allow weak passwords. Server-side validation will reject them anyway.
Testing checklist
After customizing this template:
- Form displays correctly on desktop
- Form displays correctly on mobile
- Password requirements list displays correctly
- Requirements update in real-time as user types
- Eye toggle shows/hides password (if enabled)
- Both password fields work correctly
- Form submits with valid password
- Form rejects invalid password with error message
- Form rejects mismatched passwords
- Form rejects expired reset keys
- Form works with JavaScript disabled (server-side validation)
- Screen readers can navigate the form
- Keyboard navigation works (Tab, Enter, Space for toggle)
What's next
- Completion page - Success confirmation page
- Security and validation - Understand password validation
- Template overrides guide - Create custom templates