Skip to content

Create Special Offers Page based on Attribute combined with Catalog Rule

As known in Magento there are multiple ways to apply special pricing from products and based on many answers I found this forum I created a module with Layer Navigation to load all products that have special prices applied and also Catalog rule price applied however it ended up loading a couple of products and not all products.

<?php

namespace VendorSpecialModel;

use MagentoCatalogApiCategoryRepositoryInterface;
use MagentoCatalogModelResourceModelProductAttributeCollectionFactory as AttributeCollectionFactory;
use MagentoCatalogModelResourceModelProductCollectionFactory;
use MagentoCatalogRuleModelResourceModelRuleCollectionFactory as RuleCollectionFactory;
use MagentoCatalogModelProduct;

/**
 * Vendor Special Layer model class
 */
class Layer extends MagentoCatalogModelLayer
{
    /**
     * @var CollectionFactory
     */
    protected $productCollectionFactory;

    /**
     * @var RuleCollectionFactory
     */
    protected $ruleCollectionFactory;

    /**
     * @var MagentoCatalogModelProduct
     */
    protected $_modelProduct;

    /**
     * Layer constructor.
     * @param MagentoCatalogModelLayerContextInterface $context
     * @param MagentoCatalogModelLayerStateFactory $layerStateFactory
     * @param AttributeCollectionFactory $attributeCollectionFactory
     * @param MagentoCatalogModelResourceModelProduct $catalogProduct
     * @param MagentoStoreModelStoreManagerInterface $storeManager
     * @param MagentoFrameworkRegistry $registry
     * @param CategoryRepositoryInterface $categoryRepository
     * @param CollectionFactory $productCollectionFactory
     * @param RuleCollectionFactory $ruleCollectionFactory
     * @param Product $product
     * @param array $data
     */
    public function __construct(
        MagentoCatalogModelLayerContextInterface $context,
        MagentoCatalogModelLayerStateFactory $layerStateFactory,
        AttributeCollectionFactory $attributeCollectionFactory,
        MagentoCatalogModelResourceModelProduct $catalogProduct,
        MagentoStoreModelStoreManagerInterface $storeManager,
        MagentoFrameworkRegistry $registry,
        CategoryRepositoryInterface $categoryRepository,
        CollectionFactory $productCollectionFactory,
        RuleCollectionFactory $ruleCollectionFactory,
        Product $modelProduct,
        array $data = []
    ) {
        $this->productCollectionFactory = $productCollectionFactory;
        $this->ruleCollectionFactory = $ruleCollectionFactory;
        $this->_modelProduct = $modelProduct;
        parent::__construct(
            $context,
            $layerStateFactory,
            $attributeCollectionFactory,
            $catalogProduct,
            $storeManager,
            $registry,
            $categoryRepository,
            $data
        );
    }

    /**
     * Get special product collection
     * @return MagentoCatalogModelResourceModelProductCollection
     * @throws Zend_Date_Exception
     */
    public function getProductCollection()
    {
        if (isset($this->_productCollections['vendor_custom'])) {
            $collection = $this->_productCollections['vendor_custom'];
        } else {
            $date = new Zend_Date();

            $collection = $this->productCollectionFactory->create()
            ->addAttributeToSelect('*')
            ->addAttributeToFilter(
                'special_from_date',
                [
                    'or' => [
                        0 => [
                            'date' => true,
                            'to' => $date->get('YYYY-MM-dd') . ' 23:59:59'
                        ],
                        1 => [
                            'is' => new Zend_Db_Expr('null')
                        ],
                    ]
                ],
                'left'
            )
            ->addAttributeToFilter(
                'special_to_date',
                [
                    'or' => [
                        0 => [
                            'date' => true,
                            'from' => $date->get('YYYY-MM-dd') . ' 00:00:00'
                        ],
                        1 => [
                            'is' => new Zend_Db_Expr('null')
                        ],
                    ]
                ],
                'left'
            )
            ->addAttributeToFilter('special_price',array('lt'=>new Zend_Db_Expr("price_index.price")));
            $this->prepareProductCollection($collection);
           // $collection->addAttributeToFilter('special',MagentoCatalogModelProductAttributeSourceStatus::STATUS_ENABLED);
           $rules = $this->ruleCollectionFactory->create();

           // read: if there are active rules
           if($rules->getData()) {
               $rule_ids = array(); // i used this down below to style the products according to which rule affected
               $productIds[] = array(); // this will hold the ids of the products
   
               foreach($rules as $rule) {
                   $rule_ids[] = $rule->getId();
                   $productIds = $rule->getMatchingProductIds(); // affected products come in here
               }
   
               // merge the collections: $arr is an array and keeps all product IDs we fetched before with the special-price-stuff
               $arr = $collection->getAllIds();
               if($productIds) {
                   // if there are products affected by catalog price rules, $arr now also keeps their IDs
                   $arr = array_merge($arr,$productIds);
               }
   
               // we initialize a new collection and filter solely by the product IDs we got before, read: select all products with their entity_id in $arr
               $collection = $this->_modelProduct->getCollection()->addAttributeToFilter('entity_id',array('in'=>$arr))
                   ->load();
           }
           
            
            $this->_productCollections['vendor_custom'] = $collection;
        }

    

        
        return $collection;
    }
}

I have more than 4 rules that runs discount on prices and also more than 100 products that include special pricing some with date define and others not. The total products should be 500+ products between direct special_price attribute and catalog_rule collection.

How’s it possible to combine all those products and load them properly in a dedicated page named “Special Offers”