9

I have a need to place a user's password reset form in areas outside the context of the user edit page.

This Change Password module looked promising; however, it is only available for drupal 6 and only a dev snapshot is available.

I could use hook_form_alter to hide the fields on the edit user form that are not related to the user's password, but I would prefer not to do that if at all possible.

I'm hopping this functionality exists somewhere already.

Thanks in advance.

2 Answers 2

27

I couldn't find anything out there already and it sounded like a handy thing to have, so here's a small module providing a block with a change password form:

File: change_password.info

name = Change Password
description = Provides a block containing a form for the current user to change their password.
core = 7.x

File: change_password.module

<?php

/**
 * Implements hook_block_info().
 */
function change_password_block_info() {
  return array(
    'change_password_form' => array(
      'info' => t('Change Password Form')
    )
  );
}

/**
 * Implements hook_block_view().
 */
function change_password_block_view($delta = '') {
  $block = array();
  // Only show the block for a logged-in user.
  if ($delta == 'change_password_form' && user_is_logged_in()) {
    $block['subject'] = t('Change Password');
    $block['content'] = drupal_get_form('change_password_form');
  }
  return $block;
}

/**
 * Password change form.
 */
function change_password_form($form, &$form_state) {
  // Sanity check
  if (user_is_anonymous()) {
    return $form; // Or drupal_access_denied()?
  }

  // Get the currently logged in user object.
  $form['#account'] = $GLOBALS['user'];

  // Textfield cor current password confirmation.
  $form['current_pass'] = array(
    '#type' => 'password',
    '#title' => t('Current password'),
    '#size' => 25,
    '#required' => TRUE
  );

  // Password confirm field.
  $form['account']['pass'] = array(
    '#type' => 'password_confirm',
    '#size' => 25,
    '#title' => t('New Password'),
    '#required' => TRUE
  );

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Submit')
  );

  return $form;
}

/**
 * Validate handler for change_password_form().
 */
function change_password_form_validate(&$form, &$form_state) {  
  // Make sure the password functions are present.
  require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');

  // Make sure the provided current password is valid for this account.
  if (!user_check_password($form_state['values']['current_pass'], $form['#account'])) {
    form_set_error('current_pass', t('The current password you provided is incorrect.'));
  }
}

 /**
 * Submit handler for change_password_form().
 */
function change_password_form_submit(&$form, &$form_state) {
  // Set up the edit array to pass to user_save()
  $edit = array('pass' => $form_state['values']['pass']);

  // Save the account with the new password.
  user_save($form['#account'], $edit);

  // Inform the user.
  drupal_set_message(t('Your password has been changed.'));
}

It's (lightly) tested and works, but you might want to give it a once-over for your own peace of mind.

Update I've chucked it up as a sandbox project in case anyone's interested.

7
  • Wow. That is awesome.
    – SMTF
    May 30, 2012 at 17:22
  • 3
    The Form Block module drupal.org/project/formblock already contains support for the password reset form. See drupal.org/node/524774
    – user842
    May 30, 2012 at 19:30
  • @nicoz That looks like a good Answer to the question. I think you could submit it as such rather then only commenting on an existing answer.
    – SMTF
    May 30, 2012 at 19:45
  • I thought I would let clive take the glory. He did all of the work to create a module to specifically answer the issue. Also, he is about to take over the top of the leader board here, so any point counts ;)
    – user842
    May 30, 2012 at 20:34
  • @nicoz I've specified Clive's as the correct answer. I don't think that means that I can't up-vote yours as well. Cheers.
    – SMTF
    May 30, 2012 at 22:12
7

Here's another approach.

In my example, I render the built-in user_profile_form(), and simply unset the unnecessary fields. It's good because this way Drupal's own validation functions get called, the JavaScript-based password strength AND password matching indicator also gets rendered, and the field labels and descriptions are the same as on the user edit form (except that here I took out the e-mail changing text), but you can also change them, if you wish.

The result will look like this:

Password changing form (Full screen)

This form will be visible at example.com/change-password path (of course, example.com should be substituted to your domain), and I'll also define a block for it.

/**
 * Implements hook_menu().
 */
function YOURMODULENAME_menu() {
    $items = array();

    $items['change-password'] = array(
      'title' => t('Change password'),
      'description' => t('You can change your password here.'),
      'page callback' => 'YOURMODULENAME_render_user_pass_change_form',
      'access arguments' => array('access content'),
    );

    return $items;
}

/**
 * Render the password changing form with the usage of Drupal's built-in user_profile_form
 * 
 * @global type $user
 * @return array The rendered form array for changing password
 */
function YOURMODULENAME_render_user_pass_change_form() {

    global $user;

    if (!user_is_logged_in()) {
        drupal_access_denied();
    }

    module_load_include('inc', 'user', 'user.pages');
    $form = drupal_get_form('user_profile_form', $user);

    $request_new = l(t('Request new password'), 'user/password', array('attributes' => array('title' => t('Request new password via e-mail.'))));
    $current_pass_description = t('Enter your current password to change the %pass. !request_new.', array('%pass' => t('Password'), '!request_new' => $request_new));

    $form['account']['current_pass']['#description'] = $current_pass_description;    

    unset(
      $form['account']['name'],
      $form['account']['mail'],
      $form['account']['status'],
      $form['account']['roles'],
      $form['locale'],
      $form['l10n_client'],
      $form['picture'],
      $form['overlay_control'],
      $form['contact'],
      $form['timezone'],
      $form['ckeditor'],
      $form['metatags'],
      $form['redirect']
      );

    return $form;
}

define('PASSWORD_CHANGING_BLOCK', 'password_changing_block');

/**
 * Implements hook_block_info().
 */
function YOURMODULENAME_block_info() {

    $blocks = array();

    $blocks[PASSWORD_CHANGING_BLOCK] = array(
      'info' => t('Block for changing password'), //The name that will appear in the block list.
      'cache' => DRUPAL_CACHE_GLOBAL, // The block is the same for every user on every page where it is visible.
    );

    return $blocks;
}

/**
 * Implements hook_block_view().
 * 
 * Prepares the contents of the block.
 */
function YOURMODULENAME_block_view($delta = '') {

    switch ($delta) {
        case PASSWORD_CHANGING_BLOCK :
            if(user_is_logged_in()){
                $block['subject'] = t('Change Password');
                $block['content'] = drupal_get_form('YOURMODULENAME_render_user_pass_change_form');                
            }
            break;
    }
    return $block;
}

Of course, substitute YOURMODULENAME with your own module's name (even near 'page callback' and when calling drupal_get_form)! You can also unset other fields if necessary (e.g. more fields are rendered via another module).
Clear the cache after putting it in your code.

After this, You can simply render this form by calling drupal_get_form('YOURMODULENAME_render_user_pass_change_form');.

3
  • Thanks for the response. I'm looking for an isolated change password form. In other words an isolated version of the form you fill out after requesting a new password.
    – SMTF
    May 30, 2012 at 17:10
  • @SMTF: Oh, I'm sorry, I totally misunderstood the question. So you would like to render the password changing form. I'll correct my answer soon.
    – Sk8erPeter
    May 30, 2012 at 17:12
  • 2
    @SMTF: as I promised, I revised my original post, and wrote the code with another approach: with the usage of the built-in Drupal functions. Please try that too. Thanks!
    – Sk8erPeter
    May 31, 2012 at 1:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.