0

I've created a custom reset password page on my WooCommerce site. The reset page was previously /my-account/lost-password/, but my custom page is /reset-password/.

In my theme, I've copied over the WooCommerce customer-reset-password.php so I could customise the URL in the email to point to my new page. The link in the email looks like this:

<a class="link" href="<?php echo esc_url( add_query_arg( array( 'key' => $reset_key, 'id' => $user_id ), home_url()." /reset-password/ " ) ); ?>">
  <?php // phpcs:ignore ?>
  <?php esc_html_e( 'Click here to reset your password', 'woocommerce' ); ?>
</a>

Now, when I go to /lost-password/, and enter my email address. I successfully receive a reset email with the link pointing to the correct page: /reset-password/?key=p5iemdCVtG4qkh5WQH8B&id=31

Upon clicking on the link in the email, I can then enter my new password and re-enter new password (I'm using the WooCommerce reset_password_form shortcode to show the form).

However, when filling out these fields, and clicking submit, I get the following message: This key is invalid or has already been used. Please reset your password again if needed.

I've had a look into existing threads, namely:

Unsure how to proceed?

How I've created / added the reset password form:

  1. Registered the WooCommerce reset password shortcode in functions.php

function wc_custom_reset_password_form( $atts ) {
  return wc_get_template( 'myaccount/form-reset-password.php', array( 'form' => 'reset_password' ) );
}
add_shortcode( 'reset_password_form', 'wc_custom_reset_password_form' );
  1. Added the shortcode to my template:

<?php echo do_shortcode( '[reset_password_form]' ); ?>

What's been changed in customer-reset-password.php?

This is what the template has as the link by default:

<a class="link" href="<?php echo esc_url( add_query_arg( array( 'key' => $reset_key, 'id' => $user_id ), wc_get_endpoint_url( 'lost-password', '', wc_get_page_permalink( 'myaccount' ) ) ) ); ?>"><?php // phpcs:ignore ?>
  <?php esc_html_e( 'Click here to reset your password', 'woocommerce' ); ?>
</a>

This is what I changed it to:

<a class="link" href="<?php echo esc_url( add_query_arg( array( 'key' => $reset_key, 'id' => $user_id ), home_url()." /reset-password/ " ) ); ?>">
  <?php // phpcs:ignore ?>
  <?php esc_html_e( 'Click here to reset your password', 'woocommerce' ); ?>
</a>
Freddy
  • 683
  • 4
  • 35
  • 114
  • Question are you logged in as the user that requested the reset password ? – Crisoforo Gaspar Oct 16 '21 at 23:22
  • @CrisoforoGaspar - I've tried both, being logged in as the user and as a non logged in user and receive the same message. The user doesn't need to be logged in any, the only way to reach the page is if a users requested to reset their password. To clarify, the flow is `/forgot-password > user receives email which has link to /reset-password page`. I would assume the `key` that is appended to the query string (part of `woocommerce` will then update the correct users password. The `id` is also appended to the query string,it has all the details it needs already to determine which user to update. – Freddy Oct 16 '21 at 23:35
  • Okay I see let me see if I can debug this error I was looking at the code and the under lay code uses the ID so that might be the problem as is expecting a user but as you pointed out technically the user is not logged in when requesting a new password. – Crisoforo Gaspar Oct 16 '21 at 23:43
  • Are you trying to do that on live server or localhost? And also make sure that do you use any caching plugin for your website? – Sayedur Rahman Oct 17 '21 at 10:25
  • @SayedurRahman - It's on a live server (hosted by `WPEngine`). I don't have any caching plugins and I've also tried this by clearing both server and browser cache. – Freddy Oct 17 '21 at 11:58
  • 1
    This is a common issue with WP Engine and you need to exclude the pages form WP Engine cache. Please contact their support and they will resolve this. – Outsource WordPress Oct 17 '21 at 17:41
  • Hi @OutsourceWordPress - I already have any URL that contains `/my-account`, `/forgot-password` and `/reset-password` removed from caching server side (`WPEngine` did this). The issue still persists. – Freddy Oct 18 '21 at 18:59
  • Before clicking the email link, can you check in your database user's table if the key seems correct? So in the end you only edited the email, and created a new template for the form? Note that you can edit woocommerce endpoints URL's in settings, and properly override all templates. Also take a look at this: https://stackoverflow.com/questions/29568813/woocommerce-lost-password-form-on-another-page - I had some issue like this once, mixing WP and Woocommerce resets, having additional redirections... – Mtxz Oct 18 '21 at 23:21
  • @Mtxz - Would you know where I'm looking in the database? would it be the `user_activation_key` in `wp_users`? And yes, I've only edited the URL in the email and created a new `template` where I'm just using the `WooCommerce` reset form (I've registered the shortcode). I've updated my question to showcase all of this for better visuals – Freddy Oct 18 '21 at 23:48
  • Yes, check-in `user_activation_key` of the wp_users table. Thanks for adding details, you already did it better than I thought :) So compare Db keys and email keys before clicking the link. And report here please ! – Mtxz Oct 18 '21 at 23:59
  • Hi @Mtxz - The accepted solution seemed to do the trick for me! But, wanted to thank you for giving me insight on the `user_activation_key`. Did some reading (namely this thread: https://stackoverflow.com/questions/39263010/what-is-user-activation-key-in-wordpress) and gained a better understand on how these things work. So thanks :) – Freddy Oct 20 '21 at 17:38

2 Answers2

2

The reason it's not working and gives you an error because you were supposed to be pass key and user login into form-reset-password.php which you didn't when you call template file into your shortcode.

You have to just only add 'key' => $rp_key, 'login' => $rp_login.

Your current code is :

function wc_custom_reset_password_form( $atts ) {
  return wc_get_template( 'myaccount/form-reset-password.php', array( 'form' => 'reset_password' ) );
}
add_shortcode( 'reset_password_form', 'wc_custom_reset_password_form' );

Complete code :

function wc_custom_reset_password_form( $atts ) {
    $rp_key     = wp_unslash( $_GET['key'] );
    $user_id    = absint( $_GET['id'] );
    $userdata   = get_userdata( absint( $user_id ) );
    $rp_login   = $userdata ? $userdata->user_login : '';
    $user       = WC_Shortcode_My_Account::check_password_reset_key( $rp_key, $rp_login );  
    return wc_get_template( 'myaccount/form-reset-password.php', array( 'form' => 'reset_password', 'key' => $rp_key, 'login' => $rp_login ) );
}
add_shortcode( 'reset_password_form', 'wc_custom_reset_password_form' );

You can add your validation for key and user id ( from query parameter ) into this code.

Gautam Golakiya
  • 453
  • 2
  • 12
0

You can try the following:

Your Custom Link:

<a class="link" href="<?php echo esc_url(add_query_arg(array('action' => 'rp','id' => $user_id), site_url('/')) ); ?>">

Now you can add anywhere on your site.

Add below code on functions.php

if(isset($_REQUEST['action']) && $_REQUEST['action'] == 'rp') {
    $user_id   = isset($_REQUEST['id']) ? $_REQUEST['id'] : 0;
    $action    = $_REQUEST['action'];

    if($user_id ){
       $user_data = get_userdata( $user_id );

       $user_email = $user_data->user_email;
       $reset_key  = get_password_reset_key( $user_data );

       wp_redirect( site_url( 'wp-login.php' ) . '?action='. $action .'&key=' . $reset_key . '&login=' . $user_email );
      exit;
    }
 }

After clicking on the link, the output is:

enter image description here

Chris van Chip
  • 504
  • 4
  • 20
Rajeev Singh
  • 1,724
  • 1
  • 6
  • 23