Today I would like to talk about the problem of overriding templates in a module. Some people doubt that this is a good thing to do. On the other hand others do not find this to be a great problem. It is always possible to highlight the templates which are being used (System / Configuration / Advanced / Developer / Template Settings) and then easily find and fix the required templates in case any problem occurs.
However, this is the only advantage of such a method. At the same time it has plenty of disadvantages which cause many troubles when using this method in practice.
Let me provide you some examples.
The main disadvantage of this method is that the module is installed on a running store and thus can break some page elements by rewriting the custom template with a default one. Unfortunately, such cases are inevitable because when creating themes we have to customize templates in accordance with the required design.
The second disadvantage is that if an unexperienced user is trying to install the module by himself and as a result it rewrites any on his custom templates he might not be able to fix this. A programmer would easily solve the problem by comparing two templates, but this can be a hard task for a common user without any programming skills. And as a results we get a negative feedback.
So, this is what I suggest
Try to avoid overwriting templates. For example, if you need to make small changes you can do this with the help of observers which are our small friends and helpers
core_block_abstract_to_html_before this event is invoked before a template is generated. We already have a block object so here we can add or correct the necessary data. The object is collected in a very simple way
1 2 3 4 5 6 7 |
public function blockToHtmlBefore(Varien_Event_Observer $observer) { $block = $observer->getEvent()->getBlock(); if ($block instanceof the_name_of_the_block_class_we_need) { . . . . . . } } |
But very often we may need a slightly different event.
The core_block_abstract_to_html_after event is called after a template has been generated. Here we can get the object of a block and a ready-to-use HTML, which is also included into the object thus we can modify it.
1 2 3 4 5 6 7 8 9 |
public function blockToHtmlAfter(Varien_Event_Observer $observer) { $block = $observer->getEvent()->getBlock(); if ($block instanceof the_name_of_the_block_class_we_need) { $html = $observer->getEvent()->getTransport()->getHtml(); . . . . . . $transport->setHtml($html); } } |
Some examples:
1. Magemto AjaxCart could serve as a good example. Along with Ajax-based shopping cart page we have also implemented Ajax-based updates on the Wishlist page. However, at that stage we faced the problem on how to find the whole template to update. The problem was that the template had several HTML-blocks one after another. And one of them was without any distinguishing characteristics. We found it not very convenient to update via javascript and also did not want to modify the template to simply add an html tag to wrap all blocks in the template – in this case the module would destroy the design of the theme by replacing the custom template with the default one. So, here we used the method I described above:
1 2 3 4 5 6 7 8 9 10 11 |
public function blockToHtmlAfter(Varien_Event_Observer $observer) { $block = $observer->getEvent()->getBlock(); if ($block instanceof Mage_Wishlist_Block_Customer_Wishlist) { $transport = $observer->getEvent()->getTransport(); $html = '<span class="ajaxcart-wishlist">' . $transport->getHtml() . '</span>'; $transport->setHtml($html); } } |
As you see, this is quite a simple method which significantly reduces the chances to break anything on a Wishlist page.
2. Another example is the module Magento Colors, Sizes and Materials Swatch. Here we decided to use both events: to modify the template which outputs options for a configurable product and to cache the received HTML together with the data about sub-products which are transferred via javasript.
This implementation has also proved to be quite simple.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
public function blockToHtmlBefore(Varien_Event_Observer $observer) { $block = $observer->getEvent()->getBlock(); if ($block instanceof Mage_Catalog_Block_Product_View_Type_Configurable) { $block->addData(array( 'cache_lifetime' => 3600, 'cache_tags' => array(Mage_Catalog_Model_Product::CACHE_TAG), 'cache_key' => Belvg_Colorswatch_Helper_Data::CACHE_KEY . $block->getProduct()->getId() . '_block_' . $block->getBlockAlias(), )); } } public function blockToHtmlAfter(Varien_Event_Observer $observer) { $block = $observer->getEvent()->getBlock(); if ($block instanceof Mage_Catalog_Block_Product_View_Type_Configurable) { $transport = $observer->getEvent()->getTransport(); $html = $transport->getHtml(); if (preg_match_all('/<select name="super_attribute\[(\d+)\]" [^>]*>(.*?)<\/select>/s', $html, $matches, PREG_SET_ORDER)) { $attributeIds = get an array of attributes that need to be changed; foreach ($matches AS $i => $match) { if (in_array($match[1], $attributeIds)) { . . . . . . . Mark only those attributeswhich should be replaced with icons } } $transport->setHtml($html); } } } |