Defining customer profile weights in Drupal Commerce

Drupal Commerce is a great leap forward from Ubercart. It’s especially heartening to see it use so much of other APIs - Views, Rules etc. - rather than doing its own thing. However, we think we’ve found a bug in the way that it sorts the fields and panes on the checkout page.

The commerce_customer sub-module takes customer profile types (defined via hook_commerce_customer_profile_type_info()) and prepares them for inclusion in the checkout pane. When doing so, it also transfers a weight field called checkout_pane_weight, so that in theory these types can be weighted (to make e.g. contact form appear before billing address form).

However, checkout_pane_weight is not used anywhere else in the commerce codebase as far as I can see. When commerce_checkout_panes() merges in an array of defaults, it includes a simple ‘weight’ field, but not ‘checkout_pane_weight’.

Until this bug is fixed, you can work around it with the following hook in your own module:

<?php
/** 
 * Implements hook_commerce_checkout_pane_info_alter() 
 */
function MYMODULE_commerce_checkout_pane_info_alter(&$checkout_panes) {  
  // Get weights from hook_commerce_customer_profile_type_info
  $pane_weights = cscommerce_commerce_customer_profile_type_info();
  // Loop over them and weight the assembled panes accordingly
  foreach($pane_weights as $pane_key_suffix => $weight_config) {
    $pane_key = "customer_profile_$pane_key_suffix";
    if (array_key_exists($pane_key, $checkout_panes)) {
      $checkout_panes[$pane_key]['weight'] = $weight_config['checkout_pane_weight'];
    }  
  }
}

Note that, because commerce_checkout_panes() increments pane weights by a single digit each time, you don’t get much wiggle room when you’re trying to weight your own panes and they can easily end up all at the top or all at the bottom. 

So if, like me, you just want to swap round two panes, and the single-digit weight increments are messing things up, here’s an even quicker workaround:

<?php
/**
 * Implements hook_commerce_checkout_pane_info_alter()
 */
function MYMODULE_commerce_checkout_pane_info_alter(&$checkout_panes) {
  if ($checkout_panes['customer_profile_billing']['weight'] 
      > $checkout_panes['customer_profile_contact']['weight']) {
    list($checkout_panes['customer_profile_billing']['weight'],
         $checkout_panes['customer_profile_contact']['weight']) =
      array($checkout_panes['customer_profile_contact']['weight'],
          $checkout_panes['customer_profile_billing']['weight']);
  }
}

This is a simple function that swaps the two weights around in a single assignment step, and it means that if you have weights of 20,19,18,17,16… then you can seamlessly swap your two profiles around to be 20,19,17,18,16… without any recalculation.