Help! I Can't Set A Catalog Product Collection's Page Size
Published: January 18, 2017
I ran up against a pretty interesting issue recently. I was looking to render a custom block (descendant of Mage_Catalog_Block_Product_List
) in a CMS block. You can do this with template variables…
{{block type="mpchadwick_customproductlist/list" template="mpchadwick/customproductlist/list.phtml"}}
Then, in my custom product list block I was setting up the collection in the constructor.
<?php
class Mpchadwick_CustomProductList_Block_List extends Mage_Catalog_Block_Product_List
{
protected $helper;
protected function _construct()
{
$this->helper = Mage::helper('mpchadwick_customproductlist');
$collection = Mage::getModel('catalog/product')
->getCollection();
$helper->filterCollection($collection);
$this->setCollection($collection);
return parent::_construct();
}
}
One of the things I was looking to do in the filterCollection
was set the page size. However, no matter what I did (e.g. setPageSize
, setPage
, limit
on the Varien_Db_Select
object) it still wouldn’t work.
Finally, after an hour of pulling out my hair, I figured out why.
The Bloody Toolbar
If you look in the Mage_Catalog_Block_Product_List::_beforeToHtml()
you’ll see the following line (some code omitted for clarity)…
protected function _beforeToHtml()
{
$toolbar = $this->getToolbarBlock();
$collection = $this->_getProductCollection();
$toolbar->setCollection($collection);
return parent::_beforeToHtml();
}
Looking at Mage_Catalog_Block_Product_List_Toolbar::setCollection()
you’ll see the following (again, some code omitted for clarity)
public function setCollection($collection)
{
$this->_collection = $collection;
$limit = (int)$this->getLimit();
if ($limit) {
$this->_collection->setPageSize($limit);
}
return $this;
}
Aha! So before rendering a rendering Mage_Catalog_Block_Product_List
(or any descendant) the toolbar sets the page size! Unfortunately, the toolbar doesn’t check if the someone already tried to set a limit on the collection.
What Can Be Done
Below is the entire body of Mage_Catalog_Block_Product_List::getLimit()
in all its glory.
public function getLimit()
{
$limit = $this->_getData('_current_limit');
if ($limit) {
return $limit;
}
$limits = $this->getAvailableLimit();
$defaultLimit = $this->getDefaultPerPageValue();
if (!$defaultLimit || !isset($limits[$defaultLimit])) {
$keys = array_keys($limits);
$defaultLimit = $keys[0];
}
$limit = $this->getRequest()->getParam($this->getLimitVarName());
if ($limit && isset($limits[$limit])) {
if ($limit == $defaultLimit) {
Mage::getSingleton('catalog/session')->unsLimitPage();
} else {
$this->_memorizeParam('limit_page', $limit);
}
} else {
$limit = Mage::getSingleton('catalog/session')->getLimitPage();
}
if (!$limit || !isset($limits[$limit])) {
$limit = $defaultLimit;
}
$this->setData('_current_limit', $limit);
return $limit;
}
The line(s) I’d like to draw your attention to is the following…
$limit = $this->_getData('_current_limit');
if ($limit) {
return $limit;
}
If _current_limit
is in the _data
array of the object, just go with that.
How Can We Use This
The trick is to also override the getToolbarBlock
in your custom block. What I did looks like this…
public function getToolbarBlock()
{
$block = parent::getToolbarBlock();
$block->setData('_current_limit', $this->helper->limit());
return $block;
}
Conclusion
I hope that some of you found this post helpful, in case you run into a similar issue. If you have any questions or comments, feel free to drop a note below, or, as always, you can reach me on Twitter as well.