diff --git a/commerce_checkout_login.module b/commerce_checkout_login.module
index e812f22..825ccec 100644
--- a/commerce_checkout_login.module
+++ b/commerce_checkout_login.module
@@ -5,6 +5,57 @@
* Adds an inline login form to the Account Information checkout pane.
*/
+/**
+ * Implements hook_form_FORM_ID_alter().
+ *
+ * Capture checkout pane settings
+ */
+function commerce_checkout_login_form_commerce_checkout_pane_settings_form_alter(&$form, &$form_state, $form_id) {
+ // Exit if not account checkout pane
+ if (!isset($form['checkout_pane']['#value']['pane_id']) || $form['checkout_pane']['#value']['pane_id'] != 'account') {
+ return;
+ }
+
+ $form['settings']['commerce_checkout_login'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Commerce checkout login configuration'),
+ );
+ $settings_form = &$form['settings']['commerce_checkout_login'];
+
+ $settings_form['commerce_checkout_login_username'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Allow new customers choose their username'),
+ '#description' => t('If checked, a new customer will have the option to choose a username.'),
+ '#default_value' => variable_get('commerce_checkout_login_username', FALSE),
+ );
+
+ $settings_form['commerce_checkout_login_password'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Allow new customers choose their password'),
+ '#description' => t('If checked, a new customer will have the option to choose a password if the system wide settings permit this.'),
+ '#default_value' => variable_get('commerce_checkout_login_password', FALSE),
+ );
+
+ $settings_form['commerce_checkout_login_send_welcome_message'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Send welcome e-mail after creating a new user.'),
+ '#description' => t('If checked, an e-mail with a welcome message (no approval required) will be sent to the new user. You can configue the message !here.', array('!here' => l(t('here'), 'admin/config/people/accounts'))),
+ '#default_value' => variable_get('commerce_checkout_login_send_welcome_message', FALSE),
+ );
+ $settings_form['commerce_checkout_login_send_welcome_message_show_message'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Show an e-mail notification message.'),
+ '#description' => t('If checked, a system message will be set, notifying the user of the welcome e-mail being sent.'),
+ '#default_value' => variable_get('commerce_checkout_login_send_welcome_message_show_message', FALSE),
+ '#prefix' => '
',
+ '#suffix' => '
',
+ '#states' => array(
+ 'invisible' => array(
+ ':input[name="commerce_checkout_login_send_welcome_message"]' => array('checked' => FALSE),
+ ),
+ ),
+ );
+}
/**
* Implements hook_form_FORM_ID_alter().
@@ -14,6 +65,7 @@
*/
function commerce_checkout_login_form_commerce_checkout_form_alter(&$form, &$form_state) {
global $user;
+ $show_conf_mail = variable_get('commerce_order_account_pane_mail_double_entry', FALSE);
// If the Account Information pane is on the current checkout page and the
// user is not logged in...
@@ -25,31 +77,65 @@ function commerce_checkout_login_form_commerce_checkout_form_alter(&$form, &$for
),
);
+ // Add ajax to confirmation mail for immediate validation:
+ if (isset($form['account']['login']['mail_confirm'])) {
+ $form['account']['login']['mail_confirm']['#ajax'] = array(
+ 'callback' => 'commerce_checkout_login_checkout_form_refresh',
+ 'wrapper' => 'account-login-container',
+ );
+ }
+
// Check the form state to see if an e-mail address has been specified.
- if (!empty($form_state['values']['account']['login'])) {
- $mail = trim($form_state['values']['account']['login']['mail']);
+ if (!empty($form_state['values']['account']['login']['mail']) || !empty($form_state['order']->mail)) {
+ $mail = !empty($form_state['values']['account']['login']['mail']) ? trim($form_state['values']['account']['login']['mail']) : $form_state['order']->mail;
// Don't attempt to load the user for an invalid e-mail address.
- if ($error = user_validate_mail($mail)) {
- form_set_error('account][login][mail', $error);
- }
- elseif ($account = user_load_by_mail($mail)) {
- // If a user already exists for the given e-mail address, display a
- // message letting the customer know this.
- $form['account']['login']['mail']['#description'] = t('There is already an account registered to %mail. You can login now to use your account information during checkout.', array('%mail' => $mail));
-
+ if (!user_validate_mail($mail) && user_load_by_mail($mail)) {
+ // An existing e-mail address has been entered. Add a password field to
+ // allow the customer to login.
$form['account']['login']['password'] = array(
'#type' => 'password',
'#title' => t('Password'),
+ '#required' => TRUE,
+ '#description' => t('Please enter the password for your account. !forgot', array('!forgot' => l(t('Did you forget your password?'), 'user/password')))
);
- $form['account']['login']['login_now'] = array(
- '#type' => 'submit',
- '#value' => t('Login now'),
- '#limit_validation_errors' => array(array('account')),
- '#validate' => array('commerce_checkout_login_checkout_form_validate'),
- '#submit' => array('commerce_checkout_login_checkout_form_submit'),
- );
+ // No e-mail confirmation is required to login. So we hide the e-mail
+ // confirmation field if it is set.
+ if (isset($form['account']['login']['mail_confirm'])) {
+ $form['account']['login']['mail_confirm']['#value'] = $mail;
+ $form['account']['login']['mail_confirm']['#access'] = FALSE;
+ }
+ }
+ elseif (variable_get('commerce_checkout_login_username', FALSE) || variable_get('commerce_checkout_login_password', FALSE)) {
+ if (variable_get('commerce_checkout_login_username', FALSE)) {
+ $form['account']['login']['name'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Username'),
+ '#maxlength' => USERNAME_MAX_LENGTH,
+ '#description' => t('Spaces are allowed; punctuation is not allowed except for periods, hyphens, apostrophes, and underscores.'),
+ '#attributes' => array('class' => array('username')),
+ );
+ }
+
+ // Find out if email verification is required.
+ $mail_verify = variable_get('user_email_verification', TRUE);
+ $mail_verify = !$mail_verify ? variable_get('logintoboggan_confirm_email_at_registration', 0) : $mail_verify;
+
+ // If password selection is enabled and verification is not required add
+ // the password field.
+ if (variable_get('commerce_checkout_login_password', FALSE) && !$mail_verify) {
+ $desc = t('Provide a password for the new account in both fields.');
+ if ($min_pass = variable_get('logintoboggan_minimum_password_length', 0)) {
+ $desc .= ' ' . t('Password must be at least %length characters.', array('%length' => $min_pass));
+ }
+
+ $form['account']['login']['pass'] = array(
+ '#type' => 'password_confirm',
+ '#size' => 25,
+ '#description' => $desc,
+ );
+ }
}
}
}
@@ -59,50 +145,219 @@ function commerce_checkout_login_form_commerce_checkout_form_alter(&$form, &$for
* Ajax callback: returns the account information pane to an AJAX request.
*/
function commerce_checkout_login_checkout_form_refresh($form, $form_state) {
- return $form['account']['login'];
+ $show_conf_mail = variable_get('commerce_order_account_pane_mail_double_entry', FALSE);
+
+ $mail = !empty($form_state['values']['account']['login']['mail']) ? trim($form_state['values']['account']['login']['mail']) : '';
+ _validate_email($mail);
+
+ if (!$show_conf_mail) {
+ return $form['account']['login'];
+ }
+
+
+ // Return AJAX commands to set focus to the mail confirmation field for
+ // improved user experience.
+ $commands = array();
+ $commands[] = ajax_command_replace('#' . $form['account']['login']['mail']['#ajax']['wrapper'], drupal_render($form['account']['login']));
+ $commands[] = ajax_command_invoke('[name="account[login][mail_confirm]"]', 'focus');
+ print ajax_render($commands);
+ exit;
}
/**
- * Validate callback: validate the user credentials
+ * Implements hook_commerce_checkout_pane_info_alter().
*/
-function commerce_checkout_login_checkout_form_validate($form, &$form_state) {
- // @todo Add flood control support as in user_login_authenticate_validate().
- $account = user_load_by_mail($form_state['values']['account']['login']['mail']);
-
- // If the user account is blocked...
- if (user_is_blocked($account->name)) {
- // Display an appropriate error message.
- form_set_error('account][login][email', t('The username %name has not been activated or is blocked.', array('%name' => $account->name)));
+function commerce_checkout_login_commerce_checkout_pane_info_alter(&$checkout_panes) {
+ if (isset($checkout_panes['account'])) {
+ $checkout_panes['account']['callbacks']['checkout_form_validate'] = 'commerce_checkout_login_commerce_checkout_pane_validate';
+ $checkout_panes['account']['callbacks']['checkout_form_submit'] = 'commerce_checkout_login_commerce_checkout_pane_submit';
}
- elseif ($uid = user_authenticate($account->name, $form_state['values']['account']['login']['password'])) {
- // Otherwise, if the user authenticates based on the name of the loaded
- // account and the supplied password, retain the uid to login the user on
- // final submission.
- $form_state['commerce_checkout_login_uid'] = $uid;
+}
+
+/**
+ * Account checkout pane validation.
+ */
+function commerce_checkout_login_commerce_checkout_pane_validate(&$form, &$form_state, $checkout_pane, $order) {
+ $mail = !empty($form_state['values']['account']['login']['mail']) ? trim($form_state['values']['account']['login']['mail']) : $form_state['order']->mail;
+ $validated = _validate_email($mail);
+
+ if ($account = user_load_by_mail($mail)) {
+ $validated = _validate_existing_account($form, $form_state, $account);
}
+ // A non-existing e-mail address has been entered.
else {
- // But indicate that we could not login the user if validation failed.
- form_set_error('account][login][password', t('Sorry, unrecognized username or password. Have you forgotten your password?', array('@password' => url('user/password'))));
+ // Validate e-mail confirmation field if set.
+ if (isset($form['account']['login']['mail_confirm'])) {
+ $mail_confirm = !empty($form_state['values']['account']['login']['mail_confirm']) ? trim($form_state['values']['account']['login']['mail_confirm']) : '';
+ if (empty($mail_confirm) || $mail != $mail_confirm) {
+ form_set_error('account][login][mail_confirm', t('The specified e-mail addresses do not match.'));
+ $validated = FALSE;
+ }
+ }
+
+ if (isset($form['account']['login']['password'])) {
+ // A password field is present. During rebuild of the form, this password
+ // field will be removed because a non-existing email address was entered.
+ // Previous form validation might already have set a password required
+ // message. We need to remove said message.
+ $messages = drupal_get_messages('error');
+ $password_title = $form['account']['login']['password']['#title'];
+ foreach ($messages['error'] as $message) {
+ if ($message != strip_tags(t('The field %field is required.', array('%field' => $password_title)))) {
+ // This message is not the password required message, re-add it.
+ drupal_set_message($message, 'error');
+ }
+ }
+ }
+
+ $username = substr($mail, 0, strpos($mail, '@'));
+ if (variable_get('commerce_checkout_login_username', FALSE)) {
+ $username = $form_state['values']['account']['login']['name'];
+ // Validate username.
+ if ($error = user_validate_name($username)) {
+ form_set_error('account][login][name', $error);
+ $validated = FALSE;
+ }
+ // Make sure the name is not already taken.
+ elseif ((bool) db_select('users')->fields('users', array('uid'))->condition('name', db_like($username), 'LIKE')->range(0, 1)->execute()->fetchField()) {
+ form_set_error('account][login][name', t('The name %name is already taken.', array('%name' => $username)));
+ $validated = FALSE;
+ }
+ }
+ else{
+ // Make sure the automatic username does not already exist.
+ $similar_names = db_select('users')
+ ->fields('users', array('uid', 'name'))
+ ->condition('name', db_like($username), 'LIKE')
+ ->execute()
+ ->fetchCol(1);
+ if ($similar_names && in_array($username, $similar_names)) {
+ for ($i = 1; $i < count($similar_names) + 2; $i++) {
+ if (!in_array($username.$i, $similar_names)) {
+ $username = $username.$i;
+ break;
+ }
+ }
+ }
+ }
+
+ if (variable_get('commerce_checkout_login_password', FALSE)) {
+ // Validate password if logintoboggan is present.
+ if (isset($form_state['values']['account']['login']['pass']) && module_exists('logintoboggan')) {
+ if ($error = logintoboggan_validate_pass($form_state['values']['account']['login']['pass'])) {
+ form_set_error('account][login][pass', $error);
+ $validated = FALSE;
+ }
+ }
+ }
+
+ if ($validated) {
+ // Create new user.
+ $edit = array(
+ 'name' => $username,
+ 'mail' => $mail,
+ 'init' => $mail,
+ 'pass' => isset($form_state['values']['account']['login']['pass']) ? $form_state['values']['account']['login']['pass'] : user_password(),
+ 'status' => 1,
+ 'timezone' => variable_get('user_default_timezone', variable_get('date_default_timezone', '')),
+ );
+
+ $account = user_save(NULL, $edit);
+ // set the uid to enable automatic login on submit.
+ $form_state['commerce_checkout_login_uid'] = $account->uid;
+
+ if (variable_get('commerce_checkout_login_send_welcome_message', FALSE)) {
+ _user_mail_notify('register_no_approval_required', $account);
+ if (variable_get('commerce_checkout_login_send_welcome_message_show_message', FALSE)) {
+ drupal_set_message(t('A welcome message with further instructions has been sent to your e-mail address.'));
+ }
+ }
+ }
}
+
+ return $validated;
}
/**
- * Submit callback: attempt a login of the user now.
+ * Account checkout pane submit handler.
*/
-function commerce_checkout_login_checkout_form_submit($form, &$form_state) {
+function commerce_checkout_login_commerce_checkout_pane_submit(&$form, &$form_state, $checkout_pane, $order) {
global $user;
if (!empty($form_state['commerce_checkout_login_uid'])) {
- // Load the specified user into the global $user variable.
- $user = user_load($form_state['commerce_checkout_login_uid']);
+ if (!empty($user->uid)) {
+ // Load the full user object
+ $user = user_load($user->uid);
+ }
+ else {
+ // Load the specified user into the global $user variable.
+ $user = user_load($form_state['commerce_checkout_login_uid']);
- // "Finalize" the login by triggering the appropriate system messages, IP
- // address and login timestamp logging, and user login hook.
- user_login_finalize();
+ // "Finalize" the login by triggering the appropriate system messages, IP
+ // address and login timestamp logging, and user login hook.
+ user_login_finalize();
+ }
// Convert the current cart order to an authenticated cart for the current
// user and clear out our variable from the form state.
- commerce_cart_order_convert($form_state['order'], $user);
+ $oid = is_object($form_state['order']) ? $form_state['order']->order_id : $form_state['order'];
+ $order = commerce_order_load($oid);
+ if (empty($order->uid)) {
+ commerce_cart_order_convert($order, $user);
+ }
unset($form_state['commerce_checkout_login_uid']);
}
}
+
+/**
+ * Email validation helper
+ */
+function _validate_email($mail) {
+ if ($error = user_validate_mail($mail)) {
+ form_set_error('account][login][mail', $error);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Known user validation helper.
+ */
+function _validate_existing_account(&$form, &$form_state, &$account) {
+ if ($user = user_uid_optional_load()) {
+ if ($user->uid === $account->uid) {
+ // Nothing to validate, the user is already logged in.
+ return TRUE;
+ }
+ }
+ // If there is no password field present, the customer has not yet been
+ // informed about the the pre-existing account. We therefore have to inform
+ // the customer about this.
+ if (!isset($form['account']['login']['password'])) {
+ $message = t('There is already an account registered to %mail. Please enter your password to continue checkout.', array('%mail' => $account->mail));
+ drupal_set_message($message, 'warning');
+ // By invalidating the form submission we trigger a rebuild which will cause
+ // the password field to be rendered.
+ return FALSE;
+ }
+ else {
+ // If the user account is blocked...
+ if (user_is_blocked($account->name)) {
+ // Display an appropriate error message.
+ form_set_error('account][login][email', t('The username %name has not been activated or is blocked.', array('%name' => $account->name)));
+ return FALSE;
+ }
+
+ // If the user authenticates based on the name of the loaded account and the
+ // supplied password, retain the uid to login the user on final submission.
+ if ($uid = user_authenticate($account->name, $form_state['values']['account']['login']['password'])) {
+ $form_state['commerce_checkout_login_uid'] = $uid;
+ return TRUE;
+ }
+ else {
+ // Indicate that the user could not be logged in if validation failed.
+ form_set_error('account][login][password', t('Sorry, unrecognized username or password. !password', array('!password' => l('Have you forgotten your password?', 'user/password'))));
+ return FALSE;
+ }
+ }
+}