So, the question is about gathering certain products from other categories, and putting them in some special category at the very moment customer starts to open that special category.
As example, I can suggest a category with a list of new products (based on attributes “New from Date” and “New to Date”). This category will be rebuilt each time customer opens it, to be sure it will contain only new products.
I will not discuss practical usefulness of this precarious manipulation. It’s up to you to decide whether to use this practice, or not, but newbies should not even think about implementing this idea on real projects.
So, the task is not difficult. First of all, we need to have a category to dynamically store new products. This category must not be accessible directly, but only through the special link. This link will be controlled by our special controller.
- create model or helper method that will yield collection of currently new products – those with attribute “New from Date” not bigger than today’s date, and with attribute “New to Date” not less than today’s date (of course, one of these attributes may be null);
- create helper class that will perform category resetting and refilling;
- create controller that at first will call helper method to reset and refill category, and only then redirects to standard controller to show category the usual way.
Now all these steps in details.
1) method getCollection is pretty self-explaining.
public function getCollection()
{
$todayStartOfDayDate = Mage::app()->getLocale()->date()
->setTime('00:00:00')
->toString(Varien_Date::DATETIME_INTERNAL_FORMAT);
$todayEndOfDayDate = Mage::app()->getLocale()->date()
->setTime('23:59:59')
->toString(Varien_Date::DATETIME_INTERNAL_FORMAT);
/** @var $collection Mage_Catalog_Model_Resource_Product_Collection */
$collection = Mage::getResourceModel('catalog/product_collection');
$collection->setVisibility(Mage::getSingleton('catalog/product_visibility')->getVisibleInCatalogIds());
$collection = $collection
->addStoreFilter()
->addAttributeToFilter('news_from_date', array('or'=> array(
0 => array('date' => true, 'to' => $todayEndOfDayDate),
1 => array('is' => new Zend_Db_Expr('null')))
), 'left')
->addAttributeToFilter('news_to_date', array('or'=> array(
0 => array('date' => true, 'from' => $todayStartOfDayDate),
1 => array('is' => new Zend_Db_Expr('null')))
), 'left')
->addAttributeToFilter(
array(
array('attribute' => 'news_from_date', 'is'=>new Zend_Db_Expr('not null')),
array('attribute' => 'news_to_date', 'is'=>new Zend_Db_Expr('not null'))
)
)
;
return $collection;
}
2) Category resetting and refilling have most challenges of this article.
First challenge: synchronization.
There is good chance that while our special controller will be busy resetting and refilling category, another customer will try to open this category too.
In this case we have two problems: how to prevent launching second “resetting and refilling“ process, and what to do with second customer’s request (should we put it on hold, or reject, or what?).
To ensure that only one “resetting and refilling” process will be executed at the same time, we will use power of the Mage_Index_Model_Process class.
And request from the second customer will not be put on hold or rejected, but, skipping “resetting and refilling“ phase, redirected to standard controller to show category the usual way. Of course, second customer will see “half-ready” category, with some products missing, and some outdated products present, but it is better than deny his request at all or make him wait some (may be long!) period of time.
Second challenge: “resetting and refilling” process must not be straightforward.
If category already contain products, there is a good chance that some of them are still new. So why should we delete them? So we must compare two collections: one from our method getCollection, and other – current list of category products. Then we will calculate the difference, delete only obsolete products, and add only missing ones.