
If you browse around Magento Connect you’ll quickly find dozens of Quick View extensions, which make it easier for your customers to quickly glance at a product while viewing the catalog and search pages. Quick View popups typically show some brief details about the selected product and an order form, but you can make them as simple or advanced as you want.
You can always buy an extension, but you’ll end up having to customize it for your store’s design anyway. Our premium Magento theme Avalanche comes with a Quick View popup right out of the box and it’s custom designed for the theme. I recommend purchasing a theme that comes with Quick View or learning how to build your own from scratch. In this tutorial, we’ll walk through all the steps it takes to build a popup with jQuery and create the necessary template files.
In order to build a Quick View popup for Magento, we need to do the following:
- Create an AJAX product controller.
- Update our frontend layout (local.xml) to populate the Quick View popup with data.
- Create the structural block template for <catalog_ajax_product_view>.
- Create the Quick View block template.
- Add a link to our product listings/catalog page to trigger the popup.
- Install jQuery and a jQuery Lightbox to display the Quick View. Use CSS to style the popup.
Create the AJAX Product Controller
The first thing we need to do is create an empty controller to receive AJAX requests that inherit the existing Mage_Catalog_ProductController methods. This way we can use the same controller actions used on the product page. Create an “Ajax” folder and ProductController.php file based on the path listed below:
/app/code/core/Mage/Catalog/controllers/Ajax/ProductController.php
1 2 3 4 5 6 | <?php require_once('app/code/core/Mage/Catalog/controllers/ProductController.php'); class Mage_Catalog_Ajax_ProductController extends Mage_Catalog_ProductController { } |
Update Your Magento Theme’s Local.xml
Now that we have our AJAX product controller set up we need to make it appear in the frontend. Edit your theme’s local.xml file inside /layout. If you don’t have a local.xml yet, 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 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 | <?xml version="1.0"?> <layout version="0.1.0"> <catalog_ajax_product_view> <reference name="root"> <action method="setTemplate"><template>page/quickview.phtml</template></action> </reference> <reference name="head"> <action method="addJs"><script>varien/product.js</script></action> <action method="addJs"><script>varien/configurable.js</script></action> </reference> <reference name="content"> <block type="catalog/product_view" name="product.info" template="catalog/ajax/product/view.phtml"> <!-- Media: To use, create new template with code located at bottom of blog post --> <!--<block type="catalog/product_view_media" name="product.info.media" as="media" template="catalog/product/view/media-quickview.phtml"/>--> <block type="core/text_list" name="alert.urls" as="alert_urls" translate="label"> <label>Alert Urls</label> </block> <action method="setTierPriceTemplate"><template>catalog/product/view/tierprices.phtml</template></action> <block type="core/text_list" name="product.info.extrahint" as="extrahint" translate="label"> <label>Product View Extra Hint</label> </block> <block type="catalog/product_view" name="product.info.options.wrapper" as="product_options_wrapper" template="catalog/product/view/options/wrapper.phtml" translate="label"> <label>Info Column Options Wrapper</label> <block type="core/template" name="options_js" template="catalog/product/view/options/js.phtml"/> <block type="catalog/product_view_options" name="product.info.options" as="product_options" template="catalog/product/view/options.phtml"> <action method="addOptionRenderer"><type>text</type><block>catalog/product_view_options_type_text</block><template>catalog/product/view/options/type/text.phtml</template></action> <action method="addOptionRenderer"><type>file</type><block>catalog/product_view_options_type_file</block><template>catalog/product/view/options/type/file.phtml</template></action> <action method="addOptionRenderer"><type>select</type><block>catalog/product_view_options_type_select</block><template>catalog/product/view/options/type/select.phtml</template></action> <action method="addOptionRenderer"><type>date</type><block>catalog/product_view_options_type_date</block><template>catalog/product/view/options/type/date.phtml</template></action> </block> <block type="core/html_calendar" name="html_calendar" as="html_calendar" template="page/js/calendar.phtml"/> </block> <block type="catalog/product_view" name="product.info.options.wrapper.bottom" as="product_options_wrapper_bottom" template="catalog/product/view/options/wrapper/bottom.phtml" translate="label"> <label>Bottom Block Options Wrapper</label> <action method="insert"><block>product.tierprices</block></action> <block type="catalog/product_view" name="product.clone_prices" as="prices" template="catalog/product/view/price_clone.phtml"/> <action method="append"><block>product.info.addtocart</block></action> <action method="append"><block>product.info.addto</block></action> </block> <block type="core/template_facade" name="product.info.container1" as="container1"> <action method="setDataByKey"><key>alias_in_layout</key><value>container1</value></action> <action method="setDataByKeyFromRegistry"><key>options_container</key><key_in_registry>product</key_in_registry></action> <action method="append"><block>product.info.options.wrapper</block></action> <action method="append"><block>product.info.options.wrapper.bottom</block></action> </block> <block type="core/template_facade" name="product.info.container2" as="container2"> <action method="setDataByKey"><key>alias_in_layout</key><value>container2</value></action> <action method="setDataByKeyFromRegistry"><key>options_container</key><key_in_registry>product</key_in_registry></action> <action method="append"><block>product.info.options.wrapper</block></action> <action method="append"><block>product.info.options.wrapper.bottom</block></action> </block> <action method="unsetCallChild"><child>container1</child><call>ifEquals</call><if>0</if><key>alias_in_layout</key><key>options_container</key></action> <action method="unsetCallChild"><child>container2</child><call>ifEquals</call><if>0</if><key>alias_in_layout</key><key>options_container</key></action> <!-- Rating (Use Black BG) --> <action method="addReviewSummaryTemplate"><type>default</type><template>review/helper/fd_summary-black.phtml</template></action> <!-- Add to Cart --> <block type="catalog/product_view" name="product.info.addtocart" as="addtocart" template="catalog/product/view/addtocart.phtml"/> <!-- Additional Data --> <block type="catalog/product_view_additional" name="product.info.additional" as="product_additional_data" /> </block> </reference> </catalog_ajax_product_view> </layout> |
Create the Structural Block
Catalog_Ajax_Product_View includes the same blocks used on the product page. The next thing we need to do is create the structural block that will render all of the blocks in <reference name="content">. Our structural block is set via the following XML in local.xml:
<reference name="root">
<action method="setTemplate"><template>page/quickview.phtml</template></action>
</reference>
And here’s the structural block code:
/app/design/frontend/YOUR_THEME/template/page/quickview.phtml
1 | <?php echo $this->getChildHtml('content'); ?> |
This will render all of the content blocks in the Quick View popup, including catalog/ajax/product/view.phtml.
Create the Quick View Block
Here’s a barebones template for your Quick View popup. It includes a variety of product data using the content blocks from local.xml. Feel free to add extra markup and modify as you see fit:
/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 56 57 58 59 60 61 62 63 64 65 66 67 | <?php $_helper = $this->helper('catalog/output'); $_product = $this->getProduct(); ?> <script type="text/javascript"> var optionsPrice = new Product.OptionsPrice(<?php echo $this->getJsonConfig() ?>); </script> <div class="quick-view"> <?php echo $this->getChildHtml('media') ?> <a href="<?php echo $_product->getProductUrl() ?>"><?php echo $this->__('View Full Details') ?></a> <?php echo $this->getReviewsSummaryHtml($_product) ?> <h1><?php echo $_helper->productAttribute($_product, $_product->getName(), 'name') ?></h1> <?php echo $this->getPriceHtml($_product) ?> <?php if(!$_product->isSaleable()): ?> <div id="availability"><?php echo $this->__('Out Of Stock') ?></div> <?php endif; ?> <?php echo $this->getChildHtml('alert_urls') ?> <div class="product-type-data"> <?php echo $this->getChildHtml('product_type_data') ?> </div> <?php echo $this->getTierPriceHtml() ?> <?php echo $this->getChildHtml('extrahint') ?> <?php echo $this->getChildHtml('other') ?> <form action="<?php echo $this->getSubmitUrl($_product) ?>" method="post" id="order-form" <?php if($_product->getOptions()): ?>enctype="multipart/form-data"<?php endif; ?>> <?php if($_product->isSaleable()): ?> <?php if($this->hasOptions()): ?> <?php echo $this->getChildChildHtml('container1', '', true, true) ?> <?php echo $this->getChildChildHtml('container2', '', true, true) ?> <?php endif; ?> <?php echo $this->getChildHtml('addtocart') ?> <?php endif; ?> </form> </div> <script type="text/javascript"> 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; this.form.action = oldUrl; form.submit(); if (e) { throw e; } if (button && button != 'undefined') { button.disabled = true; } return false; } }.bind(productAddToCartForm); </script> |
Show Quick View Links in Catalog
Now that we have a way to render the Quick View popup, we need to create a link or button that allows the customer to toggle the Quick View when browsing products. Add the following HTML to your catalog list template:
Add to /app/design/frontend/YOUR_THEME/template/catalog/product/list.phtml. Add it twice for list and grid mode, e.g. under lines 78 and 115.
1 | <a href="#" class="quick-view-link" data-url="<?php echo Mage::getBaseUrl(), 'catalog/ajax_product/view/id/', $_product->getId() ?>/"><?php echo $this->__('Quick View') ?></a> |
Each product shown in your catalog listings will have a Quick View link. We’re going to write an AJAX call to our new AJAX product controller (catalog/ajax_product) to get the product’s data and render the popup. The URL is pulled from the link’s “data-url” attribute.
Write the JavaScript
In order to tie everything together we need to handle the onclick event for each Quick View link. Upon clicking the link we need to make an AJAX request, get the returned template HTML, and then show that HTML in a lightbox popup. For this example we’ll be using jQuery and Lightbox_Me.
You’ll need to include a copy of jQuery and Lightbox_Me in your local.xml file. I also included some JavaScript files used on the product details page to show the configurable product options in the Quick View. I included it in the default layout handle so your Quick Views will work anywhere. If you’d like you can limit it to catalog_category_default, catalog_category_layered and catalogsearch_result_index.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?xml version="1.0"?> <layout> <default> <reference name="head"> <action method="addJs"><script>my_theme/jquery-1.6.4.js</script></action> <action method="addJs"><script>my_theme/jquery.lightbox_me.js</script></action> <!-- Add these files to show configurable product options in the Quick View --> <action method="addJs"><script>varien/product.js</script></action> <action method="addJs"><script>varien/configurable.js</script></action> <action method="addJs"><script>calendar/calendar.js</script></action> <action method="addJs"><script>calendar/calendar-setup.js</script></action> <action method="addItem"><type>skin_js</type><name>js/bundle.js</name></action> </reference> </default> </layout> |
These files are expected in /js/my_theme. If you’ve never used jQuery with Magento before, make sure you add this line to the bottom of your jQuery file:
var $jQ = jQuery.noConflict();
This moves jQuery over to a new namespace, $jQ, and avoids using $ since it’s reserved by Prototype. Now we can write our event handler for the quick view links:
/app/design/frontend/YOUR_THEME/template/catalog/product/list.phtml under line 128
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 | <script type="text/javascript"> $jQ('.quick-view-link').one('click', function(e) { showQuickView(this, e); $jQ(this).click(function() { return false; }); e.preventDefault(); }); function showQuickView(link, e) { var quickUrl = $jQ(link).data('url'); $jQ.get(quickUrl, function(data) { $jQ('body').append(data); $jQ('.quick-view').lightbox_me({ centered: true, destroyOnClose: true, overlaySpeed: 10, onClose: function() { $jQ(link).one('click', function(e) { showQuickView(link, e); $jQ(this).click(function() { return false; }); }); } }); }); } </script> |
Upon clicking a quick review link, we append the HTML to the catalog page and call lightbox_me(). Finally, we can style the lightbox. Edit your theme’s CSS:
1 2 | /* Quick View */ .quick-view { display: none; width: 780px; padding: 20px; background: #fff; border: 4px solid #000; } |
Update 10/17 – Create A Quick View Media Template
If you’d like to include product photos in your Quick View, refer to the code below (thanks for the reminder Mick):
/app/design/frontend/YOUR_THEME/template/catalog/product/view/media-quickview.phtml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?php $_product = $this->getProduct(); $_helper = $this->helper('catalog/output'); ?> <div id="quickview-image-browser"> <div id="product-image"> <?php if ($_product->getImage() != 'no_selection' && $_product->getImage()): ?> <?php $_img = '<img src="'.$this->helper('catalog/image')->init($_product, 'image').'" alt="'.$this->htmlEscape($this->getImageLabel()).'" title="'.$this->htmlEscape($this->getImageLabel()).'" width="300" height="300" />'; echo $_helper->productAttribute($_product, $_img, 'image'); ?> <?php else: ?> <?php $_img = '<img src="'.$this->helper('catalog/image')->init($_product, 'image')->resize(300).'" alt="'.$this->htmlEscape($this->getImageLabel()).'" title="'.$this->htmlEscape($this->getImageLabel()).'" width="300" height="300" />'; echo $_helper->productAttribute($_product, $_img, 'image'); ?> <?php endif; ?> </div> </div> |

