commerce_customer 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).

The problem with this is that checkout_pane_weight is not used anywhere else in the commerce codebase as far as I can see. commerce_checkout_panes() merges in defaults including a simple 'weight' field, but not 'checkout_pane_weight'.

Commerce should standardize on 'weight' unless there's a reason for commerce_customer for doing what it should be doing. In the mean time, you can work around this bug with the following hook in your own module:

/**
 * 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. It'd be great if the weights were more spaced out - or preferably just have the panes just unweighted by default, and sorted by order-added-to-array if no weight is present: isn't this how Drupal sorting usually works?

Comments

jp.stacey’s picture

By the way: 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:

/**
 * 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']);
  }
}

Replace billing and contact with your own customer profile names.

rszrama’s picture

Category: bug » support
Status: Active » Closed (works as designed)

This code actually works as designed. The "checkout_pane_weight" apparently does need to be documented in commerce_customer.api.php, though, so I can take care of that.

What's happening is a customer profile type can provide a hint as to what the default weight of the profile type's corresponding checkout pane should be. From there on out, the weight of the checkout pane is the purview of the Checkout module itself. The customer profile type itself doesn't have a weight, though, so it wouldn't make sense to just name this property "weight".

This code is all the processing we need to handle this attribute:

    $checkout_panes['customer_profile_' . $type] = array(
      'title' => !empty($instance['label']) ? check_plain($instance['label']) : $profile_type['name'],
      'file' => 'includes/commerce_customer.checkout_pane.inc',
      'base' => 'commerce_customer_profile_pane',
      'page' => 'checkout',
      'weight' => isset($profile_type['checkout_pane_weight']) ? $profile_type['checkout_pane_weight'] : $weight++,
    );

From there on, the checkout pane's weight is what matters. Also, you can feel free to use decimal values to set the weight of items - you don't have to use integers.

For a similarly named attribute, you could refer to the "status_cart" property on checkout pages, which instructs the Checkout module on how to define the order status that corresponds to the checkout page. The key thing here is that these properties are instructions telling the module how to create other data structures.