Today I will describe how to make your theme even more user friendly or to be more specific how to get rid of the password recovery pages. The default Prestashop behavior is as follows:
Step 1: user clicks on the “Forgot your password” link;
Step 2: he is redirected to another page where he enters an email address and clicks ‘Retrieve Password’
Step 3: after the page is reloaded he either sees an error message or the message that a recovery e-mail has been successfully sent to his e-mail address.
So, the default functionality takes minimum 3 steps to fulfill and involves reloading pages at least 3 times. If we want to facilitate this process we need to reduce and simplify this procedure. A standard solution here would be to use Ajаx in order to reduce the time that a client waits for his new password – we are saving time by excluding page reloads.
So, what is our plan? We will make a pop-up window with a password recovery form and will forward requests to the controller “password” using Ajаx.
Let’s create a js-code to initiate a pop-up window. We will use the fаnсybоx library, which is included in Prestashop. If your current controller authentication does not contain this library, you can include it by using the following code:
1 2 |
$this->context->controller->addCSS(_PS_CSS_DIR_ . 'jquery.fancybox-1.3.4.css', 'screen'); $this->context->controller->addJqueryPlugin(array('fancybox')); |
Edit the authentication.tpl file in accordance with the example below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<script> $(document).ready(function(){ $('.popup-password-link').fancybox(); }); </script> <p class="lost_password"><a href="#popup-password-reset" class="popup-password-link">Forgot your password?</a></p> <div style="display:none"> <div id="popup-password-reset"> {capture name=path}{l s='Forgot your password?'}{/capture} <h3>{l s='Forgot your password?'}</h3> <p>{l s='Please enter the e-mail address used to register. We will send your new password to that address.'}</p> {if isset($confirmation) && $confirmation == 1} <p class="success">{l s='Your password has been successfully reset and a confirmation has been sent to your e-mail address:'} {$smarty.post.email|escape:'htmlall':'UTF-8'|stripslashes}</p> {elseif isset($confirmation) && $confirmation == 2} <p class="success">{l s='A confirmation e-mail has been sent to your address:'} {$smarty.post.email|escape:'htmlall':'UTF-8'|stripslashes}</p> {include file="$tpl_dir./errors.tpl"} {else} <form action="{$link->getPageLink('password')}" method="post" class="std" id="form_forgotpassword"> <fieldset> <div class="error" id="popup_error" style="display: none;"></div> <div class="success" id="popup_success" style="display: none;">{l s='Your password has been successfully reset and a confirmation has been sent to your e-mail address'}</div> <p class="text"> <label for="email">{l s='Type your email address:'}</label> <input required placeholder="E-mail" type="text" id="popup_email" name="email" value="{if isset($smarty.post.email)}{$smarty.post.email|escape:'htmlall':'UTF-8'|stripslashes}{/if}" /> </p> <p class="submit"> <input type="submit" class="button" id="retrieve_password" value="{l s='Retrieve Password'}" /> </p> </fieldset> </form> {/if} </div> <!--End PopUp Reset--> |
Now, when you click the link “Forgot your password” you will see this window:
But, in order to make all this beauty work, you need to teach the controller Password to work with аjаx requests. To do this let’s reload the PаsswоrdCоntrоller:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
<?php class PasswordController extends PasswordControllerCore { public function postProcess() { if (Tools::isSubmit('email')) { if (!($email = Tools::getValue('email')) || !Validate::isEmail($email)) $this->errors[] = Tools::displayError('Invalid e-mail address'); else { $customer = new Customer(); $customer->getByemail($email); if (!Validate::isLoadedObject($customer)) $this->errors[] = Tools::displayError('There is no account registered to this e-mail address.'); elseif (!$customer->active) $this->errors[] = Tools::displayError('You cannot regenerate the password for this account.'); elseif ((strtotime($customer->last_passwd_gen.'+'.(int)($min_time = Configuration::get('PS_PASSWD_TIME_FRONT')).' minutes') - time()) > 0) $this->errors[] = sprintf(Tools::displayError('You can regenerate your password only every %d minute(s)'), (int)$min_time); else { $mail_params = array( '{email}' => $customer->email, '{lastname}' => $customer->lastname, '{firstname}' => $customer->firstname, '{url}' => $this->context->link->getPageLink('password', true, null, 'token='.$customer->secure_key.'&id_customer='.(int)$customer->id) ); if (Mail::Send($this->context->language->id, 'password_query', Mail::l('Password query confirmation'), $mail_params, $customer->email, $customer->firstname.' '.$customer->lastname)) $this->context->smarty->assign(array('confirmation' => 2, 'email' => $customer->email)); else $this->errors[] = Tools::displayError('Error occurred while sending the e-mail.'); } } if (Tools::isSubmit('ajax')) { $return_array = array( 'hasError' => count($this->errors), 'errors' => $this->errors, 'confirmation' => empty($this->errors) ? 1 : 0, ); die (json_encode($return_array)); } } elseif (($token = Tools::getValue('token')) && ($id_customer = (int)Tools::getValue('id_customer'))) { $email = Db::getInstance()->getValue('SELECT `email` FROM '._DB_PREFIX_.'customer c WHERE c.`secure_key` = \''.pSQL($token).'\' AND c.id_customer = '.(int)$id_customer); if ($email) { $customer = new Customer(); $customer->getByemail($email); if (!Validate::isLoadedObject($customer)) $this->errors[] = Tools::displayError('Customer account not found'); elseif (!$customer->active) $this->errors[] = Tools::displayError('You cannot regenerate the password for this account.'); elseif ((strtotime($customer->last_passwd_gen.'+'.(int)Configuration::get('PS_PASSWD_TIME_FRONT').' minutes') - time()) > 0) Tools::redirect('index.php?controller=authentication&error_regen_pwd'); else { $customer->passwd = Tools::encrypt($password = Tools::passwdGen(MIN_PASSWD_LENGTH)); $customer->last_passwd_gen = date('Y-m-d H:i:s', time()); if ($customer->update()) { Hook::exec('actionPasswordRenew', array('customer' => $customer, 'password' => $password)); $mail_params = array( '{email}' => $customer->email, '{lastname}' => $customer->lastname, '{firstname}' => $customer->firstname, '{passwd}' => $password ); if (Mail::Send($this->context->language->id, 'password', Mail::l('Your new password'), $mail_params, $customer->email, $customer->firstname.' '.$customer->lastname)) $this->context->smarty->assign(array('confirmation' => 1, 'email' => $customer->email)); else $this->errors[] = Tools::displayError('Error occurred while sending the e-mail.'); } else $this->errors[] = Tools::displayError('An error occurred with your account and your new password cannot be sent to your e-mail. Please report your problem using the contact form.'); } } else $this->errors[] = Tools::displayError('We cannot regenerate your password with the data you submitted'); } elseif (Tools::getValue('token') || Tools::getValue('id_customer')) $this->errors[] = Tools::displayError('We cannot regenerate your password with the data you submitted'); } } |
As a result we get a fully-functional form with intuitive and quick way to reset password for your customers.
Michał Nowak,
You can contact our support team at [email protected] for the solution.
Dear Alex
Very nice post.
I am looking for similar code to make a login/registration popup.
Can You help me?
lordbdp,
There are a lot of reasons that can cause this. You can contact our support team at [email protected] and they will try to help you. But as I see for now you have made wrong rewrite:
instead of
I have put the 2 lines in overrides/controllers/front/PasswordController.php as :
”
class PasswordControllerCore extends FrontController
{
$this->context->controller->addCSS(_PS_CSS_DIR_ . ‘jquery.fancybox-1.3.4.css’, ‘screen’);
$this->context->controller->addJqueryPlugin(array(‘fancybox’));
public $php_self = ‘password’;
”
And modify the authentication.tpl as you said, but now I haven’t the fancy box and the link to recover the password is unactive.
I am on PS 1.5.6.2
Romain,
You can do it the same way as described in the article. You need to create a popup with the help of Fancybox. And display in it the template for editing addresses (most likely you mean address.tpl).
Hi,
Is there a way to adapt that to add/edit addresses ?
If so, can you explain me how ?
Thanks.
Best regards,
Romain
Jash,
Basically, the article is related to the version 1.5, however, it should be compatible with the version 1.6 too, although some differences may take place. If the validation is not working, you need to check first if ajax-request is being sent and whether there are any errors recorded in the console.
Hello,
Great tutorial, but validation in pop up is not working for me. I am using prestashop 1.6. Maybe you can attach password controller file with your modifications?
Marcel,
The whole PHP-code that needs to be changed is placed in the controller controllers/front/PasswordController.php. And the template changes supposed to be here: themes/your_theme/authentication.tpl
Dear Alex,
Looking to the http://blog.belvg.com/how-to-make-a-popup-window-for-password-recovery-in-prestashop.html at this moment and would like to implement this. Before doing so I think only parts in the authentication code needs to be changed / updated or added but am not sure where.
Can you please advise?
Thanks
Kind regards,
Marcel