3

I am working on Layered navigation of Magento. I want to implement the following:

  1. Price filter with multiple check boxes.
  2. Kit type with Radio buttons.
  3. Ratings with multiple check boxes.

The same is shown in the below image also.

enter image description here

I have already tried to customize the extension from magento-connect. But no luck. How can implement those multiselect filters.

Can anyone please help me on this. Thanks in advance.

2

One starting point can be this question on stackoverflow: Magento: textbox instead of multi select in layered navigation

Amasty's extension: Improved navigation solves your problem (quite popular extension).

| improve this answer | |
  • Can i get it for free? Because it is very costly. – Sivakumar Dec 19 '13 at 17:14
  • "Free" = you can build it (assuming that your time is free). – FlorinelChis Dec 19 '13 at 17:15
  • Yeah i have time but i need some guidance. – Sivakumar Dec 19 '13 at 17:17
  • Read that first link I gave you... Be willing to allocate some effort, read and study... It's not realistic to expect other to give you code that you can copy-paste and have your module.4 – FlorinelChis Dec 19 '13 at 17:19
1

In one of upcoming projects I have something similar to implement. So spent some time to come up with a quick and dirty solution.

Please note that it's not a proper/complete solution. Core files have been changed along with 3rd party extension files.

Chances are it's not going to make sense in first iteration. But probaly it can reduce the development time.

  • Environment: Magento 1.9

  • Extension Installed: Amasty_Shopby

Pre-requisite: Some knowledge of how Layered navigation works in Magento is required.

Summary of changes:

app/code/core/Mage/Catalog/Model/Layer/Filter/Abstract.php

/**
 * Get all filter items
 *
 * @return array
 */
public function getItems()
{
    if (empty($this->_items)) {
        $this->_initItems();
    }
    return $this->_items;
}

app/code/core/Mage/Catalog/Model/Resource/Layer/Filter/Price.php

A bunch of methods have been added to support multi-filter price behaviour. These methods have been copied from the core class Mage_Catalog_Model_Layer_Filter_Price and it's parent classes. It will take some effort to study the code below and link it together:

    /**
     * Apply price range filter to product collection
     *
     * @param Mage_Catalog_Model_Layer_Filter_Price $filter
     * @return Mage_Catalog_Model_Resource_Layer_Filter_Price
     */
    public function applyPriceRangeMulti($filter)
    {

        $reqParams = Mage::app()->getRequest()->getParam($filter->getRequestVar());
        //validate filter
        $filterParams = array_unique(explode(',', $reqParams));

        $formattedParams = array();
        foreach($filterParams as $param){
            $filterParam = $this->_validatePriceFilter($param);
            if (!$filterParam) {
                return $this;
            }

            list($from, $to) = $filterParam;

            if ($from < 0.01 && $to < 0.01) {
                return $this;
            }

            $formattedParams[] = $filterParam;
        }

        $select = $filter->getLayer()->getProductCollection()->getSelect();
        $priceExpr = $this->_getPriceExpression($filter, $select, false);

        $andClauses = array();
        foreach($formattedParams as $filterParam){
            list($from, $to) = $filterParam;

            /*
             * Workaround for JS
             */
            if ($to == 0) {
               $to = '';
            }

            $filter->setInterval(array($from, $to));

            $index = array_search("{$from}-{$to}",$filterParams);

            $itemValue = $filterParams;

            if (false === $index){
                $itemValue[] = "{$from}-{$to}";
            }else {
                $itemValue[$index]  = null;
                unset($itemValue[$index]);
            }

            $itemValue = implode(',', $itemValue);

            $query = array(
                $filter->getRequestVar() => $itemValue,
                Mage::getBlockSingleton('page/html_pager')->getPageVarName() => null // exclude current page from urls
            );
            $url = Mage::helper('amshopby/url')->getFullUrl($query);

            $text .= $this->_renderRangeLabel($from, $to) . " ";

            $children[] = array(
                'label' => $this->_renderRangeLabel($from, $to),
                'url' => $url,
            );

            if ($to !== '') {
                $to = (float)$to;
                if ($from == $to) {
                    $to += self::MIN_POSSIBLE_PRICE;
                }
            }

            if ($from !== '') {

                //$select->where($priceExpr . ' >= ' . $this->_getComparingValue($from, $filter));

                $fromExpr = new Zend_Db_Expr($priceExpr . ' >= ' . $this->_getComparingValue($from, $filter));
                $andString .= $fromExpr;
            }
            if ($to !== '') {

                //$select->where($priceExpr . ' < ' . $this->_getComparingValue($to, $filter));
                $toExpr = new Zend_Db_Expr($priceExpr . ' < ' . $this->_getComparingValue($to, $filter));

            }

            $andClauses[] =  "{$fromExpr} AND {$toExpr}";
        }

        foreach($andClauses as $andClause){
            $select->orWhere($andClause);
        }

        $state = $this->_createItem($filter, $text, $filterParams)
            ->setVar($filter->getRequestVar());

        if (count($children) > 1) {
            $state->setData('children', $children);
        }

        $filter->getLayer()->getState()->addFilter($state);

        return $this;

    }

    /**
     * Prepare text of range label
     *
     * @param float|string $fromPrice
     * @param float|string $toPrice
     * @return string
     */
    protected function _renderRangeLabel($fromPrice, $toPrice)
    {
        $store      = Mage::app()->getStore();
        $formattedFromPrice  = $store->formatPrice($fromPrice);
        if ($toPrice === '') {
            return Mage::helper('catalog')->__('%s and above', $formattedFromPrice);
        } elseif ($fromPrice == $toPrice && Mage::app()->getStore()->getConfig(self::XML_PATH_ONE_PRICE_INTERVAL)) {
            return $formattedFromPrice;
        } else {
            if ($fromPrice != $toPrice) {
                $toPrice -= .01;
            }
            return Mage::helper('catalog')->__('%s - %s', $formattedFromPrice, $store->formatPrice($toPrice));
        }
    }

    protected function _createItem($filter, $label, $value, $count=0)
    {
        return Mage::getModel('catalog/layer_filter_item')
            ->setFilter($filter)
            ->setLabel($label)
            ->setValue($value)
            ->setCount($count);
    }

    /**
     * Validate and parse filter request param
     *
     * @param string $filter
     * @return array|bool
     */
    protected function _validatePriceFilter($filter)
    {
        $filter = explode('-', $filter);
        if (count($filter) != 2) {
            return false;
        }
        foreach ($filter as $v) {
            if (($v !== '' && $v !== '0' && (float)$v <= 0) || is_infinite((float)$v)) {
                return false;
            }
        }

        return $filter;
    }

app/code/local/Package/SomeExtension/Model/Catalog/Layer/Filter/Price/Price17ce.php

This is an extension specific file that overrided the apply() method from parent class Mage_Catalog_Model_Layer_Filter_Price. In most cases this parent class will require modifications. To explain a bit _applyPriceRange() method has been changed to _applyPriceRangeMulti(). Definition of this method has been pasted above already. Again it's a copy-paste from the _applyPriceRange() for the most part.

protected function _applyPriceRangeMulti()
{
    $this->_getResource()->applyPriceRangeMulti($this);
}

Please put a comment if any one needs any more explanation.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.