Magento : Out of stock products showing last in the category page

magentomagento-1.7

I am using Magento 1.7.0.2 and I have this code line that i am using in /app/code/core/Mage/Catalog/Block/Product/list.php :

$this->_productCollection = $layer->getProductCollection()
                    ->joinField(
                        'inventory_in_stock', 
                        'cataloginventory_stock_item', 
                        'is_in_stock', 
                        'product_id=entity_id',
                        'is_in_stock>=0', 
                        'left')
                    ->setOrder('inventory_in_stock','desc');

When sorting for position and name the out of stock products are last. But when sorting for price, the out of stock products are in a normal order not last.

How can i make that the out of stock products to be last even in the sort after price ?

Best Answer

Great find Alex! A tip: If you want to avoid changing core files (and possibly make this into a module), you can add it to an event listener, like this (tested on 1.8.1.0):

/**
 * Fires before a product collection is loaded
 *
 * @param Varien_Event_Observer $observer
 */
public function catalog_product_collection_load_before($observer)
{
    $collection = $observer->getCollection();
    $collection->getSelect()->joinLeft(
        array('_inventory_table'=>$collection->getTable('cataloginventory/stock_item')),
        "_inventory_table.product_id = e.entity_id",
        array('is_in_stock', 'manage_stock')
    );
    $collection->addExpressionAttributeToSelect(
        'on_top',
        '(CASE WHEN (((_inventory_table.use_config_manage_stock = 1) AND (_inventory_table.is_in_stock = 1)) OR  ((_inventory_table.use_config_manage_stock = 0) AND (1 - _inventory_table.manage_stock + _inventory_table.is_in_stock >= 1))) THEN 1 ELSE 0 END)',
        array()
    );
    $collection->getSelect()->order('on_top DESC');
    // Make sure on_top is the first order directive
    $order = $collection->getSelect()->getPart('order');
    array_unshift($order, array_pop($order));
    $collection->getSelect()->setPart('order', $order);
}

Edit: Changed back to catalog_product_collection_load_before from catalog_product_collection_apply_limitations_before and fixed order part priority.