extending magento layered navigation

Post on 08-Feb-2017

596 Views

Category:

Software

2 Downloads

Preview:

Click to see full reader

TRANSCRIPT

EXTENDING MAGENTOLAYERED NAVIGATIONMAGE TITANS ITALIA - MILAN, FEBRUARY 5TH 2016

Nadia Sala

Extending Magento layered navigation by Nadia Sala

ABOUT MEPHP DEVELOPER

MAGENTO BACKEND DEVELOPER

@nadiasala nadia.sala@bitbull.it

THE STORY"Once upon a time there was an e-commerce website that

exposed a catalog with many descriptive information."

You can imagine a fashion catalog, so you mind about:

Product type, Occasion, Color,

Gender, Designer, Price, Size,

...and more

SCENARIOSome information is useful for browsing catalog

Some information is useful for filtering catalog

Some information is useful for both

COMMON APPROACHSome information is useful for browsing catalog

I can create  categories and include them in the navigationmenu

COMMON APPROACHSome information is useful for filtering catalog

I can configure some attributes to be used as filters inlayered navigation

COMMON APPROACHSome information is useful for both

I have to create attributes in addition to categories andduplicate the same data

DRAWBACKSI have to keep attribute options in sync with categorychildrenI have to maintain proper correspondence betweenproduct attribute values and category assignmentFilter redundancy

THE SOLUTIONExtending Magento layered navigation

to use category branches such as filters!

LET'S CODE !Create custom moduleAdd system configurationCreate new catalog layer filterblockCreate new catalog layer filtermodelExtend catalog layer viewblockDefine module layout update

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>

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

EXTEND MAGE_CATALOG_BLOCK_LAYER_VIEW / 2

For each configured category, add block to filters listmanaging 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)

)

);

}

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(),

CREATE NEW CATALOG LAYER FILTER MODEL / 2

Apply filter logic adding a join oncatalog/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;

CONCLUSION By extending Magento layered navigation as shown we can:

avoid data replication and maintenancefilter deeply until selected category has subcategoriesavoid filter redundancy

Without touching the core

THANK YOU !NAMASTÉ

ANY QUESTION ?

@nadiasala nadia.sala@bitbull.it

https://github.com/bitbull-team/magento-module-category-layered

top related