Background
Find solution
First we thought about Ajax, the most popular technology to retrieve data from server asynchronously. But before Magento can make use Ajax for filtering, we first have to write a new controller and actions at the backend to wrap the product data, then we need write additional Javascript to parse server data and format the page at frontend, at a minimum we would need change Magento’s existing filter form to wrap form data and send Ajax request, this effort would not be small.
Then we switched our approach to iFrame, the traditional way to make page async. With a quick analysis, we thought the iframe approach should be doable, the general idea was to warp the product list view in an empty layout and embed it in iframe, and use this iframe to replace existing product list block during filtering. Let’s get started!
The implementation
1. Add an iframe element in page template after the content div. The product list view with empty layout will be embedded in this iframe:
<div class=”middle col-2-left-layout”> <?php echo $this->getChildHtml(‘breadcrumbs’) ?> <!– start left –> <div class=”col-left side-col”> ……………….. <!– start content –> <?php echo $this->getChildHtml(‘content’) ?> <!– end content –> </div> <iframe id=”categroyIframe” name=”categroyIframe” src=”/favicon.ico” scrolling=”no” frameborder=”0″></iframe> </div> |
2. Add a new template file for the iframe-mode product list (catalog/category/iframe.phtml), which is similar to existing one (catalog/category/view.phtml). Adding the following Javascript to hide original product list block and adjust the iframe size when page size inside iframe changes:
window.onload = function() { var wrapper = window.parent.document.getElementById(‘main’); var categoryIframe = window.parent.document.getElementById(‘categroyIframe’);
Element.setStyle(wrapper, {display : ‘none’}); |
3. Usually we need add a new handle in layout.xml for new action and controller, but here we would reuse the default handle for category view action (catalog_category_layered), just override the layout in new added action directly, see below.
4. Add a new controller extends Mage_Catalog_CategoryController, rewrite viewAction by copying existing action, change the following section to override layout:
if ($category->getPageLayout()) { $this->getLayout()->helper(‘page/layout’) ->applyTemplate($category->getPageLayout()); } if ($root = $this->getLayout()->getBlock(‘root’)) { $root->addBodyClass(‘categorypath-’.$category->getUrlPath()) ->addBodyClass(‘category-’.$category->getUrlKey()); } |
change to:
if ($root = $this->getLayout()->getBlock(‘root’)) { $root->addBodyClass(‘categorypath-’.$category->getUrlPath()) ->addBodyClass(‘category-’.$category->getUrlKey()); } If($categoryViewBlock=$this->getLayout()->getBlock(‘category.products’)) { $categoryViewBlock->setTemplate(‘catalog/category/iframe.phtml’); } |
5. Change ActionAttribute of filter_form in catalog/layer/filter.phtml, to submit the search request to new action and target the page response to iframe:
<li> <a href=”<?php echo $this->urlEscape($_item->getUrl()) ?>”><?php echo $_item->getLabel() ?></a> (<?php echo $_item->getCount() ?>) </li> |
change to:
<li>
<?php $url = $this->getBaseUrl() . ‘JB_catalog/product/view/id/’ . $this->helper(‘catalog’)->getCategory()->getId(); $itemUrl = $_item->getUrl(); $params = explode(‘?’, $_item->getUrl()); $param = $params[count($params)-1]; $url = $url . ‘?’ . $param; ?> <a href=”<?php echo $this->urlEscape($url) ?>” target=”categroyIframe”> <?php echo $_item->getLabel() ?></a> (<?php echo $_item->getCount() ?>) </li> |
6. We are done! Try category page now and enjoy a much quicker filtering experience. Cheers!