Magento 1.8 – Fix Sort by Yes/No Attribute Not Working

magento-1.8sorting

I am trying to sort the product listing by one attribute "best_seller". Attribute type is Yes/No , Now i need to sort product by the best_seller and need to show the best seller products set as Yes to appear first on the list. I already set this attribute to use for sorting from attribute settings.

I come to know that there is some issue with sorting when the attribute type is "Yes/No".
Can you anyone help me to fix this issue and or let me know if i am doing anything wrong?

Thanks

Best Answer

Short answer: The sorting doesn't work for Yes/No attributes.

Long Answer:
The problem:

When calling addAttributeToSort on a product collection, if the attribute has a source model then Magento calls addValueSortToCollection from that source model to sort the products.
The Yes/No attributes use the source model Mage_Eav_Model_Entity_Attribute_Source_Boolean that does not implement the method addValueSortToCollection For this model the method just returns $this without processing the collection.

A possible solution:
You can rewrite the Mage_Eav_Model_Entity_Attribute_Source_Boolean and add your addValueSortToCollection method. It should basically be the same code as it is in the class Mage_Catalog_Model_Product_Visibility or Mage_Catalog_Model_Product_Status (not entirely sure about this) which is:

public function addValueSortToCollection($collection, $dir = 'asc')
{
    $attributeCode  = $this->getAttribute()->getAttributeCode();
    $attributeId    = $this->getAttribute()->getId();
    $attributeTable = $this->getAttribute()->getBackend()->getTable();

    if ($this->getAttribute()->isScopeGlobal()) {
        $tableName = $attributeCode . '_t';
        $collection->getSelect()
            ->joinLeft(
                array($tableName => $attributeTable),
                "e.entity_id={$tableName}.entity_id"
                    . " AND {$tableName}.attribute_id='{$attributeId}'"
                    . " AND {$tableName}.store_id='0'",
                array());
        $valueExpr = $tableName . '.value';
    }
    else {
        $valueTable1 = $attributeCode . '_t1';
        $valueTable2 = $attributeCode . '_t2';
        $collection->getSelect()
            ->joinLeft(
                array($valueTable1 => $attributeTable),
                "e.entity_id={$valueTable1}.entity_id"
                    . " AND {$valueTable1}.attribute_id='{$attributeId}'"
                    . " AND {$valueTable1}.store_id='0'",
                array())
            ->joinLeft(
                array($valueTable2 => $attributeTable),
                "e.entity_id={$valueTable2}.entity_id"
                    . " AND {$valueTable2}.attribute_id='{$attributeId}'"
                    . " AND {$valueTable2}.store_id='{$collection->getStoreId()}'",
                array()
            );
            $valueExpr = $collection->getConnection()->getCheckSql(
                $valueTable2 . '.value_id > 0',
                $valueTable2 . '.value',
                $valueTable1 . '.value'
            );
    }

    $collection->getSelect()->order($valueExpr . ' ' . $dir);
    return $this;
}

Explanation provided here also for a similar issue