Anuj Sharma
Anuj Sharma

Reputation: 55

Magento Custom Sort Option

How do I add custom sort option in Magento. I want to add Best Sellers, Top rated and exclusive in addition to sort by Price. Please help

Upvotes: 4

Views: 7663

Answers (3)

Digisha
Digisha

Reputation: 365

To sort out pagination issue for custom sorting collection rewrite the resource model of it's collection from

 app\code\core\Mage\Catalog\Model\Resource\Product\Collection.php 
And modify below method from core
     protected function _getSelectCountSql($select = null, $resetLeftJoins = true)
     {
        $this->_renderFilters();
        $countSelect = (is_null($select)) ?
        $this->_getClearSelect() :
        $this->_buildClearSelect($select);

    /*Added to reset count filters for Group*/ 
    if(count($countSelect->getPart(Zend_Db_Select::GROUP)) > 0) {
     $countSelect->reset(Zend_Db_Select::GROUP);
    }
    /*Added to reset count filters for Group*/  

    $countSelect->columns('COUNT(DISTINCT e.entity_id)');
    if ($resetLeftJoins) {
      $countSelect->resetJoinLeft();
    }
    return $countSelect;
   }

Above will solve count issue for custom sorting collection.

Upvotes: 0

Qin Wang
Qin Wang

Reputation: 422

Thanks for your answer, Anuj, that was the best working module I could find so far.

Just add an extra bit to your code in order to solve no pagination caused by 'group by'

Copy '/lib/varien/data/collection/Db.php' To 'local/varien/data/collection/Db.php'.

Change the getSize function to

public function getSize()
{

    if (is_null($this->_totalRecords)) {
        $sql = $this->getSelectCountSql();
        //$this->_totalRecords = $this->getConnection()->fetchOne($sql, $this->_bindParams); //============================>change behave of fetchOne to fetchAll

        //got array of all COUNT(DISTINCT e.entity_id), then sum 
        $result = $this->getConnection()->fetchAll($sql, $this->_bindParams);

        foreach ($result as $row) {//echo'<pre>'; print_r($row);
            $this->_totalRecords += reset($row);
        }

    }
    return intval($this->_totalRecords);
}

Hope it could help anyone.


update The filter section need to be updated as well, otherwise just showing 1 item on all filter. and the price filter will not be accurate.

What you need to do it to modify core/mage/catalog/model/layer/filter/attribute.php and price.php

attribute.php getCount() on bottom

 $countArr = array();
    //print_r($connection->fetchall($select));
    foreach ($connection->fetchall($select) as $single)
    {  

        if (isset($countArr[$single['value']]))
        {
            $countArr[$single['value']] += $single['count'];
        }
        else
        {
             $countArr[$single['value']] = $single['count'];
        }


    }
    //print_r($countArr);//exit;
    return $countArr;
    //return $connection->fetchPairs($select);

Price.php getMaxPrice

$maxPrice = 0;
    foreach ($connection->fetchall($select) as $value)
    {
        if (reset($value) > $maxPrice)
        {
            $maxPrice = reset($value);
        }

    }
    return $maxPrice;

If you are having the same problem and looking for the question, you will know what I meant. Good luck, spent 8 hours on that best sell function.


Update again,

just found another method to implement using cron to collect best sale data daily saved in a table that includes product_id and calculated base sale figure. then simply left join, without applying 'group by' that means core functions do not need to changed and speed up the whole sorting process. Finally finished! hehe.

Upvotes: 1

liyakat
liyakat

Reputation: 11853

For Best Sellers

haneged in code/local/Mage/Catalog/Block/Product/List/Toolbar.php method setCollection to

public function setCollection($collection) {
    parent::setCollection($collection);
    if ($this->getCurrentOrder()) {
        if($this->getCurrentOrder() == 'saleability') {
            $this->getCollection()->getSelect()
                 ->joinLeft('sales_flat_order_item AS sfoi', 'e.entity_id = sfoi.product_id', 'SUM(sfoi.qty_ordered) AS ordered_qty')
                 ->group('e.entity_id')->order('ordered_qty' . $this->getCurrentDirectionReverse());
        } else {
            $this->getCollection()
                 ->setOrder($this->getCurrentOrder(), $this->getCurrentDirection());
        }
    }

    return $this;
}

After setCollection I added this method:

public function getCurrentDirectionReverse() {
    if ($this->getCurrentDirection() == 'asc') {
        return 'desc';
    } elseif ($this->getCurrentDirection() == 'desc') {
        return 'asc';
    } else {
        return $this->getCurrentDirection();
    }
}

And finally I changed mehod setDefaultOrder to

public function setDefaultOrder($field) {
    if (isset($this->_availableOrder[$field])) {
        $this->_availableOrder = array(
            'name'        => $this->__('Name'),
            'price'       => $this->__('Price'),
            'position'    => $this->__('Position'),
            'saleability' => $this->__('Saleability'),
        );
        $this->_orderField = $field;
    }

    return $this;
}

for Top rated

http://www.fontis.com.au/blog/magento/sort-products-rating

try above code.

for date added

Magento - Sort by Date Added

i am not associate with any of the above link for any work or concern it is just for knowledge purpose and to solve your issue.

hope this will sure help you.

Upvotes: 8

Related Questions