Ubercart: modifying checkout panes

Ubercart: modifying checkout panes

Posted by stella on Tue, 2009-11-03 11:56 in

The Ubercart module is one of the best e-commerce options for Drupal currently. It is very user friendly and highly flexible with administrators having control over the product catalogue, payment gateways and email notifications. Site administrators also have control over which checkout panes are displayed during checkout and the order in which they appear. However, as I found out recently, while it is easy to control checkout pane visibility, and even add your own, there's no simple way of modifying the forms contained within a checkout pane. This article will cover one solution on how to overcome this.

For a site I'm working on, I needed to be able to add a new field to contain the user's title (Mr, Mrs, Miss, etc) to the "billing information" ubercart checkout pane. I first implemented hook_form_alter() to add the field and set a custom submit handler. However, while I was able to modify the form, the submit function was never called and I wasn't able to save the value of the new field to the customer's order. This is because the ubercart checkout panes don't fully utilise the FAPI.

My solution was to create a new checkout pane and to entirely recreate the billing pane by pulling in the pane contents from the ubercart module, adding my own changes and returning the merged version.

So first I created a new checkout pane by implementing the hook, hook_checkout_pane():

<?php
function mymodule_checkout_pane() {
 
// Replacement for standard billing address pane.
 
$panes[] = array(
   
'id' => 'mymodule_billing',
   
'callback' => 'mymodule_checkout_pane_mymodule_billing',
   
'title' => t('Billing Address'),
   
'desc' => t('Custom billing address fields.'),
   
'weight' => 2,
   
'process' => TRUE,
   
'collapsible' => FALSE,
  );
  return
$panes;
}
?>

Each pane needs a unique id. I originally used the same id as the ubercart billing information pane in the hope that I could override it, but that didn't work unfortunately. The other two fields to pay particular attention to are callback - the function to call to build the pane and process it, and process - this should be set to TRUE, so your callback function is called with the 'process' operation.

For the callback function, I didn't want to just copy and paste in Ubercart's uc_checkout_pane_billing() function as then I wouldn't be able to avail of any modifications made to the original "billing information" pane by simply upgrading the module - I would have to modify my custom module each time. So for each operation, my checkout pane calls Ubercart's one, makes my custom changes and then returns the merged result. The final result is as follows:

<?php
function mymodule_checkout_pane_mymodule_billing($op, &$arg1, $arg2) {
  require_once(
drupal_get_path('module', 'uc_cart') . '/uc_cart_checkout_pane.inc');

  switch (
$op) {
    case
'view':
     
// This is needed to avoid 'an illegal choice has been made' error.
     
if (isset($_POST['panes']['mymodule_billing']['billing_country'])) {
       
$_POST['panes']['billing']['billing_country'] = $_POST['panes']['mymodule_billing']['billing_country'];
      }
     
$contents = uc_checkout_pane_billing($op, $arg1, $arg2);

     
// Add 'title' or 'salutation' to billing address details.
     
$contents['contents']['billing_title'] = array(
       
'#type' => 'select',
       
'#title' => t('Title'),
       
'#options' => array('Mr', 'Mrs', 'Ms', 'Miss', 'Dr', 'Fr', 'Rev', 'Sr'),
       
'#required' => TRUE,
       
'#weight' => 0,
       
'#default_value' => $arg1->data['billing_title'],
      );
     
// Address history selector doesn't work for this solution, so remove it.
     
unset($contents['contents']['billing_address_select']);

      return
$contents;

    case
'review':
      return
uc_checkout_pane_billing($op, $arg1, $arg2);

    case
'process':
     
$arg1->billing_title = $arg2['billing_title']; // Save our custom field.
     
return uc_checkout_pane_billing($op, $arg1, $arg2);
  }
}
?>

Thanks!! This saved me lots

Thanks!! This saved me lots of time.

Posted by Anonymous (not verified) on Tue, 2010-05-25 17:16
thanks

hi, thanks for this

i have use your solution for my site: http://www.one.nl/

i also need to know if you ever try to integrate a form within checkout pane?
i want to place a login form inside checkout_pane_customer
so basically instead of i send user to user/login page
they can just login through cart/checkout page

i have tried using thickbox module
however, this module did not support in case a user login with wrong username or password

so please share your knowledge if you have any solution for this problem

thank you very much

Posted by erwin yonathan (not verified) on Mon, 2010-06-07 16:50
You could try the popups

You could try the popups module (http://drupal.org/project/popups), though I think ubercart will update the correct user account if they enter in the same email address.

Posted by stella on Mon, 2010-06-07 17:01
thank you for your

thank you for your suggestion
however my boss and project leader really want it to be a form next to fieldset with customer e-mail textfield
i have a solution before using javascript, appending the login form in the predefine area
but since without javascript it will not work anymore
so stella, if you know a solution, you will be a really live saver

thank you

Posted by erwin yonathan (not verified) on Tue, 2010-06-08 15:16
Thanks for the code

Thanks for the code Stella. It works great on my local host site. I will be adding this soon to my live scooter production site.

Thanks

Posted by Scooter (not verified) on Mon, 2010-07-05 16:13
Works like a charm. For the

Works like a charm. For the record: to make this work, create a new module (mymodule.module with both the hooks and a mymodule.info, I gave it the dependancy 'uc_cart' since it is part of the cart-checkout).

Too bad the known-addresses feature doesn't work with this mod. For those who want to keep using it, it might be an option to replace the original uc_checkout_pane_billing() with the posted one.

Posted by Matthijs (not verified) on Sat, 2010-07-17 16:30
Ubercart 2.3 introduces hook_checkout_pane_alter()

As of Ubercart 2.3, there is now a new hook called hook_checkout_pane_alter() in which you can alter the information about the panes.
So now an implementation of hook_checkout_pane() is not needed anymore. However, the callback function from the example, 'mymodule_checkout_pane_mymodule_billing()', is still needed.

Example of implementing hook_checkout_pane_alter() which alters the billing pane:

<?php
/**
* Implementation of hook_checkout_pane_alter().
* Alters billing pane
* @param array $panes
* @return void
*/
function mymodule_checkout_pane_alter(&$panes) {
  foreach (
$panes as $key => $pane) {
    switch (
$pane['id']) {
      case
'billing':
       
$panes[$key]['callback'] = 'mymodule_checkout_pane_mymodule_billing';
        break;
    }
  }
}
?>

Posted by MegaChriz (not verified) on Tue, 2010-07-27 10:41
Thanks Stella and MegaChriz

Great! This helped me carry out exactly what I needed in a more future-proof fashion. I hope to write my own blog post when I get a minute, on the issues I've solved with help from both of you. Thanks.

~mccrodp

Posted by mccrodp (not verified) on Sun, 2010-08-29 18:08
Post new comment
The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.

More information about formatting options