Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Extending Magento Layered Navigation


Published on

Sometimes it’s useful to create categories to access directly to groups of products, classified according to specific characteristics.
In my talk I will show you how to extend Magento layered navigation to use category branches such as filters avoiding to replicate the same classification through specific product attributes.

Published in: Software
  • Be the first to comment

Extending Magento Layered Navigation

  1. 1. EXTENDING MAGENTO LAYERED NAVIGATION MAGE TITANS ITALIA - MILAN, FEBRUARY 5TH 2016 Nadia Sala Extending Magento layered navigation by Nadia Sala
  3. 3. THE STORY "Once upon a time there was an e-commerce website that exposed a catalog with many descriptive information."
  4. 4. You can imagine a fashion catalog, so you mind about: Product type, Occasion, Color, Gender, Designer, Price, Size, ...and more
  5. 5. SCENARIO Some information is useful for browsing catalog Some information is useful for filtering catalog Some information is useful for both
  6. 6. COMMON APPROACH Some information is useful for browsing catalog I can create  categories and include them in the navigation menu
  7. 7. COMMON APPROACH Some information is useful for filtering catalog I can configure some attributes to be used as filters in layered navigation
  8. 8. COMMON APPROACH Some information is useful for both I have to create attributes in addition to categories and duplicate the same data
  9. 9. DRAWBACKS I have to keep attribute options in sync with category children I have to maintain proper correspondence between product attribute values and category assignment Filter redundancy
  10. 10. THE SOLUTION Extending Magento layered navigation to use category branches such as filters!
  11. 11. LET'S CODE ! Create custom module Add system configuration Create new catalog layer filter block Create new catalog layer filter model Extend catalog layer view block Define module layout update
  12. 12. ADD SYSTEM CONFIGURATION <!--?xml version="1.0"?--> <config> <tabs> <bitbulltab translate="label" module="bitbull_categorylayered"> <label>BITBULL</label> <sort_order>999</sort_order> </bitbulltab> </tabs> <sections> <bitbull_categorylayered translate="label" module="bitbull_categorylayered"> <label>Category Layered Navigation</label> <tab>bitbulltab</tab> <frontend_type>text</frontend_type> <sort_order>100</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>1</show_in_store> <groups> <configuration translate="label" module="bitbull_categorylayered"> <label>Configuration</label> <sort_order>10</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>1</show_in_store> <fields> <categories translate="label"> <label>Category List</label> <comment>List of categories to use in layered navigation</comment> <frontend_model>bitbull_categorylayered/config_categories</frontend_model> <backend_model>adminhtml/system_config_backend_serialized_array</backend_model> <sort_order>20</sort_order> <show_in_default>1</show_in_default>
  13. 13. EXTEND MAGE_CATALOG_BLOCK_LAYER_VIEW / 1 Child blocks initialization, one for each configured category class Bitbull_CategoryLayered_Block_Catalog_Layer_View extends Mage_Catalog_Block_Layer_View{ /** * Prepare child blocks * @return Mage_Catalog_Block_Layer_View */ protected function _prepareLayout() { /** @var Mage_Catalog_Model_Category $current_category */ $current_category = Mage::helper('catalog')->getCategory(); foreach ($this->_layeredCategories as $layeredCatConfig) { $categoryId = $layeredCatConfig['category']; // check if current category navigation is in path of categorylayered if ($current_category->getId() && in_array($categoryId, $current_category->getPathIds())) { continue; } // create categoryLayered filter block $blockAttributes = array( 'categoryId' => $layeredCatConfig['category'], 'requestParam' => $layeredCatConfig['filter'] ); $blockName = 'categorylayered_'.$categoryId; $categoryBlock = $this->getLayout() ->createBlock($this->_categoryLayeredBlockName, $blockName, $blockAttributes) ->setLayer($this->getLayer())
  14. 14. EXTEND MAGE_CATALOG_BLOCK_LAYER_VIEW / 2 For each configured category, add block to filters list managing position class Bitbull_CategoryLayered_Block_Catalog_Layer_View extends Mage_Catalog_Block_Layer_View { /** * Get all layer filters * @return array */ public function getFilters() { $filters = parent::getFilters(); foreach ($this->_layeredCategories as $layeredCatConfig) { $categoryId = $layeredCatConfig['category']; $position = $layeredCatConfig['position']; if (($categoryFilter = $this->_getLayeredCategoryFilter($categoryId))) { $filters = array_merge( array_slice( $filters, 0, $position ), array($categoryFilter), array_slice( $filters, $position, count($filters) ) ); }
  15. 15. CREATE NEW CATALOG LAYER FILTER MODEL / 1 Retrieve subcategories as filter items. class Bitbull_CategoryLayered_Model_Catalog_Layer_Filter_CategoryLayered extends Mage_Catalog_Model_Layer_Filter_Abstract { /** * Get data array for building filter items * @return array */ protected function _getItemsData() { $key = $this->getLayer()->getStateKey().'_'.$this->_requestVar; $data = $this->getLayer()->getAggregator()->getCacheData($key); if ($data === null) { // load children for root category or current selected category for this filter $categories = $this->_appliedCategory instanceof Mage_Catalog_Model_Category ? $this->_appliedCategory->getChildrenCategories() : $this->_rootCategory->getChildrenCategories(); $this->getLayer()->getProductCollection() ->addCountToCategories($categories); $data = array(); foreach ($categories as $category) { /** @var $category Mage_Catalog_Model_Categeory */ if ($category->getIsActive() && $category->getProductCount()) { $data[] = array( 'label' => Mage::helper('core')->escapeHtml($category->getName()), 'value' => $category->getId(), 'count' => $category->getProductCount(),
  16. 16. CREATE NEW CATALOG LAYER FILTER MODEL / 2 Apply filter logic adding a join on catalog/category_product_index table class Bitbull_CategoryLayered_Model_Catalog_Layer_Filter_CategoryLayered extends Mage_Catalog_Model_Layer_Filter_Abstract /** * Apply category filter to layer * @param Zend_Controller_Request_Abstract $request * @param Mage_Core_Block_Abstract $filterBlock * @return Bitbull_CategoryLayered_Model_Catalog_Layer_Filter_CategoryLayered */ public function apply(Zend_Controller_Request_Abstract $request, $filterBlock) { $filter = (int) $request->getParam($this->getRequestVar()); if (!$filter) { return $this; } // load data for applied category $this->_appliedCategory = Mage::getModel('catalog/category') ->setStoreId(Mage::app()->getStore()->getId()) ->load($filter); if ($this->_appliedCategory->getId()) { // create join and conditions for additional category filter $tableAlias = 'category_layered_'.$this->_rootCategory->getId(); $conditions = array(); $conditions['category_id'] = $filter; $conditions['store_id'] = Mage::app()->getStore()->getId(); if (!$this->_appliedCategory->getIsAnchor()) { $conditions['is_parent'] = 1;
  17. 17.      Frontend Demo Backend Demo
  18. 18. CONCLUSION By extending Magento layered navigation as shown we can: avoid data replication and maintenance filter deeply until selected category has subcategories avoid filter redundancy Without touching the core
  19. 19. THANK YOU ! NAMASTÉ ANY QUESTION ? @nadiasala