La solución ofrecida por @SanderMangel es de primera categoría. Puedo ayudar a ampliar esto con algún código, que actualmente uso en mi módulo Productos de categoría automatizados / dinámicos, que tiene la capacidad de hacer reglas de categoría de productos en productos especiales
El código ajusta una colección de productos estándar para obtener todos los productos con un precio especial establecido, el día que se ejecuta el código. Puede usar esto en el cron para volver a llenar las categorías a las 00:00 y asegurarse de que se mantengan actualizadas.
Tenga en cuenta que el código se extrae de un módulo más grande, por lo tanto, he compactado las partes relevantes aquí para usted. Puede haber una variable o dos que no están representadas en este extracto, pero serían fáciles de deducir, o simplemente preguntar :)
El objeto $ category es la categoría real que debe contener los productos. El código a continuación también le permitirá especificar el descuento en un valor de% :)
$collection = $category->getProductCollection();
$todayDate = Mage::app()->getLocale()->date()->toString(Varien_Date::DATE_INTERNAL_FORMAT);
$collection->addAttributeToFilter(array(
array(
'attribute' => "special_to_date",
'null' => true
),
array(
'attribute' => "special_to_date",
'from' => $todayDate,
//'to' => $todayDate,
'date' => true
)
));
$collection->addAttributeToFilter(array(
array(
'attribute' => "special_from_date",
'null' => true
),
array(
'attribute' => "special_from_date",
//'from' => $todayDate,
'to' => $todayDate,
'date' => true
)
));
$collection->addAttributeToSelect('special_price','left');
$collection->addAttributeToSelect('price','left');
$select = $collection->getSelect();
if (strpos($value, '%') > 0) {
$value = str_replace('%', '', $value);
$select->where('( 100 - (( at_special_price.value * 100 ) / at_price.value ) ) ' . $operator . ' ' . $value);
} else {
$select->where('((at_price.value - at_special_price.value)) ' . $operator . ' ' . $value);
}
Ahora, hay que tener en cuenta que la colección no devolverá productos, ya que contiene enlaces a las tablas normales de enlaces de productos del catálogo <->. Como no está interesado en los productos vinculados actuales, debe borrar esa relación de tabla de la colección.
Yo uso el siguiente código para hacerlo:
/**
* Remove Catalog Product Link elements from collection
*
* @param type $collection
* @return type
*/
public function removeCatProPart($collection)
{
$select = $collection->getSelect();
$fromPart = $select->getPart(Zend_Db_Select::FROM);
$select->reset(Zend_Db_Select::FROM);
if (array_key_exists('cat_pro', $fromPart)) {
unset($fromPart['cat_pro']);
// also remove any reference to the table in the rest of the query
$columns = $select->getPart(Zend_Db_Select::COLUMNS);
$columnRemoved = false;
foreach ($columns as $columnKey => $column) {
if ($column[0] == 'cat_pro') {
unset($columns[$columnKey]);
$columnRemoved = true;
}
}
if ($columnRemoved) {
$select->setPart(Zend_Db_Select::COLUMNS, $columns);
}
$orderPart = $select->getPart(Zend_Db_Select::ORDER);
$orderRemoved = false;
foreach ($orderPart as $orderKey => $order) {
if ($order[0] == 'cat_pro') {
unset($orderPart[$orderKey]);
$orderRemoved = true;
}
}
if ($orderRemoved) {
$select->setPart(Zend_Db_Select::ORDER, $orderPart);
}
}
$select->setPart(Zend_Db_Select::FROM, $fromPart);
return $collection;
}
Como beneficio adicional, puede usar la misma técnica para ajustar la colección de productos del catálogo y encontrar productos que están en modo especial debido a las reglas del catálogo:
$storeDate = Mage::app()->getLocale()->storeTimeStamp($this->getStoreId());
$value = $this->getValue();
$conditions = 'price_rule.product_id = e.entity_id AND ';
$conditions .= "(from_time = 0
OR from_time <= " . $storeDate . ")
AND (to_time = 0
OR to_time >= " . $storeDate . ") AND ";
$conditions .= "price_rule.rule_id IN (" . $value . ")";
$collection->getSelect()->joinInner(
array('price_rule' => $collection->getTable('catalogrule/rule_product')), $conditions);
$collection->setFlag('applied_catalog_rule_id', true);
$collection->setFlag('applied_rule', true);
Una vez que tenga la colección de trabajo, todo lo que necesita hacer es obtener todos los identificadores de la colección, voltear la matriz y usar $category->setPostedProducts($products);
y una $ category-> save () l; para completar la actualización.
Para completar, aquí está mi cron diario que mantiene las categorías dinámicas actualizadas. (de nuevo, se refiere a métodos no incluidos aquí, pero estoy seguro de que lo llevará en la dirección correcta
Que te diviertas :)
public static function rebuildAllDynamic($schedule)
{
try {
$tempDir = sys_get_temp_dir() . "/";
$fp = fopen($tempDir . "dyncatprod_rebuild.lock", "w+");
if (flock($fp, LOCK_EX | LOCK_NB)) {
if (Mage::getStoreConfig('dyncatprod/debug/enabled')) {
mage::log("DynCatProd - rebuildAllDynamic");
}
if (!Mage::getStoreConfig('dyncatprod/rebuild/max_exec')) {
ini_set('max_execution_time', 3600); // 1 hour
}
$categories = Mage::getModel('catalog/category')
->getCollection()
->addAttributeToSelect('*')
->addIsActiveFilter()
->addAttributeToFilter('dynamic_attributes', array('notnull' => true));
foreach ($categories as $category) {
$products = Mage::helper('dyncatprod')->getDynamicProductIds($category);
if (is_array($products)) {
if (Mage::getStoreConfig('dyncatprod/debug/enabled')) {
mage::log("rebuilding :" . $category->getName() . ' ' . $category->getPath() );
}
$products = array_flip($products);
$category->setPostedProducts($products);
$category->setIsDynamic(true);
$category->save();
}
}
flock($fp, LOCK_UN);
unlink($tempDir . "dyncatprod_rebuild.lock");
} else {
mage::log('Could not execute cron for rebuildAllDynamic -file lock is in place, job may be running');
}
} catch (Exception $e) {
flock($fp, LOCK_UN);
unlink($tempDir . "dyncatprod_rebuild.lock");
mage::logException($e);
return $e->getMessage();
}
}
ref: http://www.proxiblue.com.au/magento-dynamic-category-products.html