Magento checkout progress

Magento checkout progress with custom layout

Recently, while working on Magento checkout process, I stumbled on two issues related to the "one page checkout" solution used on sites Magento. The problems are maybe not very difficult to solve, but as they repeat in different projects, I think they deserve mentioning. In this article I'll shortly explain the checkout progress mechanism in Magento, I'll investigate why it doesn't work with custom layout, and how to fix it.

As you can see, Magento checkout page contains two columns:

  1. main column, consisting of checkout steps
  2. side column with „checkout progress”, list of all currently entered data in checkout process (billing adress, shipping adress, shipping method, payment method)

The checkout progress column is updated by javascript each time any checkout step is completed. But if you decide to set different layout for checkout page than the default "two-columns-right" (default in Community Edition; in Enterprise Edition we've got "one column" layout here), the checkout progress column will not be updated any more. Why?

To find an answer on this mysterious riddle, open the file /skin/frontend/default/default/js/opcheckout.js. This is the javascript mechanism controlling behaviour of checkout process. About line 50 you can find function reloadProgressBlock:

reloadProgressBlock: function(){
    var updater = new Ajax.Updater(
        $$('.col-right')[0],
        this.progressUrl,  
        {method: 'get', onFailure: this.ajaxFailure.bind(this)}
    );
},

This function updates the content of the right column, filling it with the actual checkout progress status. So if the layout of checkout page is "two columns right", everything works fine. But in other case the function fails – it can't find the DOM element with class="col-right", specified by $$('.col-right')[0] javascript statement.

Now the solution is obvious – to replace $$('.col-right')[0] by the selector of your wrapper element containing <div class="one-page-checkout-progress">. So, for example, if your HTML structure looks like that:

<div id=”my-custom-right-column”>
        <div class=”one-page-checkout-progress”>
        ...
        </div>
</div>

then you have to copy the default opcheckout.js file, put it into your theme's appriopriate folder, and edit the reloadProgressBlock function, by changing the $$('.col-right')[0] into $('my-custom-right-column'):

reloadProgressBlock: function(){
    var updater = new Ajax.Updater(
        $('my-custom-right-column'),
        this.progressUrl,
        {method: 'get', onFailure: this.ajaxFailure.bind(this)}
    );
},

Moreover, the Ajax.Updater() accepts also an id of an object as first argument, so if you select wrapper by ID, you can simplify the code, removing the $() Prototype element selector:

reloadProgressBlock: function(){
    var updater = new Ajax.Updater(
        'my-custom-right-column',
        this.progressUrl,
        {method: 'get', onFailure: this.ajaxFailure.bind(this)}
    );
},

That's all. It works :)