Note for recent versions of Magento – Broken
Seems like this tutorial doesn’t work anymore for recent versions (1.6.2 for me), because of magento prices indexing. Price is not calculated on the fly on frontend anymore, and indexing does not call the event “catalog_product_get_final_price”. To be confirmed.
Attention: Disable Mage_Compiler
System → Tools → Compilation → In the top right corner there are 2 buttons, make sure the first one is labeled ‘Disabled’.
Apart from the powerful OOP way of customizing Magento, which is overriding methods by subclassing Magento’s core Blocks and Models, there is another way to plug in customizations in key flow areas of your Magento eCommerce shop.
Referred to as the Event-Observer methodology, Magento has been programmed to raise events in crucial areas of the flow Using these events for customizations can keep upgrading a much more simple task that does not require fiddling around with Magento’s core source code. An example would be the event ‘catalog_product_save_after’ which will be raised by Magento immediately after a product is saved.
Event An Event is something that occurs in a certain place during a particular sequence flow. Say once a customer completes an order, the flow sequence would be to
1. Save the order details 2. Send e-mail confirmation to customer
Events may be emitted before or after each of these flow points to introduce custom logic.
Observer An Observer is an event handler. It listens to any event it is attached to and accordingly reacts to the event.
Customization – Using Events vs. Overriding classes
|
|
Simply put, think about overriding existing core logic if you need to completely change or if you need to extend core logic and your new logic is going to be reused elsewhere. Use events if you are fine with existing logic provided by Magento and need to add to the core logic.
This example tries to use the Event-Observer technique to introduce a percentage discount for each product. Currently Magento supports special price functionality without a % discount. So we would use this opportunity to customize magento to introduce %discount at a product level.
Before starting, the aim is to ensure that the percentage discount is considered for a simple product when a product is displayed. The event is raised in the class Mage_Catalog_Model_Product_Type_Price→getFinalPrice() (Magento 1.3.0 file: app/code/core/Mage/Catalog/Model/Product/Type/Price.php). The event is raised by the line Mage::dispatchEvent(’catalog_product_get_final_price’,array(’product’⇒$product));
The event that we are about to handle is catalog_product_get_final_price which is going to help us add logic to consider the percentage discount.
Create a new attribute ‘percent_discount‘.
Attrib Identifier –percent_discount , Scope – Store View , Catalog I/p – Text , Unique Value – No , Values Required – NoInput , Validation –Decimal , Apply to Configurable/All Product Types – Yes
Use in quick search – No , Advanced Search – No , Comparable – No , Visibile on Frontend – Yes , Attribute Label – % Discount
Add this new attribute to your attributeset. If your product’s attributeset is ‘default‘, add the new ‘percent_discount’ attribute to this attributeset under “prices” attribute group.
Register a new custom local module under name ‘Xyz’. For this create file ‘Xyz.xml’ under directory ‘app/etc/modules/’. File contents are –
-
<?xml version=”1.0″?>
-
<config>
-
<modules>
-
<Xyz_Catalog>
-
<codePool>local</codePool>
-
<active>true</active>
-
</Xyz_Catalog>
-
</modules>
-
</config>
Register the event with its Observer. Create file ‘config.xml’ under directory ‘app/code/local/Xyz/Catalog/etc/’ with contents as –
-
<?xml version=”1.0″?>
-
<config>
-
<global>
-
<models>
-
<xyzcatalog>
-
<class>Xyz_Catalog_Model</class>
-
</xyzcatalog>
-
</models>
-
<events>
-
<catalog_product_get_final_price>
-
<observers>
-
<xyz_catalog_price_observer>
-
<type>singleton</type>
-
<class>Xyz_Catalog_Model_Price_Observer</class>
-
<method>apply_discount_percent</method>
-
</xyz_catalog_price_observer>
-
</observers>
-
</catalog_product_get_final_price>
-
</events>
-
</global>
-
</config>
Creating the Observer. Create the directory structure – app/code/local/Xyz/Catalog/Model/Price/. Place the php code below in a file by name ‘Observer.php’ in the directory just created.
-
<?php
-
class Xyz_Catalog_Model_Price_Observer
-
{
-
public function __construct()
-
{
-
}
-
/**
-
* Applies the special price percentage discount
-
* @param Varien_Event_Observer $observer
-
* @return Xyz_Catalog_Model_Price_Observer
-
*/
-
public function apply_discount_percent($observer)
-
{
-
$event = $observer->getEvent();
-
$product = $event->getProduct();
-
// process percentage discounts only for simple products
-
if ($product->getSuperProduct() && $product->getSuperProduct()->isConfigurable()) {
-
} else {
-
$percentDiscount = $product->getPercentDiscount();
-
-
if (is_numeric($percentDiscount)) {
-
$today = floor(time()/86400)*86400;
-
$from = floor(strtotime($product->getSpecialFromDate())/86400)*86400;
-
$to = floor(strtotime($product->getSpecialToDate())/86400)*86400;
-
-
if ($product->getSpecialFromDate() && $today < $from) {
-
} elseif ($product->getSpecialToDate() && $today > $to) {
-
} else {
-
$price = $product->getPrice();
-
$finalPriceNow = $product->getData(‘final_price’);
-
-
$specialPrice = $price – $price * $percentDiscount / 100;
-
-
// if special price is negative – negate the discount – this may be a mistake in data
-
if ($specialPrice < 0)
-
$specialPrice = $finalPriceNow;
-
-
if ($specialPrice < $finalPriceNow)
-
$product->setFinalPrice($specialPrice); // set the product final price
-
}
-
}
-
}
-
return $this;
-
}
-
}
NOTE: To get Magento to load the changed local code configuration, one needs to (temporary) disable caching of code configuration. In admin panel, go to System > Cache management and uncheck the Configuration option.
Set the discount on the product. Navigate to the catalog product on the admin login and edit a product. Set the percentage discount for this product (under prices subtab).
Navigate to the product details page on the front end and observe that the new discount has taken effect. To be noted here is that, on all other screens where discounted price is required. An example here is the search results screen, where you would need to add this new attribute to the select query search attributes in method Mage_CatalogSearch_Block_Result→_getProductCollection()
-
$_productCollection= $_productCollection->addAttributeToSelect(‘percent_discount’);
The events list is continually expanding in the Magento core and with extensions you can easily add even more events. In v1.4 there are nearly 300 events compared to 223 in v1.3 and 140 in v1.2. On a Unix like system you can easily determine the available events in your particular build by grepping through the Local, Core and Community folders of your install eg change to the Magento root folder and type
-
grep -rin -B2 -A2 “Mage::dispatchEvent” app/* > events.txt
This will create a file events.txt containing all the events located in the app folder.
If you prefere a shell script check out the blog post on http://www.edmondscommerce.co.uk/blog/magento/magento-events-cheat-sheet-grep-works-for-any-version/
A list of events from earlier releases
|
(From an unknown Wiki user) I found that step 4 was wrong, here is how I got it to work:
Created: local/Company/Module/Model/Observer.php as class Company_Module_Model_Observer
Then I played around with the XML and watched the file it was trying to include (which with the above instructions was looking for classes called Mage_Company). Then I used this XML exactly, changed EVENT_TO_HOOK and ‘Company’ and ‘company’ and ‘module’. Pay attention to case. (Note from the editor: the case of “company_module_model_observer” seems to be wrong. Won’t problably work on case-sensitive file systems).
<events>
<EVENT_TO_HOOK>
<observers>
<module>
<type>singleton</type>
<class>company_module_model_observer</class>
<method>methodToCall</method>
</module>
</observers>
</EVENT_TO_HOOK>
</events>