Szymon Switala's blog

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 :)

Magento Checkout – How to customize the design

Customize checkout page!One of the most important parts of any e-commerce solution, including Magento, is checkout process. The number of orders is higly dependent on the simplicity, usability and even look of the checkout pages. That's why shop owners often decide to create custom design of those pages in their Magento website. With Magento templates system you can easily customize the look of any page, but in case of checkout, you have to keep some default constructions.

You can find the default template of checkout stages in app/design/frontend/.../.../templates/checkout/onepage.phtml. Here's the fragment of html output of that template:

<ol id="checkoutSteps" class="one-page-checkout">
    <li id="opc-login" class="section">
        <div class="head">
            ...<!-- head of  login section -->
        </div>
        <div id="checkout-step-login" class="box a-item" style="display:none;">
            ...<!-- body of login section -->
        </div>
    </li>
    ... <!-- next sections here -->
</ol>

As we can see, the checkout process is enclosed in an ordered list (<ol>...</ol>). It is quite a good idea, as the order of steps is very important here. Moreover, the default javaScript scripts are strongly related to the html structure (especially to the names of classes – we will look at them later). So it is suggested to preserve this default structure of an ordered list.

To improve the usability of the process, it is a good habit to give a different look to checkout steps headers, depending on the currently active stage. It is an easy task in Magento, because the included script dynamicaly adds or removes class names to the <li class="section"> elements of <ol id="checkoutSteps">. Those class names depend on the currently active step of checkout:

  • no additional class for all next steps after the current step
  • class="allow" for all previous steps
  • class="allow active" for the current step

A similar mechanism is applied in checkout progress - an additional column containing data of already passed checkout steps (billing address, shipping address, shipping method and payment method). The content of this column is changed dynamically, too, according to the current step. The example below show the checkout progress block's html structure after the "billing information" checkout step:

<div class="box one-page-checkout-progress">
    <h3>Your Checkout Progress</h3>
    <ol>
        <li>
            <h4 class="complete">Billing Address                  
                <span class="separator">|</span>                  
                <a href="#billing" onclick="checkout.accordion.openSection('opc-billing'); return false;">Change</a>
            </h4>
            <div class="content">
                ... <!-- billing address here -->
            </div>
        </li>
        <li>
            <h4>Shipping Address</h4>
        </li>
        <li>
            <h4>Shipping Method</h4>
        </li>
        <li>
            <h4>Payment Method</h4>
        </li>
    </ol>
</div>

The checkout progress is an ordered list, too. The steps that are not yet passed contain only <h4> title. In the other steps there is a class="complete" added to <h4> so we can make the titles of previous steps look different then the titles of next steps.

Those are the basis of the Magento checkout page structure. Understanding and remembering that strucutre can be very helpful during custom Magento shop development.

Prototype and jQuery in Magento

As we know, the Prototype JavaScript framework is included in standard magento installation. Together with script.aculo.us it is a powerful tool for programming client-side actions and effects. It also provides Ajax framework which makes any ajax requests easier then ever before. A lot of magento templates deploy Prototype functionality, e.g. to show/hide elements depending on user's choice or to display error messages with a nice 'fade' effect.

But Prototype is not the only JavaScript library to offer such an useful set of functions. One of other most popular libraries is jQuery – very lightweight (19KB minified and compressed version), simple to use and, to tell the truth, my favourite one. Created in 2006, now it has a large community and hudge set of plugins.

However, is it generally a good idea to use both libraries in one site magento? In my opinion: no, it isn't. At least in most cases. Why? There are a few main reasons:

  • They provide similar functionality so what you achieved by one of them, you can achieve by the other
  • More libraries included mean more data to download by a web browser and slower loading of page
  • They use some common structures, which may lead to conflicts

In some cases, though, you may be forced to include jQuery in your magento shop. For example, you need to use an additional JavaScript library which is created as a jQuery plugin. So how can you force Prototype and jQuery to work together without conflicts?

At first you have to download the recent jquery version (the current release is v.1.3.2) and put it in /js/jquery folder. Then you have to include it in all magento pages – the most logical way is to put the following piece of code in <block type="page/html_head"> section of /app/design/frontend/.../.../layout/page.xml:

<action method="addJs"><script>jquery/jquery-1.3.2.min.js</script></action>

Now you have to avoid conflicts with Prototype framework – they both use $ notation (in jQuery it is a shortcut for jQuery and in Prototype it is an alias for getElementById function). Fortunately, there is a mechanism in jQuery to override the $ function: jQuery.noConflict(). You can put such a construction at the end of your jquery-1.3.2.min.js file:

var $j = jQuery.noConflict();

and from now you have to use $j instead of $ function (or, if you want, you can still use jQuery). So be careful to change all instances of $ in your jquery plugins (but there are many plugins which have jQuery.noConflict() already implemented).

And it would be all, if there wasn't one web browser which still would have problems with coexisting Prototype and jQuery. And, surprisingly, it is not Internet Explorer ;) It is Firefox 2. It throws errors and refuses to execute the JavaScript. Of course currently there are newer versions of Firefox and the problem doesn't exist there, but there is still a little percent of net surfers who use Firefox 2 and they want to spend money in your shop, too;)

Fortunately there is an easy way to solve this problem. You have to include jQuery file before including Prototype. So you have to do the following in page.xml:

<action method="addJs"><script>jquery/jquery-1.3.2.min.js</script></action>
<action method="addJs"><script>prototype/prototype.js</script></action>

And now you can forget about the conflicts and enjoy those two magnificent libraries working together.

Understanding Magento Default Templates

Magento template system allows you to easily create custom html/css code according to design requirements. However, in some cases it would be a good idea to use some of the default magento templates. It may save some time spent on integrating new html structure with magento functionality.

For example, let's take a look at this location in standard magento structure: app\design\frontend\default\default\template\page. Here we have templates describing a basic structure of a page: 1column.phtml, 2colums-left.phtml, 2colums-right.phtml or 3colums.phtml. They all contain the same structure of the page (let's focus on the inside of 'body' section):

<div class="wrapper">

<!-- start header -->
        <div class="header">
            ...
        </div>
<!-- end header -->

<!-- start middle -->
        <div class="middle-container">
            ...
        </div>
<!-- end middle -->

<!-- start footer -->
        <div class="footer-container">
                <div class="footer">
                    ...
                </div>
        </div>
<!-- end footer -->

</div>

They differ only in part inside <div class=”middle-container”>, where a html code for specified layout is defined. As you can see, they present the most common way of building the pages – header, middle part, footer. So in most cases you can use those templates without any change in html and create only your own skin css, which will adapt the look of your page to your needs.

Of course, the more detailed a template is, the less chance that it can be used without change, but you can still start working on a default magento template and just modify the parts you need.