DIY Magento: Create an AJAX Quick Cart for Your Magento Theme

by on November 23, 2011

DIY Magento

One of the hottest extensions for Magento is the AJAX Quick Cart, a useful eCommerce feature that allows customers to quickly add a product to their cart without reloading the page or getting redirected to the checkout. In this tutorial I’m going to show you how to create your own AJAX cart from scratch. To see it in action, check out our premium Magento 1.6 theme.

Note: This tutorial requires the Quick View popup from our previous DIY Magento article – Create a Quick View for Your Magento Theme

In order to build an AJAX Quick Cart for Magento, we need to do the following:

  1. Set up our cart extension and override the checkout cart controller.
  2. Create the cart dropdown template which will show the cart products in a dropdown.
  3. Update our frontend layout (local.xml) to append the cart dropdown block to the store header.
  4. Update header.phtml to append the cart dropdown block to the store header.
  5. Use jQuery to make an AJAX post call after clicking the “Add to Cart” button in the Quick View popup.
  6. Use jQuery to attach a hover event to the header cart link.
  7. Use CSS to style the AJAX cart dropdown.

Create the Extension

The first thing we need to do is set up the folder structure for our extension. Follow the screenshot below and add the folders and files to your /app/code/local directory:

Extension File Structure

Now let’s override the checkout cart controller. We’re going to do 3 things:

  1. Override the index action to load the AJAX cart dropdown only if we make an AJAX request.
  2. Upon saving the cart, we want to redirect to the AJAX cart dropdown when making an AJAX request: _goBack().
  3. Create a new function to return the AJAX cart dropdown block: _sendSideCartHtml().

/app/code/local/FastDivision/QuickCart/controllers/Checkout/CartController.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
<?php
require_once('Mage/Checkout/controllers/CartController.php');
 
class FastDivision_QuickCart_Checkout_CartController extends Mage_Checkout_CartController
{
    /**
    * Shopping cart display action
    */
    public function indexAction()
    {
        $cart = $this->_getCart();
        if ($cart->getQuote()->getItemsCount()) {
            $cart->init();
            $cart->save();
 
            if (!$this->_getQuote()->validateMinimumAmount()) {
                $warning = Mage::getStoreConfig('sales/minimum_order/description');
                $cart->getCheckoutSession()->addNotice($warning);
            }
        }
 
        foreach ($cart->getQuote()->getMessages() as $message) {
            if ($message) {
                $cart->getCheckoutSession()->addMessage($message);
            }
        }
 
        /**
         * if customer enteres shopping cart we should mark quote
         * as modified bc he can has checkout page in another window.
         */
        $this->_getSession()->setCartWasUpdated(true);
 
	// Quick Cart: If AJAX call, then return the cart dropdown HTML
        if ($this->getRequest()->isXmlHttpRequest()) {
            $this->_sendSideCartHtml();
        } else {
            Varien_Profiler::start(__METHOD__ . 'cart_display');
            $this
                ->loadLayout()
                ->_initLayoutMessages('checkout/session')
                ->_initLayoutMessages('catalog/session')
                ->getLayout()->getBlock('head')->setTitle($this->__('Shopping Cart'));
            $this->renderLayout();
            Varien_Profiler::stop(__METHOD__ . 'cart_display');
        }
    }
 
     /**
     * Set back redirect url to response
     *
     * @return Mage_Checkout_CartController
     */
    protected function _goBack()
    {
	// Quick Cart: If AJAX call, then return the cart dropdown HTML
	if ($this->getRequest()->isXmlHttpRequest()) {
		$this->_sendSideCartHtml();
	} else {
	       $returnUrl = $this->getRequest()->getParam('return_url');
	       if ($returnUrl) {
	           // clear layout messages in case of external url redirect
	           if ($this->_isUrlInternal($returnUrl)) {
	               $this->_getSession()->getMessages(true);
	           }
	           $this->getResponse()->setRedirect($returnUrl);
	       } elseif (!Mage::getStoreConfig('checkout/cart/redirect_to_cart')
	           && !$this->getRequest()->getParam('in_cart')
	           && $backUrl = $this->_getRefererUrl()
	       ) {
	           $this->getResponse()->setRedirect($backUrl);
	       } else {
	           if (($this->getRequest()->getActionName() == 'add') && !$this->getRequest()->getParam('in_cart')) {
	               $this->_getSession()->setContinueShoppingUrl($this->_getRefererUrl());
	           }
	           $this->_redirect('checkout/cart');
	       }
	       return $this;
	}
    }
 
    protected function _sendSideCartHtml()
    {
	// Return the Quick Cart's dropdown block
        $this->loadLayout();
        $output = $this->getLayout()->getBlock('quickcart')->toHtml();
        $this->getResponse()->setBody($output);
    }
}

Next we just need to edit the /etc/config.xml file. We’re simply overriding the /checkout frontend route in Magento to hit our controller before accessing the actions inherited from the Mage_Checkout_CartController.

/app/code/local/FastDivision/QuickCart/etc/config.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0"?>
<config>
    <modules>
        <FastDivision_QuickCart>
            <version>0.1.0</version>
        </FastDivision_QuickCart>
    </modules>
    <frontend>
        <routers>
	        <checkout>
			<args>
				<modules>
					<FastDivision_QuickCart before="Mage_Checkout">FastDivision_QuickCart_Checkout</FastDivision_QuickCart>
				</modules>
			</args>
		</checkout>
        </routers>
    </frontend>
</config>

Create the Cart Dropdown Block

The cart dropdown block will show a list of products in the customer’s cart when mousing over the header cart link.

/app/design/frontend/YOUR_THEME/template/checkout/cart/header.phtml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php if ($this->getIsNeedToDisplaySideBar()):?>
<?php $_cartQty = $this->getSummaryCount() ?>
<li class="cart">
   	<a href="<?php echo $this->getUrl('checkout/cart') ?>" class="cart-link"><?php echo $this->__('My Cart') ?> (<?php print (!empty($_cartQty)) ? $_cartQty : '0' ;?>)</a>
	<div class="quickcart">
		<div class="quickcart-container">
	        <?php
				$_items = $this->getRecentItems($_cartQty);
				if(count($_items)):
			?>
				<table>
	                <?php foreach($_items as $_item): ?>
	                    <?php echo $this->getItemHtml($_item) ?>
	                <?php endforeach; ?>
				</table>
				<div class="quickcart-checkout">
					<a href="<?php echo $this->getCheckoutUrl() ?>"><span><?php echo $this->__('Proceed to Checkout') ?></span></a>
				</div>
	         <?php else: ?>
	         	<p class="no-items-in-cart"><?php echo $this->__('You have no items in your shopping cart.') ?></p>
	         <?php endif ?>
		</div>
	</div>
</li>
<?php endif ?>

Update Your Magento Theme’s Local.xml

In order to display the cart dropdown in the header we need to edit the local.xml file for your theme. We’re also going to remove the existing cart link to make way for the new cart link in our block. If you don’t have a local.xml in your theme’s /layout directory, you can learn more about local.xml files here.

/app/design/frontend/YOUR_THEME/layout/local.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0"?>
<layout version="0.1.0">
	<default>
	        <reference name="header">
	                <!-- Quick Cart Dropdown -->
                        <block type="checkout/cart_sidebar" name="quickcart" template="checkout/cart/header.phtml">
			        <action method="addItemRender"><type>simple</type><block>checkout/cart_item_renderer</block><template>checkout/cart/sidebar/default.phtml</template></action>
                                <action method="addItemRender"><type>grouped</type><block>checkout/cart_item_renderer_grouped</block><template>checkout/cart/sidebar/default.phtml</template></action>
                                <action method="addItemRender"><type>configurable</type><block>checkout/cart_item_renderer_configurable</block><template>checkout/cart/sidebar/default.phtml</template></action>
		        </block>
                </reference>
		<reference name="top.links">
			<remove name="checkout_cart_link"/>
		</reference>
	</default>
</layout>

Update Your Magento Theme’s Store Header Template

After adding the cart dropdown block to your local.xml file we’ll need to render it in your theme’s header.phtml template file:

/app/design/frontend/base/YOUR_THEME/template/page/html/header.phtml

1
<?php echo $this->getChildHtml('quickcart') ?>

Add this line directly under <?php echo $this->getChildHtml('topLinks') ?>.

Write an AJAX Post Call Upon Clicking “Add to Cart” in the Quick View

If you followed our Quick View tutorial you should already have jQuery included in your Magento theme. We’re going to edit the Quick View block and add some code to the productAddToCartForm submit event:

/app/design/frontend/YOUR_THEME/template/catalog/ajax/product/view.phtml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
var productAddToCartForm = new VarienForm('order-form');
productAddToCartForm.submit = function(button, url) {
    if (this.validator.validate()) {
        var form = this.form;
        var oldUrl = form.action;
 
        if (url) {
           form.action = url;
        }
        var e = null;
 
        try {
	    $jQ.post('<?php echo $this->helper('checkout/cart')->getAddUrl($_product, array()) ?>', $jQ('#order-form').serialize(), function(data) {
	        // Close quick view
	        $jQ('.quick-view').trigger('close');
 
	        // Update quick cart
	        $jQ('.header .cart').remove();
	        $jQ('.header .links').append(data);
	        initQuickCart();
 
	        // Show quick cart temporarily to customer signifying cart addition
	        $jQ('html, body').animate({ 'scrollTop': $jQ('.header .links').scrollTop() }, 500);
	        $jQ('.header .cart').addClass('cart-active');
	        var showCartToUser = setTimeout(function() {
	            $jQ('.header .cart').removeClass('cart-active');
	        }, 5000);
	    });
        } catch (e) {
	    throw e;
        }
 
        this.form.action = oldUrl;
 
        if (e) {
            throw e;
        }
 
        if (button && button != 'undefined') {
            button.disabled = true;
        }
 
		return false;
    }
}.bind(productAddToCartForm);
 
function initQuickCart() {
	if($jQ('.quickcart').length && !$jQ('.no-items-in-cart').length) {
		$jQ('.cart').unbind().hoverIntent({
			interval: 20,
			over: function() { $jQ(this).addClass('cart-active').find('.quickcart').show(); },
			out: function() { $jQ(this).removeClass('cart-active').find('.quickcart').hide(); }
		});
	}
}

$jQ.post makes an AJAX post to the product add to cart URL. It sends the form parameters from the Quick View order form. The post callback returns the quick cart dropdown block from /checkout/cart/header.phtml. We append the block to our Magento theme’s account menu and display the dropdown for 5 seconds to let the customer know that we added their product to the cart.

Cart Dropdown jQuery Hover Event

Now that we’ve created a way to add products to the cart via AJAX, built the dropdown block, and tied the Quick Cart and Quick View together, we need a way to show the dropdown after mousing over the cart link. I recommend creating a main.js file and making the initQuickCart() function available sitewide:

/js/YOUR_THEME/main.js

1
2
3
4
5
6
7
8
9
10
11
$jQ(document).ready(function() {
    function initQuickCart() {
	if($jQ('.quickcart').length && !$jQ('.no-items-in-cart').length) {
		$jQ('.cart').hoverIntent({
			interval: 20,
			over: function() { $jQ(this).addClass('cart-active').find('.quickcart').show(); },
			out: function() { $jQ(this).removeClass('cart-active').find('.quickcart').hide(); }
		});
	}
    }
});

For the hover event I’m using hoverIntent for jQuery. Add hoverIntent to your Magento theme’s JavaScript directory and then load jquery.hoverIntent.minified.js and main.js in your local.xml file (preferably at the bottom of your “head” reference after loading jQuery):

1
2
3
4
5
6
7
8
9
<?xml version="1.0"?>
<layout>
    <default>
        <reference name="head">
            <action method="addJs"><script>YOUR_THEME/jquery.hoverIntent.minified.js</script></action>
            <action method="addJs"><script>YOUR_THEME/main.js</script></action>
        </reference>
    </default>
</layout>

Style the AJAX Cart Dropdown

The last thing we need to do is style our Quick Cart dropdown with CSS. Add this code to your theme’s stylesheet and revise as you see fit:

1
2
3
4
5
.quickcart { display: none; position: absolute; z-index: 9999; top: 36px; right: 0; padding: 0 0 4px 4px; background: #fff; }
	.cart-active .quickcart { display: block; }
	.quickcart-container { width: 380px; padding: 10px; font-size: 12px; font-weight: normal; text-transform: none; line-height: 1.3em; }
	.quickcart-checkout { margin: 10px 0 0 0; padding: 16px 0 8px 0; }
.quickcart td { margin: 0 6px 0 0; padding: 10px 0 10px 0; color: #333; vertical-align: middle; }

You should now have a working Quick Cart dropdown that allows customers to purchase products via the Quick View popup without going to the product page. If you have any questions or run into issues leave a comment.

  • http://www.developer.web.tr/ Oğuz Çelikdemir

    Thank you so much, I have been looking for a while such a solution.

  • http://fastdivision.com/ Jake Johnson

    You’re welcome! Let me know if you have any questions.

  • Rbloodworth

    Thanks for posting. I am having a issue with getting the drop down (hoverIntent) to fire.The cart is being built and product list added as expected. The “My Cart” is added to the header as expected, just do not have any effect on hover or roll over of the element. Using Magento 1.6.2 Any suggestions?

  • Eirik

    Been trying to get this to work however I am getting a js error

    Error: initQuickCart is not defined
    Source File: http://www.localhost.com/new-jh/js/quickview/jquery-1.6.4.js
    Line: 634

    I worked my way through the instructions 3 times but still encountering the same issue. The files are all loaded, not sure what might be the problem. Does this extension require a config file inside the app/etc/modules?

  • http://fastdivision.com/ Jake Johnson

    Hi Eirik, thanks for your patience. Can you try copying the initQuickCart function over to /app/design/frontend/YOUR_THEME/template/catalog/ajax/product/view.phtml ? Chances are the AJAX Quick View isn’t finding the initQuickCart function. Throw it over there as well and it should fix that problem.

  • http://fastdivision.com/ Jake Johnson

    Hi, sorry for the delay. Do you get any JavaScript errors in your browser? Please report them and I’ll try to assist you further.

  • http://fastdivision.com/ Jake Johnson

    I updated the article to reflect this fix.

  • http://fastdivision.com/2012/03/29/diy-magento-create-ajax-login-registration-forms-for-your-magento-theme/ DIY Magento: Create AJAX Login & Registration Forms for Your Magento Theme — Fast Division

    [...] [...]

  • Me Kremil

    it’s also happen to me……and haven’t any solution yetttt….pufff

  • Me Kremil

    eroor javascript in..whyy…

    jquery.hoverIntent.minified.js

    $jQ is not defined
    return this.bind(‘mouseenter’,handleHover).bind(‘mouseleave’,handleHover)}})(jQuery);

    main.js
    $jQ is not defined
    $jQ(document).ready(function()

    thanks for great article..

  • Me Kremil

    in this case I only one top link cart hoverintent…thanks..

  • Vivek Shingala

    thanks very much…

    helped me…

  • http://fastdivision.com/ Jake Johnson

    Make sure your jQuery has the jQ namespace to prevent conflicts with Prototype (the default JS library used by Magento). Place this line at the bottom of your jQuery file:

    var $jQ = jQuery.noConflict();

    Or you can add it immediately after including jQuery like so:

    var $jQ = jQuery.noConflict();

Previous post:

Next post: