We had to create a part 2 to this tutorial “How to create a Forgot/Reset Password form with Gravity Forms”. Please read the first article in order to understand how this process works from start-to-finish.
It is a frequent issue among website users to forget their passwords. As a website owner, it is crucial to incorporate a functionality for password recovery/reset to ensure that users can regain entry to their accounts. Gravity Forms, a well-known WordPress plugin, offers the capability to create personalized forms, including a form specifically designed for Forgot/Reset Password purposes. Utilizing this approach enables users to maintain their frontend forms while aligning them with their unique branding.
In this article, we will guide you through the process of creating the final part of the Forgot/Reset Password form with Gravity Forms by setting up the form to change the password, creating a new page so your end-users can use the functionality, and last-but-not-least, the under-the-hood code to enable all of the functionality for the user resetting their password.
Step 1: read “How to create a Forgot/Reset Password form with Gravity Forms”
The first step is to read part 1 How to create a Forgot/Reset Password form with Gravity Forms.
Step 2: Create the Reset Password form
To make it easier for you, you can download the JSON form and then import it into Gravity Forms. Take note of the new Form ID as we’ll need this later. For your reference, the JSON code is below:
{"0":{"fields":[{"type":"password","id":1,"formId":15,"label":"Password","adminLabel":"","isRequired":true,"size":"large","errorMessage":"","visibility":"visible","inputs":[{"id":"1","label":"Enter Password","name":""},{"id":"1.2","label":"Confirm Password","name":""}],"displayOnly":true,"description":"Hint: The password should be at least twelve characters long. To make it stronger, use upper and lower case letters, numbers, and symbols like ! \" ? $ % ^ & ).","allowsPrepopulate":false,"inputMask":false,"inputMaskValue":"","inputMaskIsCustom":false,"maxLength":"","inputType":"","labelPlacement":"","descriptionPlacement":"above","subLabelPlacement":"","placeholder":"","cssClass":"","inputName":"","noDuplicates":false,"defaultValue":"","enableAutocomplete":false,"autocompleteAttribute":"","choices":"","conditionalLogic":"","productField":"","layoutGridColumnSpan":"","passwordStrengthEnabled":true,"passwordVisibilityEnabled":true,"enableEnhancedUI":0,"layoutGroupId":"9f99f61f","multipleFiles":false,"maxFiles":"","calculationFormula":"","calculationRounding":"","enableCalculation":"","disableQuantity":false,"displayAllCategories":false,"useRichTextEditor":false,"fields":"","checkboxLabel":""}],"button":{"type":"text","text":"","imageUrl":"","width":"auto","location":"bottom","layoutGridColumnSpan":12},"title":"Forgot Password - Reset","description":"","version":"2.7.8","id":15,"markupVersion":2,"nextFieldId":2,"useCurrentUserAsAuthor":true,"postContentTemplateEnabled":false,"postTitleTemplateEnabled":false,"postTitleTemplate":"","postContentTemplate":"","lastPageButton":null,"pagination":null,"firstPageCssClass":null,"labelPlacement":"top_label","descriptionPlacement":"below","subLabelPlacement":"below","requiredIndicator":"text","customRequiredIndicator":"(Required)","cssClass":"","saveButtonText":"Save & Continue","limitEntries":false,"limitEntriesCount":"","limitEntriesPeriod":"","limitEntriesMessage":"","scheduleForm":false,"scheduleStart":"","scheduleEnd":"","schedulePendingMessage":"","scheduleMessage":"","requireLogin":false,"requireLoginMessage":"","enableHoneypot":true,"honeypotAction":"spam","enableAnimation":true,"validationSummary":false,"deprecated":"","saveEnabled":"","save":{"enabled":false,"button":{"type":"link","text":"Save & Continue"}},"scheduleStartHour":"","scheduleStartMinute":"","scheduleStartAmpm":"","scheduleEndHour":"","scheduleEndMinute":"","scheduleEndAmpm":"","notifications":[],"confirmations":[{"id":"64824fa5e79c9","name":"Default Confirmation","isDefault":true,"type":"message","message":"Success! Your password has been reset. You may proceed to login.","url":"","pageId":"","queryString":"","event":"","disableAutoformat":false,"page":"","conditionalLogic":[]}]},"version":"2.7.8"}
Step 3: Add the Reset Password functionality to functions.php
There are three parts to this code.
- First we need to add a new filter for Gravity Forms to pre-render the form. This will do the initial checking to make sure the reset key is valid.
- Then we need to add another filter for Gravity Forms to validate the input field before submission. Again, this will check the reset key is valid. We do this because if the user is sitting idle on the page for 5 hours and then finally submits the form, without checking it would allow them to change the password. This step is vital to protect the account.
- And finally, we need to actually change the password after the form has been submitted.
You can copy/paste the code below into your functions.php or a custom plugin file.
In the code example below, your new form ID is 100 and the password field ID is 1. If you import the form using the JSON file above, you’ll only need to change the Form ID.
// Forgot Password - The password reset form, check for a valid key!
add_filter('gform_pre_render_100', function($form) {
$key = sanitize_text_field($_GET['key']);
$login = sanitize_text_field($_GET['login']);
$validation = check_password_reset_key($key, $login);
$form['limitEntriesMessage'] = 'The link you followed either expired or is invalid.';
if(is_wp_error($validation)) {
$form['limitEntries'] = true;
}
return $form;
});
// Let's do some validation of field 1 (the password field) prior to resetting the password
add_filter('gform_field_validation_100_1', function($result, $value, $form, $field) {
$key = sanitize_text_field($_GET['key']);
$login = sanitize_text_field($_GET['login']);
$validation = check_password_reset_key($key, $login);
if(is_wp_error($validation)) {
$result['is_valid'] = false;
$result['message'] = 'The link you followed either expired or is invalid. Please refresh.';
}
return $result;
}, 10, 5);
// Validation success, let's change the password
add_action('gform_after_submission_100', function($entry, $form) {
$login = sanitize_text_field($_GET['login']);
$user = get_user_by('login', $login);
if($user) {
wp_set_password(rgar($entry, '1'), $user->ID);
}
}, 10, 2);
Step 4: Create a new page and embed the new Gravity Form to this page
In order for users to create a new password, they’ll need public access to the new form you’ve imported (or setup) in this article. To do so, simply create a new page and then embed the form on the page. You’ll need to note down the page ID as we will use it in the next step for a flawless integration.
Please note: if you have read the previous article in Step 1 and are continuing this tutorial, at the very end you’ll end up with two forms and two pages that you have to create. The first form is to handle the user’s email address so they can receive a reset password email and the second form (in this article) is so the user can actually create new password and update their account.
Got Gravity Forms? You'll need Cloudflare Turnstile.
Protect your forms from those pesky spammers with our Cloudflare Turnstile plugin for Gravity Forms. A super lightweight plugin.
Step 5: Change the initial redirect in Part 1
In part one, you added a filter to your functions.php
file to the first form after submission. That filter was gform_notification_99
and one line contained part of the code site_url('wp-login.php')
. You’ll need to change this part of the code to redirect to your new password reset form (which is the page you created in Step 4) by replacing it with get_the_permalink(PAGE_ID)
(PAGE_ID = the page ID you saved in Step 4); Once you do that, the add_filter code may look something like this:
// After forgot password submission
add_filter('gform_notification_99', function($notification, $form, $entry) {
// Send the forgot password email
$user = get_user_by('email', rgar($entry, '1'));
if($user->ID)
{
$displayName = $user->display_name;
$reset_link = add_query_arg([
'key' => get_password_reset_key($user),
'login' => urlencode($user->user_login)
], get_the_permalink(123456789));
$notification['message'] = str_replace('{full_name}', $displayName, $notification['message']);
$notification['message'] = str_replace('{password_link}', $reset_link, $notification['message']);
}
return $notification;
}, 10, 3);
Once you’ve changed this filter to redirect to your new password reset form page, the user who receives an email notification about the password reset will be sent to the new form you’ve created and then may proceed to change their password.
Step 5: Test!
The next step is to test the form! This is the most important step. You should get all the way to the confirmation message and the password of the user account will have been reset. Once you do, you know it’s working 100%!
I had some issues initially but I realized there were some missing steps. I didn’t have 2 separate pages (one page for Forgot password and one page for Reset password). I think it would’ve been helpful to mention creating a page in the first tutorial & in the second tutorial specify a 2nd page would need to be created separately. I also hid the default “Lost your password?” link with CSS on my login page and added a new link to my new Forgot password page, it would’ve been helpful to have mentioned that too in the 2nd tutorial.
Either way it ended up working out for me so thanks!!
Thank you so much for your comment. I really appreciate you taking the time to provide feedback. I’ve gone ahead and modified the first and second article to include your idea about the separate pages. Hopefully it’s clear now for others as well!
I have not officially added it to this tutorial (and I might later) however, a previous comment wanted to change the lost password URL. By default WordPress has a filter for that so you don’t need to use CSS to hide it! Here is that comment: https://ss88.us/blog/part-2-how-to-create-a-reset-password-form-with-gravity-forms?swcfpc=1#div-comment-34
WordPress and Gravity Forms are so flexible that sometimes modifying default behaviours can cause panic to users who are expecting WordPress branded pages! Happy coding!!
The only thing I’ll add that was helpful for my scenario and may be helpful for others:
I’m adding this to a multisite theme, so the form IDs and Reset Password page ID will be different from site to site. (This could also apply if using this in a plugin or GF add-on.)
My solution:
I used Advanced Custom Fields (ACF) to create fields for the Forgot Password form ID, Reset Password form ID and the Reset Password page ID in the Options menu. In the code, I created variables for their values and used them where needed, like so:
…
Alternative solution (if someone doesn’t have access to ACF’s Pro features, like the Options menu):
GF’s API has the method you can use to return an array of form objects to pinpoint your form IDs in other ways: https://docs.gravityforms.com/getting-forms-with-the-gfapi/#get-forms – will take a bit of knowledge of PHP, but it’s doable! 🙂
Thanks in advance for your assistance resolving this.
When you get this error “The link you followed either expired or is invalid.”, it means that link you clicked in the email does not contain the query parameter key or login. Can you check those are present in the reset URL you received via email? If they are present, then the function check_password_reset_key is returning an error and that usually means the key has expired or is invalid.
If the “Forgot password” link is automatically generated by a third party, such as gravity forms, you’ll need extra code to change this URL site-wide. The code I’m about to show below will also change the “Lost your password?” on the default WP Login page too. The following should do the trick:
In the snippet, change 123456789 to the Page ID of the forgot password page you created in Part 1. I’m also just realizing that in Step 1, I never instructed people to create a page and embed the form on it!
Please advise what I should do.
That’s right.
Part 1: https://ss88.us/blog/how-to-create-a-forgot-reset-password-form-with-gravity-forms
Part 1 covers the very first form that users type their email address in. This form is what generates a reset key for their account and then sends them an email with a reset link. This by default links to wp-login.php because for Part 1, it has to. You can only change this once you have integrated Part 2.
Part 2: https://ss88.us/blog/part-2-how-to-create-a-reset-password-form-with-gravity-forms
Part 2 lets you replace wp-login.php (in Part 1) with your own custom reset page. There is another form that has to be created for Part 2 because this handles the new password the user types in and updates their WordPress account.
Once you have created the form and another page in Part 2, that page will have an ID — let’s say it’s 787. In order to make Part 1’s reset link direct users to the form which asks them for a password, you have to change site_url(‘wp-login.php’) to get_the_permalink(787) in Part 1.
– Part 1 will work by itself, allowing users to reset their password.
– Part 2 make the entire process completely branded to your brand, skipping wp-login.php
The user flow with both Part 1 and Part 2 integrated is completely custom branded and works like this:
1) User types email address to generate a reset key (part 1, fully branded).
2) User receives email with a reset link (part 1, fully branded).
3) User clicks on link and is directed to a new page asking for a new password (part 2, fully branded).
4) User submits new password form and new password is updated on their WordPress account (part 2, fully branded).
Without Part 2, the user flow is as follows:
1) User types email address to generate a reset key (part 1, fully branded).
2) User receives email with a reset link (part 1, not fully branded).
3) User clicks on link and is directed to a WordPress reset key page.
Let me know if that helps a little more!
Sully
The redirect code which I have added to my functions.php file after following both articles and your comments below:
The emails sends when using the first form but links to the default WordPress password reset page.
Thank you in advance for continuing to help me get to the bottom of where I am going wrong with your tutorials.
Thank you so much for the wonderful tutorial. It is a bit confusing but after some debugging it definitely worked like wonders for us!
I’m so glad you finally got it working!
Please let me know how I can improve on the confusing part of the articles and I’ll certainly attempt to re-word things and add in more descriptions so others can easily integrate this without issue.
Can you please copy/paste your code into the comments for the gform_notification_XXX filter (after forgot password submission)? It sounds like within this code, it still has snippet in there.
If you’ve created your own page to handle the password reset (the second GF form), you’ll need to change it to the following and change to the ID of the page. That will change the email link received via email.
Let me know how you get on!
the code you provided in the comments above last week and the code in the Part 1 article. Are you saying I need to also have all the code in this article for the wp-login.php to correctly forward from the GF link?
Please let me know.
Catch you tomorrow!
Can you share the forgot password URL where the first forgot password form is embed on? I’ll be able to take a look.
In total, there should be two forms:
1) For the initial form, which asks for their email address.
2) The second form, which asks for their password.
Did you read and follow Part 1?
I have not tested the solution you provided yesterday yet. I will be in the next few hours. I would prefer not to share the links to either of the forms here if that solution does not solve my problem… are you okay with moving the conversation to email though?
I’m having an odd problem with the password reset URL, When I visit the password reset URL, the semicolon after https appears to be missing, so the URL fails to load. Any ideas on what might be the problem?
Thanks for your comment!
I’ve checked the code and everything looks OK to me.
Do you want to change the following part of the code and forcefully enter the URL of the password reset page? i.e:
to
In doing so, if the colon is still removed, it might be some other function/plugin/theme in WordPress changing the URL.
Your code would end up looking something like;
Thank you so much for your reply. I selectively turned off and on all plugins except for Gravity Forms but the problem remained. It’s not your code of course, but the URL in the email gets encoded and starts with http://url3268.domain.com (not https by the way) and once clicked it’s interpreted as https//domain.com/ls/click?upn=xxxxxx
So the problem appears to be in the encoding of the URL but I’m not sure what does this 🙂
Just to note I’m using Divi as my theme with my own child theme (and I removed all code from my functions.php except for the bits you’ve provided).
Do you have any third party email / SMTP service that could be changing the URL? If you are connecting for example via Amazon SES, sometimes that has a link tracker which modifies the URLs (but I didn’t think it would break them!).
It could be an idea to test this on a vanilla installation of WordPress (without divi) just to double check.