How do you set the sort order for event observers in Magento?

Scruffy Paws picture Scruffy Paws · Apr 10, 2013 · Viewed 12.7k times · Source

I have created an observer on the catalog_product_save_after event, but it seems to be getting called before the catalogrule observer that runs the applyAllRulesOnProduct() method. I need to call mine after applyAllRulesOnProduct() runs. How is the order for these observers chosen?

Answer

Alan Storm picture Alan Storm · Apr 10, 2013

The answer, like many in Magento, is complicated. There's also two possible problems your specific situation might relate to. This is going to be long — skip to the end for the contextless short version.

Module Loading Order

There is not way to explicitly set an observer sort order. Magento will run through the events in the order they've been merged into the global configuration. So, while you can't control the order of event specifically, you can control the order Magento loads and merges modules in by using the <depends/> tag in your app/etc/modules XML declaration file.

For example, in the Mage_Api2.xml file

<!-- File: app/etc/modules/Mage_Api2.xml -->
<config>
    <modules>
        <Mage_Api2>
            <active>true</active>
            <codePool>core</codePool>
            <depends>
                <Mage_Core />
                <Mage_Oauth />
            </depends>
        </Mage_Api2>
    </modules>
</config>

the author has indicated that the Mage_Api2 module depends on the Mage_Core and Mage_Oauth modules. This means Mage_Api2's config.xml file will be merged after the config.xml files of Mage_Core and Mage_Oauth. This means that events defined in Mage_Api2 will run after events defined in Mage_Core and Mage_Oauth.

Lacking a <depends/> node, the rules for module loading are

  1. All core modules are loaded before non-core modules

  2. The remaining modules are loaded alphabetically.

It would be good form to have your module depend on the Mage_CatalogRule module (where the applyAllRulesOnProduct observer method is defined). However, it should not be necessary, as all core modules are loaded before non-core modules.

That's because there's another factor in the order event observer methods are run in.

Area Order

In addition to module order, you'll also need to consider which area your event observer is defined in. That is, when you create an event observer in Magento, you drop in some config.xml that looks like this

<config>
    <!-- ... -->
    <global>
        <!-- ... -->
        <events>
            <catalog_product_save_after>
                <observers>
                    <abc_abc>
                        <class>abc_abc/observer</class>
                        <method>test</method>
                    </abc_abc>
                </observers>
            </catalog_product_save_after>
        </events>       
    </global>
</config>

In the above example, this event observer has been defined in the global area (because it's inside the <global/> node). This means the observer will run in both the frontend and adminhtml areas of Magento. However, it's also possible to restrict the area your event is run in. For example, the catalogrule event you mentioned is defined in the adminhtml area

<!-- #File: app/code/core/Mage/CatalogRule/etc/config.xml -->
<config>
    <!-- ... -->
    <adminhtml>
        <!-- ... -->
        <events>
            <!-- ... -->
            <catalog_product_save_after>
                <observers>
                    <catalogrule>
                        <class>catalogrule/observer</class>
                        <method>applyAllRulesOnProduct</method>
                    </catalogrule>
                </observers>
            </catalog_product_save_after>
        </events>
    </adminhtml>
</config>

This means this event observer will only run in Magento's backend adminhtml area. In other words, it only runs when you save an event in the backend admin console.

This is where I think your problem is, because in modern versions of Magento (and possibly the old ones), event observers from the <global/> node always run before event observers in the <adminhtml/> node. My guess is your event is in the <global/> node. Try moving it to the <adminhtml/> node.

The Short Version: Make sure your module <depends/> on the Mage_CatalogRule module, and move your event observer configuration to the <adminhtml/> node in your module's config.xml.