1

I have a custom checkout pane that only loads if there is a product of type 'Event' in the cart. For each product of type 'Event' in the cart, the pane prints out two custom fields: 'Ticketholder's Name' and 'Ticketholder's Email'. Further depend on the event there are upto another 8 extra fields such as 'Dietary Requirements' and 'Arrival Time'.

In the past, if I have a custom value that I want sent through with the order, I have created a custom field within the order fields, and then set the value in the following way:

$order->field_my_custom_field['und']['0']['value'] = 'my custom value';
commerce_order_save($order);

Now this seems fine for custom values that need to be set for all orders. However with this custom checkout pane, these custom fields only appear for 'events'. Further it is dynamic, so if there are 2 tickets for the same event (i.e one product of quantity 2) in the cart, it will need to store Ticketholder's Name & Email etc. for both ticket 1 and ticket 2.

So is there a more appropriate way to set the custom values and display them when you go to Store > Orders > View Order? Can I programmatically attach the custom fields to the order?

In the past I have looked at adding custom line items to checkout to store this kind of data but have been unsuccessful in getting them to display within Store > Orders > View Order. Further the same event, with quantity 2 will just be one line item in the cart so I'm not sure how you would attach the data for both ticketholders in this way.

What is the best way to store this data as part of the Order, so that it is accessible at Store > Orders > View Order?

Thanks for your help!

1

I have had the same issue for some time with field collections and simply switching the panes on and off in the order entity was not doing the trick. I ended up being able to work up a solution using order types. http://drupal.org/project/commerce_order_types

In addition I want to mention that we used the following patch: http://drupal.org/node/1887812 so that commerce could recognize panes from different order types. At this point your already there, its a simple process of switching order types and subsequent panes based on the order type.

| improve this answer | |
1

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;
}

Now to answer the rest of your question about showing this custom data on Store > Orders > View Order:

Sometimes there's data I want to quickly see on the Store > Orders view itself without having to go into each order. To do this, I edit the view at admin/structure/views/view/commerce_backoffice_orders/edit/admin_page. You need Views PHP to be able to add Global: PHP fields to your view. Once you have that module enabled, you can add the following fields to your view. You don't necessarily need to add a field for the entire Order object, but it is helpful if you're going to be adding multiple fields that use the Order object. Otherwise, each field will have to call commerce_order_load, when you could only do it one time and reference that field from other fields later on.

enter image description here

There are 2 key parts to this. In the Value code section, you must return some value that you want to use or display. You can see that I'm using the $row->order_id value made available to me by an existing field on this view. In the Output code section, it's usually best just to print the $value variable made available to you. This $value variable contains the value of the $phoneNumber variable I returned in the Value code section.

enter image description here

That's it! That's all there is to it.

But to get this info to show up on Store > Orders > Edit Order, there are a couple different ways to do it and a couple different places you can show it. I chose to display the phone number data as an additional settings tabbed fieldset, down by the Order Status, User Information, and Order History tabs.

Here's the code to do this:

/**
 * Implements hook_form_alter
 */
function example_form_alter(&$form, &$form_state, $form_id) {
//Add phone number field to the additional settings tab of the admin edit order form
  if ($form_id == 'commerce_order_ui_order_form') {
    $form['phone_number'] = array(
      '#type' => 'fieldset',
      '#title' => t('Phone Number'),
      '#collapsible' => TRUE,
      '#collapsed' => FALSE,
      '#group' => 'additional_settings',
      '#weight' => 20,
    );
    $form['phone_number']['number'] = array(
      '#type' => 'textfield',
      '#title' => t('Phone Number'),
      '#default_value' => (isset($form['#entity']->data['phone_number']) && !empty($form['#entity']->data['phone_number'])) ? $form['#entity']->data['phone_number'] : '',
    );
  }
}
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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