12

Im trying to limit the number of returned results manually in a copy of the list.phtml template, but its turning out to be alot harder than I anticipated.

Ive tried manually setting the collection size, but ya once again nothing working. Can someone show me how to do this? Would be nmuch appreciated!

Jonathan Day
  • 18,519
  • 10
  • 84
  • 137
thrice801
  • 1,671
  • 5
  • 23
  • 31
  • 1
    Are you trying to limit the number of returned products so only a certain number are displayed, or for other reasons? – Alana Storm May 18 '10 at 07:28
  • Im trying to extend this module http://yoast.com/landing-pages-module-magento/ I mean extend as in, even just manually write in on the custom list.php page im making, call a set number of products so that I can have for instance, 3 featured products from category x, 3 from y, 3 from z, and make it show up all nice and pretty in a jquery slider. – thrice801 May 18 '10 at 17:30

6 Answers6

21

A quick way is with this method I recently discovered. You can even use it directly in the template.

$_productCollection = clone $this->getLoadedProductCollection();
$_productCollection->clear()
                   ->setPageSize(3)
                   ->load();
Community
  • 1
  • 1
clockworkgeek
  • 37,650
  • 9
  • 89
  • 127
7

A similar approach to @joseph is to override Mage_Catalog_Block_Product_List but insert the following code in your new class:

const PAGE_SIZE = 3;

protected function _getProductCollection(){
    $collection = parent::_getProductCollection();
    $yourCustomBoolean = someFunctionThatDetectsYourCustomPage();
    if($yourCustomBoolean) {
        $collection->setPageSize(self::PAGE_SIZE);
    }
    return $collection;
}

that way you will inherit any future changes in the Mage_Catalog code from the parent block but still set your page limits.

Ideally you would use a system.xml node to create a field that can be edited by an administrator without hardcoding the page_size. The xml would look something like:

<config>
<sections>
    <catalog>
        <groups>
            <frontend>
                <fields>
                    <custom_page_size translate="label">
                        <label>Page Size for Custom Page Type</label>
                        <frontend_type>text</frontend_type>
                        <sort_order>9999</sort_order>
                        <show_in_default>1</show_in_default>
                        <show_in_website>1</show_in_website>
                        <show_in_store>1</show_in_store>
                    </custom_page_size>
                </fields>
            </frontend>
        </groups>
    </catalog>
</sections>
</config>

Then retrieve that value in your code with:

$page_size = Mage::getStoreConfig('catalog/frontend/custom_page_size');

HTH,
JD

Jonathan Day
  • 18,519
  • 10
  • 84
  • 137
  • This is great, only could you please provide a brief suggestion of how I'd implement `someFunctionThatDetectsYourCustomPage()`? I have a custom module which uses a category page as its base and I'm trying to limit the number of products for that module only. But I have no idea how I'd detect, in the observer function, that I'm viewing that module's category page and not any other category pages on the site. Thanks! – WackGet Nov 21 '12 at 10:56
  • sounds like you should be using a custom Controller within your module rather than (ab)using a category page... – Jonathan Day Nov 21 '12 at 11:08
  • Very true, Jonathan. However I've inherited this codebase and it's far, far too massive to change at this time. I've been using clockworkgeek's solution but would definitely prefer to implement yours; I'm just unsure as to how to detect if the user is on my specific module's category page. – WackGet Nov 21 '12 at 12:09
  • Sounds like fun :) If you look in this @chapagain blog post, http://blog.chapagain.com.np/magento-how-to-get-controller-action-and-module-name-in-template-file/ that will give you some pointers. Also, check the Mage::registry('current_category') to see if the category controller has stashed the category in the registry already for you. – Jonathan Day Nov 21 '12 at 12:35
5

unfortunately it doesn't work because in the _getProductCollection() method the Collection has been already initialized with a page size.

A more flexible solution could be that of observing the catalog_product_collection_load_before event which, as the name suggests, is dispatched before the collection is loaded.

Here follows an example (assuming to write a yourmodule extension under yourpackage):

STEP 1: Define your observer in config.xml

in the global section of your config.xml extension file insert something like:

<events>
  <catalog_product_collection_load_before>
    <observers>
      <yourpackage_yourmodule_catalog_observer>
        <type>singleton</type>
        <class>yourpackage_yourmodule/catalog_observer</class>
        <method>limitPageSize</method>
      </yourpackage_yourmodule_catalog_observer>
    </observers>
  </catalog_product_collection_load_before>
</events>    

STEP 2: Define your Observer class under the Model\Catalog folder:

<?php
class Yourpackage_Yourmodule_Model_Catalog_Observer
{
  public function limitPageSize($observer)
  {
    #TODO: Insert the logic you need to differentiate when to apply the following
    $event = $observer->getEvent();
    $collection = $event->getCollection();
    $collection->setPageSize(3);
    return $this;
  }
}

Hope it helps. Sincerely, Alessandro Ronchi

3

I got the Code of User:clockworkgeek , but here is some issue and correct code is as follow, it work and thanks clockworkgeek.

$_productCollection = $this->getLoadedProductCollection();
$_productCollection->clear();
$_productCollection->setPageSize(3)
$_productCollection->load();

You Also writeenter code here or solve this issue by modify as

$this->getLoadedProductCollection()->clear();
$_productCollection = $this->getLoadedProductCollection();

Thanks, If it help you then comment.

Sajjucode
  • 51
  • 4
2

It looks like the collection returned in list.phtml has already had load() called, which means that by the time we get to the template we've lost the opportunity to set the page size. So, this is going to get a bit messy!

The block that generates that collection is Mage_Catalog_Block_Product_List, which we can extend with our own class and override at the same time. Create a new block that extends Mage_Catalog_Block_Product_List and override the method _getProductCollection as follows:

/**
 * Retrieve loaded category collection
 *
 * @return Mage_Eav_Model_Entity_Collection_Abstract
 */
protected function _getProductCollection()
{
    if (is_null($this->_productCollection)) {
        $layer = Mage::getSingleton('catalog/layer');
        /* @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->_productCollection = $layer->getProductCollection();

        $this->prepareSortableFieldsByCategory($layer->getCurrentCategory());

        // OUR CODE MODIFICATION ////////////////////
        $yourCustomPage = someFunctionThatDetectsYourCustomPage();
        if($yourCustomPage) {
            $this->_productCollection->setPageSize(1);
            $this->_productCollection->setCurPage(3);
            $this->_productCollection->load();
        }
        /////////////////////////////////////////////

        if ($origCategory) {
            $layer->setCurrentCategory($origCategory);
        }
    }
    return $this->_productCollection;
}

The important part is to find some way to detect whether you're using the custom list.phtml page or not. Then you'll need to override references to <block type='catalog/product_list' /> in the layouts with your class, and you should be set to go.

Hope that helps!

Thanks, Joe

Joe Mastey
  • 26,809
  • 13
  • 80
  • 104
  • Hey Joe, Thanks for the reply. Ok so, can I put this in the custom list.php file (which Im using to make a landing page), before the other code or do I need to put it somewhere else? Im basically just extending this module; http://yoast.com/landing-pages-module-magento/ -- to allow the limiting of the number of items returned, so I can make nice looking landing pages. Im a little confused about the part someFunctionThatDetectsYourCustomPage(); -- Do I call that function first on the landing.php page before everything else or? (sorry Im still fairly new to OO PHP and Zend and what not.) – thrice801 May 18 '10 at 17:29
  • thanks for the suggestion @Joseph - I've tweaked it a little in my answer so that it's less obtrusive and more future-proof. JD – Jonathan Day Apr 19 '11 at 00:42
0

As was mentioned, the productCollection already has page size set. There is another way to get the collection though; via the catalog/product Model:

$productCollection = Mage::getModel('catalog/product')
    ->getCollection()
    ->addAttributeToSelect(
        array('name', 'image', 'price')
    )
    ->addIdFilter( 
        array('1', '2')
    )
    ->setPageSize( 2 )
    ->load();
;

return $productCollection->getSelect()->__toString();

The resulting query (and ultimately object) contains the LIMIT syntax:

SELECT `e`.* ... WHERE (`e`.`entity_id` IN('1', '2')) LIMIT 2;

Is that what you were asking?

Jongosi
  • 2,305
  • 1
  • 28
  • 31