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:
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:
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;
}
name
is a required field, but it's not showing up, even after clearing the cache...