More Flexible Approach to Listing Sale Products in Magento

onsale_featured

Some clients have a need to show product on sale on homepage, or, sometimes, to filter products on sale in each category individually. In this post i’ll show you two ways of listing products on sale:

  • On CMS page as a list
  • By using a filter in category view

Let’s get to it!

Static CMS page

This is just a quick way of showing products on sale on one page, using admin and uploading one phtml file. Going down this path, you won’t be able to use pagination nor layered navigation. In case you would like those features, I’d recommend following the second part (Filter in Category) of this post.

Create a new CMS page with content set to

{{block type="catalog/product_list" template="inchoo/onsale/sale.phtml"}}

and a template for listing your products.

app/design/frontend/default/YOUR_THEME/template/inchoo/onsale/sale.phtml

<?php
$_productCollection = Mage::getModel('catalog/product')->getCollection();
$_productCollection->addAttributeToSelect(array(
                                   'image',
                                   'name',
                                   'short_description'
                   ))
                   ->addFieldToFilter('visibility', array(
                               Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH,
                               Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_CATALOG
                   )) //showing just products visible in catalog or both search and catalog
                   ->addFinalPrice()
//                        ->addAttributeToSort('price', 'asc') //in case we would like to sort products by price
                   ->getSelect()
                   ->where('price_index.final_price < price_index.price')
//                        ->limit(30) //we can specify how many products we want to show on this page
//                        ->order(new Zend_Db_Expr('RAND()')) //in case we would like to sort products randomly
                   ;
Mage::getModel('review/review')->appendSummary($_productCollection);
$_helper = $this->helper('catalog/output');
?>
//
<?php if(!$_productCollection->count()): ?>
    <p class="note-msg"><?php echo $this->__('There are no products matching the selection.') ?></p>
<?php else: ?>
    <div class="category-products">
        <?php // List mode ?>
            <?php $_iterator = 0; ?>
            <ol class="products-list" id="products-list">
                <?php foreach ($_productCollection as $_product): ?>
                    <li class="item<?php if( ++$_iterator == sizeof($_productCollection) ): ?> last<?php endif; ?>">
                        <?php // Product Image ?>
                        <a href="<?php echo $_product->getProductUrl() ?>" title="<?php echo $this->stripTags($this->getImageLabel($_product, 'small_image'), null, true) ?>" class="product-image"><img src="<?php echo $_product->getImageUrl(); ?>" width="135" height="135" alt="<?php echo $this->stripTags($this->getImageLabel($_product, 'small_image'), null, true) ?>" /></a>
                        <?php // Product description ?>
                        <div class="product-shop">
                            <div class="f-fix">
                                <?php $_productNameStripped = $this->stripTags($_product->getName(), null, true); ?>
                                <h2 class="product-name"><a href="<?php echo $_product->getProductUrl() ?>" title="<?php echo $_productNameStripped; ?>"><?php echo $_helper->productAttribute($_product, $_product->getName() , 'name'); ?></a></h2>
                                <?php if($_product->getRatingSummary()): ?>
                                    <?php echo $this->getReviewsSummaryHtml($_product) ?>
                                <?php endif; ?>
                                <?php echo $this->getPriceHtml($_product, true) ?>
                                <?php if($_product->isSaleable()): ?>
                                    <p><button type="button" title="<?php echo $this->__('Add to Cart') ?>" class="button btn-cart" onclick="setLocation('<?php echo $this->getAddToCartUrl($_product) ?>')"><span><span><?php echo $this->__('Add to Cart') ?></span></span></button></p>
                                <?php else: ?>
                                    <p class="availability out-of-stock"><span><?php echo $this->__('Out of stock') ?></span></p>
                                <?php endif; ?>
                                <div class="desc std">
                                    <?php echo $_helper->productAttribute($_product, $_product->getShortDescription(), 'short_description') ?>
                                    <a href="<?php echo $_product->getProductUrl() ?>" title="<?php echo $_productNameStripped ?>" class="link-learn"><?php echo $this->__('Learn More') ?></a>
                                </div>
                                <ul class="add-to-links" style="margin:0; padding-left:0; list-style: none;">
                                    <?php if ($this->helper('wishlist')->isAllow()) : ?>
                                        <li><a href="<?php echo $this->helper('wishlist')->getAddUrl($_product) ?>" class="link-wishlist"><?php echo $this->__('Add to Wishlist') ?></a></li>
                                    <?php endif; ?>
                                    <?php if($_compareUrl=$this->getAddToCompareUrl($_product)): ?>
                                        <li><span class="separator">|</span> <a href="<?php echo $_compareUrl ?>" class="link-compare"><?php echo $this->__('Add to Compare') ?></a></li>
                                    <?php endif; ?>
                                </ul>
                            </div>
                        </div>
                    </li>
                <?php endforeach; ?>
            </ol>
            <script type="text/javascript">decorateList('products-list', 'none-recursive')</script>
    </div>
<?php endif; ?>

That’s it! Try and visit your CMS page. You’ll see that the products with special price are listed in a ‘list view’, something like this:

onsale1

With small modifications, you could display products in ‘grid view’ as well.

Filter in Category View

Magento applies filtering and loads collection to layered navigation before that same collection gets loaded in the template. That’s why we need to overwrite _getProductCollection method, so that we can apply custom filtering before the collection gets loaded. Let’s do that by extending Mage_Catalog_Product_List class and rendering our block instead of the default one on category view.

Let’s register out little module. For our purposes, let’s name it ‘Inchoo/Onsale’.

app/etc/modules/Inchoo_Onsale.xml

<?xml version="1.0"?>
<config>
    <modules>
        <Inchoo_Onsale>
            <active>true</active>
            <codePool>local</codePool>
        </Inchoo_Onsale>
    </modules>
</config>

Let’s also configure our module. We’ll use a block, helper, and modify the layout of our template a little bit.

app/code/local/Inchoo/Onsale/etc/config.xml

<?xml version="1.0"?>
<config>
    <modules>
        <Inchoo_Onsale>
            <version>1.0.0.3</version>
        </Inchoo_Onsale>
    </modules>
    <global>
        <blocks>
            <inchoo_onsale>
                <class>Inchoo_Onsale_Block</class>
            </inchoo_onsale>
        </blocks>
        <helpers>
            <inchoo_onsale>
                <class>Inchoo_Onsale_Helper</class>
            </inchoo_onsale>
        </helpers>
    </global>
    <frontend>
        <layout>
            <updates>
                <onsale>
                    <file>inchoo/onsale.xml</file>
                </onsale>
            </updates>
        </layout>
    </frontend>
</config>

Now, register a helper that will have two methods: getOnSaleUrl and getNotOnSaleUrl. They’ll be used by our checkbox, to fetch URL that will be loaded upon click. We’ll also add a new variable to URL – ‘sale‘. When sale equals 1, we’ll show products on sale, if it is not set, we’ll show all products in category.

app/code/local/Inchoo/Onsale/Helper/Data.php

<?php
class Inchoo_Onsale_Helper_Data extends Mage_Core_Helper_Abstract
{
    public function getOnSaleUrl()
    {
        $url = Mage::getUrl('', array(
            '_current' => true,
            '_use_rewrite' => true,
            '_query' => array(
                'sale' => 1,
                'p' => NULL
            )
        ));
        return $url;
    }
    public function getNotOnSaleUrl()
    {
        $url = Mage::getUrl('', array(
            '_current' => true,
            '_use_rewrite' => true,
            '_query' => array(
                'sale' => NULL,
                'p' => NULL
            )
        ));
        return $url;
    }
}

Now, lets create our block. We’ll extend our class from Mage_Catalog_Block_Product_List, and write our own _getProductCollection method.

app/code/local/Inchoo/Onsale/Block/Catalog/Product/List.php

<?php
class Inchoo_Onsale_Block_Catalog_Product_List extends Mage_Catalog_Block_Product_List
{
    protected function _getProductCollection()
    {
        if (is_null($this->_productCollection)) {
            $layer = $this->getLayer();
            /* @var $layer Mage_Catalog_Model_Layer */
            if ($this->getShowRootCategory()) {
                $this->setCategoryId(Mage::app()->getStore()->getRootCategoryId());
            }
            // if this is a product view page
            if (Mage::registry('product')) {
                // get collection of categories this product is associated with
                $categories = Mage::registry('product')->getCategoryCollection()
                                  ->setPage(1, 1)
                                  ->load();
                // if the product is associated with any category
                if ($categories->count()) {
                    // show products from this category
                    $this->setCategoryId(current($categories->getIterator()));
                }
            }
            $origCategory = null;
            if ($this->getCategoryId()) {
                $category = Mage::getModel('catalog/category')->load($this->getCategoryId());
                if ($category->getId()) {
                    $origCategory = $layer->getCurrentCategory();
                    $layer->setCurrentCategory($category);
                    $this->addModelTags($category);
                }
            }
            $this->_productCollection = $layer->getProductCollection();
//                inchoo start
            $param = Mage::app()->getRequest()->getParam('sale');
            if(isset($param) && $param==='1'){
                $this->_productCollection
                    ->addFinalPrice()
                    ->getSelect()
                    ->where('price_index.final_price < price_index.price');
            }
//                inchoo end
            $this->prepareSortableFieldsByCategory($layer->getCurrentCategory());
            if ($origCategory) {
                $layer->setCurrentCategory($origCategory);
            }
        }
        return $this->_productCollection;
//            return parent::_getProductCollection();
    }
}

We’ll also add a checkbox to our toolbar, where our customer will be able to filter products that are on sale. Open your toolbar.phtml file.

app/design/frontend/default/YOUR_THEME/template/inchoo/onsale/toolbar.phtml

<!--inchoo start-->
<?php $helper = Mage::helper('inchoo_onsale'); ?>
<!--inchoo end-->
<?php if($this->getCollection()->getSize()): ?>
    <div class="toolbar">
        <div class="pager">
            <p class="amount">
                <?php if($this->getLastPageNum()>1): ?>
                    <?php echo $this->__('Items %s to %s of %s total', $this->getFirstNum(), $this->getLastNum(), $this->getTotalNum()) ?>
                <?php else: ?>
                    <strong><?php echo $this->__('%s Item(s)', $this->getTotalNum()) ?></strong>
                <?php endif; ?>
            </p>
            <div class="limiter">
                <label><?php echo $this->__('Show') ?></label>
                <select onchange="setLocation(this.value)">
                    <?php foreach ($this->getAvailableLimit() as  $_key=>$_limit): ?>
                        <option value="<?php echo $this->getLimitUrl($_key) ?>"<?php if($this->isLimitCurrent($_key)): ?> selected="selected"<?php endif ?>>
                            <?php echo $_limit ?>
                        </option>
                    <?php endforeach; ?>
                </select> <?php echo $this->__('per page') ?>
            </div>
            <?php echo $this->getPagerHtml() ?>
        </div>
        <?php if( $this->isExpanded() ): ?>
            <div class="sorter">
                <?php if( $this->isEnabledViewSwitcher() ): ?>
                    <p class="view-mode">
                        <?php $_modes = $this->getModes(); ?>
                        <?php if($_modes && count($_modes)>1): ?>
                            <label><?php echo $this->__('View as') ?>:</label>
                            <?php foreach ($this->getModes() as $_code=>$_label): ?>
                                <?php if($this->isModeActive($_code)): ?>
                                    <strong title="<?php echo $_label ?>" class="<?php echo strtolower($_code); ?>"><?php echo $_label ?></strong>&nbsp;
                                <?php else: ?>
                                    <a href="<?php echo $this->getModeUrl($_code) ?>" title="<?php echo $_label ?>" class="<?php echo strtolower($_code); ?>"><?php echo $_label ?></a>&nbsp;
                                <?php endif; ?>
                            <?php endforeach; ?>
                        <?php endif; ?>
                    </p>
                <?php endif; ?>
                <div class="sort-by">
                    <label><?php echo $this->__('Sort By') ?></label>
                    <select onchange="setLocation(this.value)">
                        <?php foreach($this->getAvailableOrders() as $_key=>$_order): ?>
                            <option value="<?php echo $this->getOrderUrl($_key, 'asc') ?>"<?php if($this->isOrderCurrent($_key)): ?> selected="selected"<?php endif; ?>>
                                <?php echo $this->__($_order) ?>
                            </option>
                        <?php endforeach; ?>
                    </select>
                    <?php if($this->getCurrentDirection() == 'desc'): ?>
                        <a href="<?php echo $this->getOrderUrl(null, 'asc') ?>" title="<?php echo $this->__('Set Ascending Direction') ?>"><img src="<?php echo $this->getSkinUrl('images/i_desc_arrow.gif') ?>" alt="<?php echo $this->__('Set Ascending Direction') ?>" class="v-middle" /></a>
                    <?php else: ?>
                        <a href="<?php echo $this->getOrderUrl(null, 'desc') ?>" title="<?php echo $this->__('Set Descending Direction') ?>"><img src="<?php echo $this->getSkinUrl('images/i_asc_arrow.gif') ?>" alt="<?php echo $this->__('Set Descending Direction') ?>" class="v-middle" /></a>
                <!--inchoo start-->
                        <label for="sale"><?php echo $this->__('On Sale') ?></label>
                        <input name="sale" id="sale" type="checkbox"
                            value="<?php
                                $currentUrl = Mage::helper('core/url')->getCurrentUrl();
                                if($currentUrl===$helper->getOnSaleUrl()):
                                    echo $helper->getNotOnSaleUrl();
                                    echo "\"checked=\"checked";
                                else:
                                    echo $helper->getOnSaleUrl();
                                endif;
                            ?>" autocomplete="off" onchange="setLocation(this.value)"/>
                <!--inchoo end-->
                    <?php endif; ?>
                </div>
            </div>
        <?php endif; ?>
    </div>
<?php endif ?>

And, lastly, create our layout file to make Magento use our toolbar.phtml template instead of the default one.

app/design/frontend/default/YOUR_THEME/layout/inchoo/onsale.xml

<?xml version="1.0"?>
<layout version="0.1.0">
    <catalog_category_default>
        <reference name="category.products">
                <block type="inchoo_onsale/catalog_product_list" name="product_list" template="catalog/product/list.phtml">
                    <block type="catalog/product_list_toolbar" name="product_list_toolbar" template="inchoo/onsale/toolbar.phtml">
                        <block type="page/html_pager" name="product_list_toolbar_pager"/>
                        <!-- The following code shows how to set your own pager increments -->
                        <!--
                            <action method="setDefaultListPerPage"><limit>4</limit></action>
                            <action method="setDefaultGridPerPage"><limit>9</limit></action>
                            <action method="addPagerLimit"><mode>list</mode><limit>2</limit></action>
                            <action method="addPagerLimit"><mode>list</mode><limit>4</limit></action>
                            <action method="addPagerLimit"><mode>list</mode><limit>6</limit></action>
                            <action method="addPagerLimit"><mode>list</mode><limit>8</limit></action>
                            <action method="addPagerLimit" translate="label"><mode>list</mode><limit>all</limit><label>All</label></action>
                        -->
                    </block>
                    <action method="addColumnCountLayoutDepend"><layout>empty</layout><count>6</count></action>
                    <action method="addColumnCountLayoutDepend"><layout>one_column</layout><count>5</count></action>
                    <action method="addColumnCountLayoutDepend"><layout>two_columns_left</layout><count>4</count></action>
                    <action method="addColumnCountLayoutDepend"><layout>two_columns_right</layout><count>4</count></action>
                    <action method="addColumnCountLayoutDepend"><layout>three_columns</layout><count>3</count></action>
                    <action method="setToolbarBlockName"><name>product_list_toolbar</name></action>
                </block>
        </reference>
    </catalog_category_default>
    <catalog_category_layered>
        <reference name="category.products">
            <block type="inchoo_onsale/catalog_product_list" name="product_list" template="catalog/product/list.phtml">
                <block type="catalog/product_list_toolbar" name="product_list_toolbar" template="inchoo/onsale/toolbar.phtml">
                    <block type="page/html_pager" name="product_list_toolbar_pager"/>
                    <!-- The following code shows how to set your own pager increments -->
                    <!--
                        <action method="setDefaultListPerPage"><limit>4</limit></action>
                        <action method="setDefaultGridPerPage"><limit>9</limit></action>
                        <action method="addPagerLimit"><mode>list</mode><limit>2</limit></action>
                        <action method="addPagerLimit"><mode>list</mode><limit>4</limit></action>
                        <action method="addPagerLimit"><mode>list</mode><limit>6</limit></action>
                        <action method="addPagerLimit"><mode>list</mode><limit>8</limit></action>
                        <action method="addPagerLimit" translate="label"><mode>list</mode><limit>all</limit><label>All</label></action>
                    -->
                </block>
                <action method="addColumnCountLayoutDepend"><layout>empty</layout><count>6</count></action>
                <action method="addColumnCountLayoutDepend"><layout>one_column</layout><count>5</count></action>
                <action method="addColumnCountLayoutDepend"><layout>two_columns_left</layout><count>4</count></action>
                <action method="addColumnCountLayoutDepend"><layout>two_columns_right</layout><count>4</count></action>
                <action method="addColumnCountLayoutDepend"><layout>three_columns</layout><count>3</count></action>
                <action method="setToolbarBlockName"><name>product_list_toolbar</name></action>
            </block>
        </reference>
    </catalog_category_layered>
</layout>

See it in action:
onsale2

Note that layered navigation works, as well as pagination. Just what we wanted.

P.S. You can always view this module on GitHub or download zipped file and install it.

23
Top

Care to rate this post?

Author

Petar Sambolek

Ex Inchooer

Petar worked at Inchoo as a Backend Developer from January to August 2014

Other posts from this author

Discussion 23 Comments

Add Comment
  1. hotmonitor

    Hello
    List mode in CMS works
    How to put Grid mode in CMS?

  2. Hi, hotmonitor!
    Thanks for the comment :)

    For listing products in grid mode on a CMS page, place the following code in your app/design/frontend/default/YOUR_THEME/template/inchoo/onsale/sale.phtml
    instead of the one written above.

    <?php
        $_productCollection = Mage::getModel('catalog/product')->getCollection();
        $_productCollection->addAttributeToSelect(array(
                                       'image',
                                       'name',
                                       'short_description'
                                                  ))
                            ->addFieldToFilter('visibility', array(
                                        Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH,
                                        Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_CATALOG
                                )) //showing just products visible in catalog or both search and catalog
                            ->addFinalPrice()
    //                        ->addAttributeToSort('price', 'asc') //in case we would like to sort products by price
                            ->getSelect()
                            ->where('price_index.final_price < price_index.price')
    //                        ->limit(30) //we specify how many products we want to show on this page
    //                        ->order(new Zend_Db_Expr('RAND()')) //in case we would like to sort products randomly
                            ;
        Mage::getModel('review/review')->appendSummary($_productCollection);
        $_helper = $this->helper('catalog/output');
    ?>
    <?php if(!$_productCollection->count()): ?>
        <p class="note-msg"><?php echo $this->__('There are no products matching the selection.') ?></p>
    <?php else: ?>
        <div class="category-products">
            <?php // Grid Mode ?>
            <?php $_collectionSize = $_productCollection->count() ?>
            <?php $_columnCount = $this->getColumnCount(); ?>
            <?php $i=0; foreach ($_productCollection as $_product): ?>
            <?php if ($i++%$_columnCount==0): ?>
                <ul class="products-grid" style="padding:0; list-style: none">
            <?php endif ?>
                <li class="item<?php if(($i-1)%$_columnCount==0): ?> first<?php elseif($i%$_columnCount==0): ?> last<?php endif; ?>">
                    <a href="<?php echo $_product->getProductUrl() ?>" title="<?php echo $this->stripTags($this->getImageLabel($_product, 'small_image'), null, true) ?>" class="product-image"><img src="<?php echo $_product->getImageUrl(); ?>" width="135" height="135" alt="<?php echo $this->stripTags($this->getImageLabel($_product, 'small_image'), null, true) ?>" /></a>
                    <h2 class="product-name"><a href="<?php echo $_product->getProductUrl() ?>" title="<?php echo $this->stripTags($_product->getName(), null, true) ?>"><?php echo $_helper->productAttribute($_product, $_product->getName(), 'name') ?></a></h2>
                    <?php if($_product->getRatingSummary()): ?>
                        <?php echo $this->getReviewsSummaryHtml($_product, 'short') ?>
                    <?php endif; ?>
                    <?php echo $this->getPriceHtml($_product, true) ?>
                    <div class="actions">
                        <?php if($_product->isSaleable()): ?>
                            <button type="button" title="<?php echo $this->__('Add to Cart') ?>" class="button btn-cart" onclick="setLocation('<?php echo $this->getAddToCartUrl($_product) ?>')"><span><span><?php echo $this->__('Add to Cart') ?></span></span></button>
                        <?php else: ?>
                            <p class="availability out-of-stock"><span><?php echo $this->__('Out of stock') ?></span></p>
                        <?php endif; ?>
                        <ul class="add-to-links">
                            <?php if ($this->helper('wishlist')->isAllow()) : ?>
                                <li><a href="<?php echo $this->helper('wishlist')->getAddUrl($_product) ?>" class="link-wishlist"><?php echo $this->__('Add to Wishlist') ?></a></li>
                            <?php endif; ?>
                            <?php if($_compareUrl=$this->getAddToCompareUrl($_product)): ?>
                                <li><span class="separator">|</span> <a href="<?php echo $_compareUrl ?>" class="link-compare"><?php echo $this->__('Add to Compare') ?></a></li>
                            <?php endif; ?>
                        </ul>
                    </div>
                </li>
                <?php if ($i%$_columnCount==0 || $i==$_collectionSize): ?>
                </ul>
            <?php endif ?>
            <?php endforeach ?>
            <script type="text/javascript">decorateGeneric($$('ul.products-grid'), ['odd','even','first','last'])</script>
        </div>
    <?php endif; ?>
    
  3. Jay

    I tried implementing your code and couldn’t get it to work with my custom theme. I have since removed the code, however, now I am still left with the option to filter by “On Sale”. Double checked that all files have been removed. Any tips on how I can remove this so that the option is longer available?

  4. Hi, Jay.

    Which approach of these two have you used?
    Have you cleared your cache when you changed layout xml configuration (onsale.xml)?

  5. vishnu

    Hi this is really nice work

    but i have a query . i show only 4 product on home page. and after that i want to add a link find out more . but i am unable to give this links how can i show all products using this link

  6. Travis

    Oh Man! I just had to solve exactly the same problem earlier this week. Unfortunately I hadn’t found this post til today after I’d finished.

    I was completely unaware of the addFinalPrice() collection method and of the price_index table alias used in the where clause. I solved it by creating an is_on_sale product attribute and then running a nightly ‘indexer’ to populate the attribute for all products. Same effect, but it would have been great to know Magento had the features I needed right there the whole time.

    Thanks for the research.

  7. Hans Kuijpers

    thank you for the great blog! Especially the second solution is great. I used to have sales items on a CMS Page but was missing the Layered Navigation.

    How can I implement the second solution without the toolbar? I want a catalog view with only products with special price AND layered navigation on the side.

  8. Hi, Hans.
    I’m glad to hear this article helped you :)

    As for your question, the simplest solution would be to comment out all code in the toolbar.phtml or add a conditional in toolbar.phtml file.
    However, this would remove toolbar from other category pages as well.

    If you need to do this for only one CMS page (without pagination), the most appropriate method would be following the second part of this article (Filter in Category View), but without doing layout updates (onsale.xml). Then, create a CMS page with the content set to

    {{block type="inchoo_onsale/product_list" template="inchoo/onsale/sale.phtml"}}

    and commenting out lines 36 and 41 in List.php

    But, this is just an idea. Hope this helped you :)

  9. Thanks Petar, I really appreciate your responses and I have a question regarding my online store at hompathcure.com where I would like to create a cms page to how just product name, short description and add to cart button all three options in one row so I can show my customers to purchase directly from that page whatever they are interested to purchase, I will really appreciate your response via email thanks

  10. Hi,

    This is great info!
    However I was wondering how could I include pagination and layered navigation into the CMS catalog sale list…
    Summing up I want a regular normal product list (grid and list) with only sale products :)

    Thanks

  11. Hello Petar,

    Does the CMS method also list product on sale by setting Catalog Price Rules ?

    Thank you very much.

  12. Otokim

    @?? ch?i tr? em

    Yes, it does works

    @Petar:

    Thank you for your post, very usefull. I just have one issue. I need to automatically list all product in sales for the whole catalog.
    I created a sales category which contains all products. It works well, but layer navigation display all results from my category (and not only product’s in sale).

    In my class, i changed a bit your method:

     protected function _getProductCollection()
        {
            if (is_null($this->_productCollection)) {
                $layer = $this->getLayer();
                /* @var $layer Mage_Catalog_Model_Layer */
                if ($this->getShowRootCategory()) {
                    $this->setCategoryId(Mage::app()->getStore()->getRootCategoryId());
                }
                // if this is a product view page
                if (Mage::registry('product')) {
                    // get collection of categories this product is associated with
                    $categories = Mage::registry('product')->getCategoryCollection()
                    ->setPage(1, 1)
                    ->load();
                    // if the product is associated with any category
                    if ($categories->count()) {
                        // show products from this category
                        $this->setCategoryId(current($categories->getIterator()));
                    }
                }
                $origCategory = null;
                if ($this->getCategoryId()) {
                    $category = Mage::getModel('catalog/category')->load($this->getCategoryId());
                    if ($category->getId()) {
                        $origCategory = $layer->getCurrentCategory();
                        $layer->setCurrentCategory($category);
                        $this->addModelTags($category);
                    }
                }
                $this->_productCollection = $layer->getProductCollection();
                    $this->_productCollection
                    ->addFinalPrice()
                    ->getSelect()
                    ->where('price_index.final_price < price_index.price');
                $this->prepareSortableFieldsByCategory($layer->getCurrentCategory());
                if ($origCategory) {
                    $layer->setCurrentCategory($origCategory);
                }
            }
            return $this->_productCollection;
        }
    

    In admin, i tried those two approaches:

    <reference name="category.products">
                    <block type="elijaq_catalog/product_list" name="product_list" template="catalog/product/sales.phtml">
                        <block type="catalog/product_list_toolbar" name="product_list_toolbar" template="catalog/product/list/toolbar.phtml">
                            <block type="page/html_pager" name="product_list_toolbar_pager"/>
                            <!-- The following code shows how to set your own pager increments -->
                            <!--
                                <action method="setDefaultListPerPage"><limit>4</limit></action>
                                <action method="setDefaultGridPerPage"><limit>9</limit></action>
                                <action method="addPagerLimit"><mode>list</mode><limit>2</limit></action>
                                <action method="addPagerLimit"><mode>list</mode><limit>4</limit></action>
                                <action method="addPagerLimit"><mode>list</mode><limit>6</limit></action>
                                <action method="addPagerLimit"><mode>list</mode><limit>8</limit></action>
                                <action method="addPagerLimit" translate="label"><mode>list</mode><limit>all</limit><label>All</label></action>
                            -->
                        </block>
                        <action method="addColumnCountLayoutDepend"><layout>empty</layout><count>6</count></action>
                        <action method="addColumnCountLayoutDepend"><layout>one_column</layout><count>5</count></action>
                        <action method="addColumnCountLayoutDepend"><layout>two_columns_left</layout><count>4</count></action>
                        <action method="addColumnCountLayoutDepend"><layout>two_columns_right</layout><count>4</count></action>
                        <action method="addColumnCountLayoutDepend"><layout>three_columns</layout><count>3</count></action>
                        <action method="setToolbarBlockName"><name>product_list_toolbar</name></action>
                    </block>
            </reference>
     <catalog_category_layered>
            <reference name="category.products">
                <block type="inchoo_onsale/catalog_product_list" name="product_list" template="catalog/product/list.phtml">
                    <block type="catalog/product_list_toolbar" name="product_list_toolbar" template="catalog/product/list/toolbar.phtml">
                        <block type="page/html_pager" name="product_list_toolbar_pager"/>
                        <!-- The following code shows how to set your own pager increments -->
                        <!--
                            <action method="setDefaultListPerPage"><limit>4</limit></action>
                            <action method="setDefaultGridPerPage"><limit>9</limit></action>
                            <action method="addPagerLimit"><mode>list</mode><limit>2</limit></action>
                            <action method="addPagerLimit"><mode>list</mode><limit>4</limit></action>
                            <action method="addPagerLimit"><mode>list</mode><limit>6</limit></action>
                            <action method="addPagerLimit"><mode>list</mode><limit>8</limit></action>
                            <action method="addPagerLimit" translate="label"><mode>list</mode><limit>all</limit><label>All</label></action>
                        -->
                    </block>
                    <action method="addColumnCountLayoutDepend"><layout>empty</layout><count>6</count></action>
                    <action method="addColumnCountLayoutDepend"><layout>one_column</layout><count>5</count></action>
                    <action method="addColumnCountLayoutDepend"><layout>two_columns_left</layout><count>4</count></action>
                    <action method="addColumnCountLayoutDepend"><layout>two_columns_right</layout><count>4</count></action>
                    <action method="addColumnCountLayoutDepend"><layout>three_columns</layout><count>3</count></action>
                    <action method="setToolbarBlockName"><name>product_list_toolbar</name></action>
                </block>
            </reference>
        </catalog_category_layered>

    And

    <reference name="category.products">
                    <block type="elijaq_catalog/product_list" name="product_list" template="catalog/product/sales.phtml">
                        <block type="catalog/product_list_toolbar" name="product_list_toolbar" template="catalog/product/list/toolbar.phtml">
                            <block type="page/html_pager" name="product_list_toolbar_pager"/>
                            <!-- The following code shows how to set your own pager increments -->
                            <!--
                                <action method="setDefaultListPerPage"><limit>4</limit></action>
                                <action method="setDefaultGridPerPage"><limit>9</limit></action>
                                <action method="addPagerLimit"><mode>list</mode><limit>2</limit></action>
                                <action method="addPagerLimit"><mode>list</mode><limit>4</limit></action>
                                <action method="addPagerLimit"><mode>list</mode><limit>6</limit></action>
                                <action method="addPagerLimit"><mode>list</mode><limit>8</limit></action>
                                <action method="addPagerLimit" translate="label"><mode>list</mode><limit>all</limit><label>All</label></action>
                            -->
                        </block>
                        <action method="addColumnCountLayoutDepend"><layout>empty</layout><count>6</count></action>
                        <action method="addColumnCountLayoutDepend"><layout>one_column</layout><count>5</count></action>
                        <action method="addColumnCountLayoutDepend"><layout>two_columns_left</layout><count>4</count></action>
                        <action method="addColumnCountLayoutDepend"><layout>two_columns_right</layout><count>4</count></action>
                        <action method="addColumnCountLayoutDepend"><layout>three_columns</layout><count>3</count></action>
                        <action method="setToolbarBlockName"><name>product_list_toolbar</name></action>
                    </block>
            </reference>
    

    Of course, i did not need your toolbar since i want to automatically list sale’s item.

    Would you help me finding out whats going one?

    Thank you!

    Very nice job

  13. Hi, Otokim.
    I’m glad you found a use for this code :)

    I have tried what you did and I get only products on sale in category. I did everything as written in the article, removed the code for ‘onsale‘ parameter in List.php, and modified layout to use default toolbar template. Try doing everything again, and instead of onsale.xml written in the article, use this code:

    <?xml version="1.0"?>
    <layout version="0.1.0">
        <catalog_category_default>
            <reference name="category.products">
                <block type="inchoo_onsale/catalog_product_list" name="product_list" template="catalog/product/list.phtml">
                    <block type="catalog/product_list_toolbar" name="product_list_toolbar" template="catalog/product/list/toolbar.phtml">
                        <block type="page/html_pager" name="product_list_toolbar_pager"/>
                        <!-- The following code shows how to set your own pager increments -->
                        <!--
                            <action method="setDefaultListPerPage"><limit>4</limit></action>
                            <action method="setDefaultGridPerPage"><limit>9</limit></action>
                            <action method="addPagerLimit"><mode>list</mode><limit>2</limit></action>
                            <action method="addPagerLimit"><mode>list</mode><limit>4</limit></action>
                            <action method="addPagerLimit"><mode>list</mode><limit>6</limit></action>
                            <action method="addPagerLimit"><mode>list</mode><limit>8</limit></action>
                            <action method="addPagerLimit" translate="label"><mode>list</mode><limit>all</limit><label>All</label></action>
                        -->
                    </block>
                    <action method="addColumnCountLayoutDepend"><layout>empty</layout><count>6</count></action>
                    <action method="addColumnCountLayoutDepend"><layout>one_column</layout><count>5</count></action>
                    <action method="addColumnCountLayoutDepend"><layout>two_columns_left</layout><count>4</count></action>
                    <action method="addColumnCountLayoutDepend"><layout>two_columns_right</layout><count>4</count></action>
                    <action method="addColumnCountLayoutDepend"><layout>three_columns</layout><count>3</count></action>
                    <action method="setToolbarBlockName"><name>product_list_toolbar</name></action>
                </block>
            </reference>
        </catalog_category_default>
        <catalog_category_layered>
            <reference name="category.products">
                <block type="inchoo_onsale/catalog_product_list" name="product_list" template="catalog/product/list.phtml">
                    <block type="catalog/product_list_toolbar" name="product_list_toolbar" template="catalog/product/list/toolbar.phtml">
                        <block type="page/html_pager" name="product_list_toolbar_pager"/>
                        <!-- The following code shows how to set your own pager increments -->
                        <!--
                            <action method="setDefaultListPerPage"><limit>4</limit></action>
                            <action method="setDefaultGridPerPage"><limit>9</limit></action>
                            <action method="addPagerLimit"><mode>list</mode><limit>2</limit></action>
                            <action method="addPagerLimit"><mode>list</mode><limit>4</limit></action>
                            <action method="addPagerLimit"><mode>list</mode><limit>6</limit></action>
                            <action method="addPagerLimit"><mode>list</mode><limit>8</limit></action>
                            <action method="addPagerLimit" translate="label"><mode>list</mode><limit>all</limit><label>All</label></action>
                        -->
                    </block>
                    <action method="addColumnCountLayoutDepend"><layout>empty</layout><count>6</count></action>
                    <action method="addColumnCountLayoutDepend"><layout>one_column</layout><count>5</count></action>
                    <action method="addColumnCountLayoutDepend"><layout>two_columns_left</layout><count>4</count></action>
                    <action method="addColumnCountLayoutDepend"><layout>two_columns_right</layout><count>4</count></action>
                    <action method="addColumnCountLayoutDepend"><layout>three_columns</layout><count>3</count></action>
                    <action method="setToolbarBlockName"><name>product_list_toolbar</name></action>
                </block>
            </reference>
        </catalog_category_layered>
    </layout>
    
  14. Otokim

    Hello Petar,

    Thank you for your answer, but i guess you misunderstood my issue.

    I need to display all product’s in sale for the whole catalog (and not for a specific category).

    In my case, i did not need your toolbar.

    I created a specific category which contains all products for my catalog and used update layout in back office in order to override getColletion method by using mine.

    Display works well, i have only products in sales, and so is pagination, but results of filters display all products for the category (as if they were no sales).

    By the way, i’ll dig from my side if you have no clue and put the answer here.

    Thank you again!

  15. Otokim

    Found it :)

    To sum up, i needed to create a special category which list automatically all products in sales for the whole catalog.

    Sometimes, i’d like to not display some specific products on it.

    First, i created a category “Sales” which contains all the product’s i’d like to display.

    Then, creation of a custom module like in the article.

    Changes are:

    &lt;?php
    /**
     * Special collection for getting only products on sales
     * @author apu
     *
     */
    class Yourmodule_Catalog_Block_Sales_Product_List extends Mage_Catalog_Block_Product_List
    {
        public function getLayer()
        {
            $layer = Mage::registry('current_layer');
            if ($layer) {
                return $layer;
            }
            return Mage::getSingleton('yourmodule/sales_layer');
        }
        protected function _getProductCollection()
        {
            if (is_null($this-&gt;_productCollection)) {
                $layer = $this-&gt;getLayer();
                /* @var $layer Mage_Catalog_Model_Layer */
                if ($this-&gt;getShowRootCategory()) {
                    $this-&gt;setCategoryId(Mage::app()-&gt;getStore()-&gt;getRootCategoryId());
                }
                // if this is a product view page
                if (Mage::registry('product')) {
                    // get collection of categories this product is associated with
                    $categories = Mage::registry('product')-&gt;getCategoryCollection()
                    -&gt;setPage(1, 1)
                    -&gt;load();
                    // if the product is associated with any category
                    if ($categories-&gt;count()) {
                        // show products from this category
                        $this-&gt;setCategoryId(current($categories-&gt;getIterator()));
                    }
                }
                $origCategory = null;
                if ($this-&gt;getCategoryId()) {
                    $category = Mage::getModel('catalog/category')-&gt;load($this-&gt;getCategoryId());
                    if ($category-&gt;getId()) {
                        $origCategory = $layer-&gt;getCurrentCategory();
                        $layer-&gt;setCurrentCategory($category);
                        $this-&gt;addModelTags($category);
                    }
                }
                $this-&gt;_productCollection = $layer-&gt;getProductCollection();
                    $this-&gt;_productCollection
                    -&gt;addFinalPrice()
                    -&gt;getSelect()
                    -&gt;where('price_index.final_price &lt; price_index.price');
                $this-&gt;prepareSortableFieldsByCategory($layer-&gt;getCurrentCategory());
                if ($origCategory) {
                    $layer-&gt;setCurrentCategory($origCategory);
                }
                $layer-&gt;setProductCollection($this-&gt;_productCollection);
            }
            return $this-&gt;_productCollection;
        }
    }
    

    This update let us automatically list all the product’s in sales without a checkbox in a toolbar.
    At this point, pagination and list works well, but not filters on the navigation left.

    Here’s the trick:

    Creation of a customer model layer:

    &lt;?php
    /**
     *
     */
    class Yourmodule_Catalog_Model_Sales_Layer extends Mage_Catalog_Model_Layer
    {
        /**
         * Retrieve current layer product collection
         *
         * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection
         */
        public function getProductCollection()
        {
            if (isset($this-&gt;_productCollections[$this-&gt;getCurrentCategory()-&gt;getId()])) {
                $collection = $this-&gt;_productCollections[$this-&gt;getCurrentCategory()-&gt;getId()];
                $collection-&gt;getSelect()
                    -&gt;where('price_index.final_price &lt; price_index.price');
            } else {
                $collection = $this-&gt;getCurrentCategory()-&gt;getProductCollection();
                $this-&gt;prepareProductCollection($collection);
                $collection-&gt;getSelect()
                    -&gt;where('price_index.final_price &lt; price_index.price');
                $this-&gt;_productCollections[$this-&gt;getCurrentCategory()-&gt;getId()] = $collection;
            }
            return $collection;
        }
    }
    

    Now, our custom layer needs to be called, we need to create a special layer view block (like list one)

    &lt;?php
    class Yourmodule_Catalog_Block_Sales_Layer_View extends Mage_Catalog_Block_Layer_View
    {
        /**
         * Get layer object
         * @return Mage_Catalog_Model_Layer
         */
        public function getLayer()
        {
            return Mage::getSingleton('yourmodule/sales_layer');
        }
    }
    

    To finish, i the back office, we need to update custom layout for that category (customer design / custom update layout)

    &lt;reference name=&quot;category.products&quot;&gt;
                    &lt;block type=&quot;yourmodule/sales_product_list&quot; name=&quot;product_list&quot; template=&quot;catalog/product/sales.phtml&quot;&gt;
                        &lt;block type=&quot;catalog/product_list_toolbar&quot; name=&quot;product_list_toolbar&quot; template=&quot;catalog/product/list/toolbar.phtml&quot;&gt;
                            &lt;block type=&quot;page/html_pager&quot; name=&quot;product_list_toolbar_pager&quot;/&gt;
                            &lt;!-- The following code shows how to set your own pager increments --&gt;
                            &lt;!--
                                &lt;action method=&quot;setDefaultListPerPage&quot;&gt;&lt;limit&gt;4&lt;/limit&gt;&lt;/action&gt;
                                &lt;action method=&quot;setDefaultGridPerPage&quot;&gt;&lt;limit&gt;9&lt;/limit&gt;&lt;/action&gt;
                                &lt;action method=&quot;addPagerLimit&quot;&gt;&lt;mode&gt;list&lt;/mode&gt;&lt;limit&gt;2&lt;/limit&gt;&lt;/action&gt;
                                &lt;action method=&quot;addPagerLimit&quot;&gt;&lt;mode&gt;list&lt;/mode&gt;&lt;limit&gt;4&lt;/limit&gt;&lt;/action&gt;
                                &lt;action method=&quot;addPagerLimit&quot;&gt;&lt;mode&gt;list&lt;/mode&gt;&lt;limit&gt;6&lt;/limit&gt;&lt;/action&gt;
                                &lt;action method=&quot;addPagerLimit&quot;&gt;&lt;mode&gt;list&lt;/mode&gt;&lt;limit&gt;8&lt;/limit&gt;&lt;/action&gt;
                                &lt;action method=&quot;addPagerLimit&quot; translate=&quot;label&quot;&gt;&lt;mode&gt;list&lt;/mode&gt;&lt;limit&gt;all&lt;/limit&gt;&lt;label&gt;All&lt;/label&gt;&lt;/action&gt;
                            --&gt;
                        &lt;/block&gt;
                        &lt;action method=&quot;addColumnCountLayoutDepend&quot;&gt;&lt;layout&gt;empty&lt;/layout&gt;&lt;count&gt;6&lt;/count&gt;&lt;/action&gt;
                        &lt;action method=&quot;addColumnCountLayoutDepend&quot;&gt;&lt;layout&gt;one_column&lt;/layout&gt;&lt;count&gt;5&lt;/count&gt;&lt;/action&gt;
                        &lt;action method=&quot;addColumnCountLayoutDepend&quot;&gt;&lt;layout&gt;two_columns_left&lt;/layout&gt;&lt;count&gt;4&lt;/count&gt;&lt;/action&gt;
                        &lt;action method=&quot;addColumnCountLayoutDepend&quot;&gt;&lt;layout&gt;two_columns_right&lt;/layout&gt;&lt;count&gt;4&lt;/count&gt;&lt;/action&gt;
                        &lt;action method=&quot;addColumnCountLayoutDepend&quot;&gt;&lt;layout&gt;three_columns&lt;/layout&gt;&lt;count&gt;3&lt;/count&gt;&lt;/action&gt;
                        &lt;action method=&quot;setToolbarBlockName&quot;&gt;&lt;name&gt;product_list_toolbar&lt;/name&gt;&lt;/action&gt;
                    &lt;/block&gt;
            &lt;/reference&gt;
    &lt;reference name=&quot;left&quot;&gt;
          &lt;action method=&quot;unsetChild&quot;&gt;&lt;name&gt;catalog.leftnav&lt;/name&gt;&lt;/action&gt;
          &lt;block type=&quot;yourmodule/sales_layer_view&quot; name=&quot;catalog.leftnav&quot; after=&quot;currency&quot; template=&quot;catalog/layer/view.phtml&quot;/&gt;
    &lt;/reference&gt;
    

    Worked well for me, thank you again Petar for your post.

  16. Simon

    Hi Petar,

    really nice work here. Can you show me how to get only the x newest products on sale?

    Thanks a lot!

  17. Arp

    Awesome job man. Definitely pointed me in the right direction. I checked out your code and it is working fine. Although one thing boggles me: I tried your Grid (instead of List) view snippet and it doesn’t work. The products look like grid view, but there is only one column. I tried setting an absolute value for columnCount in the phtml and tried every page-layout for the CMS page, but to no avail.

    Did I miss something? Should the CMS include line on the page be different, as well?

  18. Arp

    Update: the problem seems to be CSS related. For some reason the items are very wide and thus only one product per row is displayed (which really sucks).

  19. nilesh

    we added https://github.com/Marko-M/Inchoo_Sale module but in that case layer navigation not display and also in template layer folder is missing.

    Our requirement is display sales product listing with layer navigation.

    we don’t need to sale and on sale attribute.layer navigation work with default category.

    We need sale product listing display same as

    http://www.manadev.com/demo/shop-by-special-price/index.php/sale/

    http://www.manadev.com/shop-by-special-price

  20. nilesh

    How can I implement the second solution without the toolbar? I want a catalog view with only products with special price AND layered navigation on the side.

  21. sud

    hiii Petar Sambolek,

    i want show discounted product top of the category rest will be on bottom. i tried but it show mixed. i’m working on localhost.

    plzz help

  22. how can i add this in search result page toolbar??

  23. I have implemented the same in my site. But it is affecting the ajax layer navigation & ajax toolbar. May i know how to fix it?

Add Your Comment

Please wrap all source codes with [code][/code] tags.
Top