3

I am using Commerce but I do not require customers' billing or shipping information. However, I do need them to provide their name.

Since I have a field for the name in the user profile, I want to require anonymous users (only) to provide their name. By default, in Commerce the Account Information pane requires users to input their e-mail addresses if anonymous and is hidden if they are authenticated.

This is exactly the behavior I want, so I was hoping to add my name field from the user profile to the Account Information, but I can't find a way to do that.

Approach I tried and rejected

By adding the name field under Checkout settings-> Order-> Manage display, I was able to add the field, and using the Commerce Fieldgroup Panes module I could even display it in a custom fieldgroup. However, when taking this approach, authenticated users are prompted for their names and their names aren't prepopulated.

3
  • Just make that profile field 'name' as required & then it will be asked for anonymous. For registered it will be filled, so that it won't show.. Can it work ?
    – RajeevK
    Commented Aug 2, 2013 at 11:50
  • name is a required field, but it's not showing up, even after clearing the cache... Commented Aug 2, 2013 at 11:55
  • Please have a look at the module given by me in answer. I forget at first then I saw my own setting and found it..
    – RajeevK
    Commented Aug 2, 2013 at 12:00

4 Answers 4

8

I think you are looking for Commerce User Profile Pane module.

Commerce User Profile Pane is a module that allows you to capture a Drupal Users profile fields directly in the Commerce checkout pages. This is similar to the Commerce Billing Profile or Commerce Shipping Profile panes, but instead of storing extra fields in the Commerce Profile entity, this will allow you to store it directly in the Drupal core User entity. This is useful when you want a quick registration process without the user having to fill a long user registration form, but you still want to retain the option to complete the User profile info in the checkout phase.

2
  • 1
    Just a quick note-- even if a field is marked required in the Field UI, after installing the module, you have to go back to each field's page and mark it required for the user profile pane as well (see module instructions). Commented Aug 2, 2013 at 12:19
  • Yes. Now I know. I commented without seeing the setting. When you said you have done, I went & saw again..
    – RajeevK
    Commented Aug 2, 2013 at 12:26
4

I needed to receive an optional phone number during checkout, but I didn't think the phone number field really belonged in the Billing Information pane. As you can see in the image below, I wanted the phone number field to show up below the email address in the Account Information pane, which I renamed "Contact Information".

Commerce User Profile Pane, Commerce Fieldgroup Panes, and Address Field Phone were all too feature-rich for my needs. I just wanted to simply add one field to the Account Information pane, validate and save it to the order, thereby persisting it through the checkout.

In my case, the simplest solution was to save the phone number in the $order->data array by adding a form field to the checkout form using hook_form_alter. Before saving it into the $order->data array, I do some validation stripping and formatting on future display.

Add phone number field below email address field: add phone number field below email address field

Show phone number input with invalid characters that will be stripped out: show phone number input with invalid characters that will be stripped out

Successfully stripped invalid characters and show the saved phone number formatted for display: successfully stripped invalid characters and show the saved phone number formatted for display

Here's the code to make this happen:

/**
 * Implements hook_form_alter
 * Alter the checkout and review forms
 */
function example_form_alter(&$form, &$form_state, $form_id) {

  if ($form_id == 'commerce_checkout_form_checkout') {
    //Changing some titles and adding Bootstrap wrapper classes
    $form['account']['#title'] = t('Contact Information');
    $form['account']['login']['mail']['#title'] = t('Email Address');
    $form['account']['login']['mail']['#prefix'] = '<div class="row"><div class="col-xs-12 col-sm-5">';
    $form['account']['login']['mail']['#suffix'] = '</div></div>';
    $form['account']['login']['mail_confirm']['#title'] = t('Confirm Email Address');
    $form['account']['login']['mail_confirm']['#description'] = t('<small>Please re-enter your email address.</small>');
    $form['account']['login']['mail_confirm']['#prefix'] = '<div class="row"><div class="col-xs-12 col-sm-5">';
    $form['account']['login']['mail_confirm']['#suffix'] = '</div></div>';

    //add a phone number textfield to the account login array
    $form['account']['login']['phone_number'] = array(
      '#type' => 'textfield',
      '#title' => t('Phone Number (Optional)'),
      '#size' => 15,
      '#attributes' => array('class' => array('phone-number')),
      '#prefix' => '<div class="row"><div class="col-xs-12 col-sm-5">',
      '#suffix' => '</div></div>',
    );

    //load the order from the form state
    if ($form_state['order']->order_id) {
      $form_state['order'] = commerce_order_load($form_state['order']->order_id);

      $order = $form_state['order'];

      //prefill the phone number field if it's already been set in the data array
      if (!empty($order->data['phone_number'])) {
        $form['account']['login']['phone_number']['#default_value'] = _format_phone_number($order->data['phone_number']);
      }
    }

    //add a custom submit callback function to save the phone number to the order data array
    array_unshift($form['buttons']['continue']['#submit'], "_example_commerce_order_account_pane_checkout_form_alter_submit");
  }

  //show the phone number in the account info section of the review screen
  if ($form_id == 'commerce_checkout_form_review') {
    //load the order from the form state
    if ($form_state['order']->order_id) {
      $form_state['order'] = commerce_order_load($form_state['order']->order_id);

      $order = $form_state['order'];

      //append the phone number to the account info html. there's probably a better way to do this...
      if (!empty($order->data['phone_number'])) {
        $form['checkout_review']['review']['#data']['account']['data'] .= '<div class="form-item form-type-item"><label>Phone Number: </label> '._format_phone_number($order->data['phone_number']).'</div>';
      }
    }
  }
}

/**
 * Custom Account pane: checkout form submission callback.
 */
function _example_commerce_order_account_pane_checkout_form_alter_submit($form, &$form_state) {
  if (!empty($form_state['values']['account'])) {
    $pane_values = $form_state['values']['account'];

    // If the user is editing an order, load a fresh copy to merge changes into.
    if ($form_state['order']->order_id) {
      $form_state['order'] = commerce_order_load($form_state['order']->order_id);
    }

    $order = $form_state['order'];

    if (!empty($pane_values['login']['phone_number'])) {
      $order->data['phone_number'] = _strip_chars_in_phone_number($pane_values['login']['phone_number']);
    }
    else {
      $order->data['phone_number'] = '';
    }

    //don't cut a new revision, just save phone number
    $order->revision = FALSE;
    commerce_order_save($order);
  }
}

/**
 * Custom utility function to strip invalid characters from phone number input
 * leaving only digits
 * stripping a leading 1
 * substring first 10 digits
 */
function _strip_chars_in_phone_number($phone) {
  $strPhoneDigits = '';

  if (isset($phone) && !empty($phone)) {
    $strPhoneDigits = preg_replace("/[\D]/", "", $phone);
    $strPhoneDigits = preg_replace("/^1/", "", $strPhoneDigits);
    $strPhoneDigits = substr($strPhoneDigits, 0, 10);
  }

  return $strPhoneDigits;
}

/**
 * Custom utility function to format a phone number for display
 */
function _format_phone_number($phone) {
  $strFormattedPhone = '';

  if (isset($phone) && !empty($phone)) {
    if (strlen($phone) == 7) {
      $strFormattedPhone = preg_replace("/([0-9]{3})([0-9]{4})/", "$1-$2", $phone);
    }
    elseif (strlen($phone) == 10) {
      $strFormattedPhone = preg_replace("/([0-9]{3})([0-9]{3})([0-9]{4})/", "($1) $2-$3", $phone);
    }
    else {
      $strFormattedPhone = $phone;
    }
  }

  return $strFormattedPhone;
}
3
  • Wow, thanks, Your code proved very useful. I added a custom token [commerce-order:phone-number] also, so I could add the customer's phone number in the "admin mail" as well.
    – TBJ
    Commented Jan 9, 2017 at 10:20
  • Thank you very much for posting your solution. I tried using the code so I could add in a telephone number field but had a few problems which I could not solve. First the form_alter function was running twice on the review pane so the telephone number was appearing twice. I didn't know why it was doing this. Also, my users were not creating accounts on checkout so I wasn't sure how to access the telephone number from the admin order details screen. In the user info, it only showed the email address.
    – Ben
    Commented Feb 24, 2017 at 11:46
  • I am searching a simple solution for adding a phone field to commerce in Drupal 8.
    – drupalfan
    Commented Aug 26, 2017 at 13:22
1

I've found it useful to add fields to the Order object directly so that they are retained in the Orders UI and available for use in the Rules API when the order is completed. I can then create the user account via Rules.

More specifically, I use Profile2 to manage extra user data; I've added fields to the Order type (/admin/commerce/config/order/fields) and in some cases I can expose these as panes in the order form. For adding data to the user account section along with the email field, I found that the solution by @Wesley goes most of the way. However, adding data to the order object directly doesn't work unless you use entity metadata wrappers. (EMW has been a lifesaver for me on more than one occasion)

To extend his example, say we have a field on the Order type called "Phone Number" (default machine name field_phone_number); you will have to alter the callback function as follows:

function _example_commerce_order_account_pane_checkout_form_alter_submit($form, &$form_state) {
  if (!empty($form_state['values']['account'])) {
    $pane_values = $form_state['values']['account'];

    // If the user is editing an order, load a fresh copy to merge changes into.
    if ($form_state['order']->order_id) {
      $form_state['order'] = commerce_order_load($form_state['order']->order_id);
    }

    $order_wrapper = entity_metadata_wrapper('commerce_order', $form_state['order']); 

    if (!empty($pane_values['login']['phone_number'])) {
      $order_wrapper->field_phone_number->set(_strip_chars_in_phone_number($pane_values['login']['phone_number']));
    }
    else {
      $order_wrapper->field_phone_number->set('');
    }
    // save the wrapper then convert to StdClass object
    $order_wrapper->save();
    $order = $order_wrapper->value();

    //don't cut a new revision, just save phone number
    $order->revision = FALSE;
    commerce_order_save($order);
  }
}
1

For Drupal 8: there is a great module https://www.drupal.org/project/commerce_checkout_order_fields. Just enable it, go to /admin/commerce/config/order-types/default/edit/form-display, scroll down, enable 'Checkout' view, drag/drop fields on the Checkout view, and then go to /admin/commerce/config/checkout-flows/manage/default and add 'Order Fields: Checkout' pane to a step you want. Enjoy!

Your Answer

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

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