We were asked to write a simple module that makes it possible to display a rule-specific teaser on product pages when they are affected by catalog price rules.
So, our first question was: how can we even detect if a price rule is applied to a product?
The easiest Solutions
Model Mage_CatalogRule_Model_Rule
offers two methods that seem quite interesting: loadProductRules
and calcProductPriceRule
.
loadProductRules
will save any rule ids that are attached to the given product in the product’s collection:
// $_product is an instance of Mage_Catalog_Model_Product $catalogRule = Mage::getModel('catalogrule/rule')->loadProductRules($_product);
$catalogRule will now contain an array: Array( [rule_id] => [irrelevant_number] )
. If you want to know why we get an irrelevant number here, you can read up below.
While this is the fastest and easiest way to get any rules applied to our product, the most important thing to note is that it literally gives us *every* rule that is somehow connected. There are no filters applied which means we also get future and past rules and rules that are meant for any customer group or website. Depending on what you want to do this can be totally fine, of course.
Lets take a look at calcProductPriceRule
. This handy method is returning our product’s price with any catalog rule applied to it. If there is no rule applied it will return NULL. This sounds great because we can use it do exactly what we need – detect whether a price rule gets applied to our product or not:
if( Mage::getModel('catalogrule/rule')->calcProductPriceRule($_product,$_product->getPrice()) ){ echo 'Catalog price rule applied'; } else { echo 'No catalog price rule applied'; }
And yes, this one filters our rules by date, customer groups and website. The only downside of it is that it does more than we need it to do – which means it takes more resources than necessary.
So what are the alternatives?
An alternative way and also the way that we ended up going is reproducing what calcProductPriceRule
does, but without actually calculating any prices. Essentially, it makes use of Mage_CatalogRule_Model_Resource_Rule::getRulesFromProduct
and so will we:
Step 1: Set up your Model
class My_Module_Model_Catalogrule extends Mage_Core_Model_Abstract { /* * @param Mage_Catalog_Model_Product $product * @return array */ public function getRulesFromProduct(Mage_Catalog_Model_Product $product) { $productId = $product->getId(); $storeId = $product->getStoreId(); $websiteId = Mage::app()->getStore($storeId)->getWebsiteId(); if ($product->hasCustomerGroupId()) { $customerGroupId = $product->getCustomerGroupId(); } else { $customerGroupId = Mage::getSingleton('customer/session')->getCustomerGroupId(); } $dateTs = Mage::app()->getLocale()->date()->getTimestamp(); return Mage::getResourceModel('catalogrule/rule')->getRulesFromProduct($dateTs, $websiteId, $customerGroupId, $productId); } }
Our method returns an empty array if the product does not have any price rules applied.
Step 2: Set up your Block
class My_Module_Block_Catalog_Product_Catalogrule extends Mage_Catalog_Block_Product_Abstract { protected $_rules; public function getRules(){ if( is_null($this->_rules) ){ $catalogrule = Mage::getModel('my_module/catalogrule'); if(($product = $this->getProduct()) && ($rules = $catalogrule->getRulesFromProduct($product))){ $this->_rules = $rules; } else { $this->_rules = false; } } return $this->_rules; } public function hasRuleApplied(){ if( $this->getRules() ){ return true; } return false; } }
Step 3: Set up your template
Now we can do stuff like this in our block’s template:
<?php if($this->hasRuleApplied()): ?> <?php foreach($this->getRules() as $rule): ?> <div class="pricerule-teaser"> <strong><?php switch($rule['action_operator']){ case 'by_percent': echo $this->__('%s%% Discount', round($rule['action_amount'])); break; case 'by_fixed': echo $this->__('%s Discount', Mage::helper('core')->currency($rule['action_amount'], true, false)); break; case 'to_percent': echo $this->__('Only %s%% of the original price', round($rule['action_amount'])); break; case 'to_fixed': echo $this->__('Only %s', Mage::helper('core')->currency($rule['action_amount'], true, false)); break; } ?></strong> <?php echo $this->__('until the %s !', date('dS M', $rule['to_time'])) ?> </div> <?php endforeach; ?> <?php endif; ?>
Read up below if you want a list of all the values our $rule array stores.
Well and that’s it! Let us know if you have questions or ideas for improvement.
Continue reading How to detect if a price rule gets applied to a product