4

So I'm trying to accomplish the following: I want to add a third view mode to the product listing (I called it "gridx5") using event observers.

I originally did it via Blocks rewrites and it was working fine but I want to do it via observers now as it's conflicting with 3rd party modules depending on which website I install the module.

So here it what I've got:

config.xml

<global>
   <events>
            <core_block_abstract_to_html_before>
                <observers>
                    <extendedcatalog_toolbar_modes>
                        <type>singleton</type>
                        <class>extendedcatalog/observer</class>
                        <method>addToolbarModes</method>
                    </extendedcatalog_toolbar_modes>
                </observers>
            </core_block_abstract_to_html_before>
        </events>
</global>

In my observer, I've got this:

public function addToolbarModes(Varien_Event_Observer $observer)
    {
        $block = $observer->getEvent()->getBlock();

        if ($block instanceof Mage_Catalog_Block_Product_List) {
            switch (Mage::getStoreConfig('catalog/frontend/list_mode')) {
                case 'grid':
                    $block->setModes(array('grid' => $block->__('Grid')));
                    break;

                case 'gridx5':
                    $block->setModes(array('gridx5' => $block->__('Grid x5')));
                    break;

                case 'list':
                    $block->setModes(array('list' => $block->__('List')));
                    break;

/*** Etc for the other cases ***/
            }
        }
    }

So everything above works, but according to my tests, here is what happens. So basically in _beforeToHtml function of the Mage_Catalog_Block_Product_List block, you've got this part of code:

if ($modes = $this->getModes()) {
            $toolbar->setModes($modes);
        }

This is where this block is supposed to set the modes of the toolbar block. Then in the setModes of the Mage_Catalog_Block_Product_List_Toolbar block:

public function setModes($modes)
    {
        if(!isset($this->_availableMode)){
            $this->_availableMode = $modes;
        }
        return $this;
    }

HERE is the problem, by default the $_availableMode is an empty array. But that means the condition above is ALWAYS true right ?

EDIT based on questions asked:

  • Why using the setModes function on Mage_Catalog_Block_Product_List_Toolbar does not work:

In the _construct() method, the _availableModes is supposed to be set with a value like this:

switch (Mage::getStoreConfig('catalog/frontend/list_mode')) {
            case 'grid':
                $this->_availableMode = array('grid' => $this->__('Grid'));
                break;

            case 'list':
                $this->_availableMode = array('list' => $this->__('List'));
                break;

            case 'grid-list':
                $this->_availableMode = array('grid' => $this->__('Grid'), 'list' =>  $this->__('List'));
                break;

            case 'list-grid':
                $this->_availableMode = array('list' => $this->__('List'), 'grid' => $this->__('Grid'));
                break;
        }

However, as my mode value is "gridx5" is not listed in the cases of the switch, the variable keep its original value defined at the top of the file, so an empty array.

Thus when I use the setModes method, the variable is considered as set so my value is automatically skipped with the code below:

public function setModes($modes)
    {
        if(!isset($this->_availableMode)){
            $this->_availableMode = $modes;
        }
        return $this;
    }

So three questions here (EDIT: added the answers):

  • am I doing something wrong ? No, definitely was the good idea.

  • shouldn't Magento use if(empty()) instead of if (!isset()) ? Yes and No, see below.

  • can I do it WITHOUT rewriting the toolbar block NOR rewriting the setModes function ? It is actually not possible to add a new mode without rewriting the toolbar block.

Reasons behind that is the following code in the toolbar block, it is too closed to let anyone add a new mode without rewriting everything. That's why Magento uses !isset because of empty, there is no reason to use the least because no one can add a mode using the setModes.

Below is the other parts of the code (does not include the construct function as already pasted above) that I found too strict to let someone add a mode via observer:

    public function getDefaultPerPageValue()
    {
        if ($this->getCurrentMode() == 'list') {
            if ($default = $this->getDefaultListPerPage()) {
                return $default;
            }
            return Mage::getStoreConfig('catalog/frontend/list_per_page');
        }
        elseif ($this->getCurrentMode() == 'grid') {
            if ($default = $this->getDefaultGridPerPage()) {
                return $default;
            }
            return Mage::getStoreConfig('catalog/frontend/grid_per_page');
        }
        return 0;
    }

public function getAvailableLimit()
    {
        $currentMode = $this->getCurrentMode();
        if (in_array($currentMode, array('list', 'grid'))) {
            return $this->_getAvailableLimit($currentMode);
        } else {
            return $this->_defaultAvailableLimit;
        }
    }
  • I think the only solution I've got without rewriting the toolbar block is to copy it to local and rewrite the setModes function. Ugly but that's the only solution I come up with. – Raphael at Digital Pianism Aug 11 '15 at 10:38
2

Ugh, the core_block_abstract_to_html_before event. It's intentionally non-specific to prevent improper view hacks via the event system, but your use case seems acceptable. Given that it's fired for every single block render, it's correct that you are (1) using a singleton observer and (2) some refining logic. However, based on this statement...

• I did try to use the setModes function of the toolbar block

...your block type logic...

if ($block instanceof Mage_Catalog_Block_Product_List) { /*...*/}

...is incorrect for the Mage_Catalog_Block_Product_List_Toolbar block, which directly extends Mage_Core_Block_Template. You can try your latest approach using Mage_Catalog_Block_Product_List_Toolbar as a test.

Pretty sure there are different/better ways to do this, but I will give you this for now.

  • Thanks Ben, you'll find the detailed explanation about why using the toolbar block setModes method didn't work, thanks for the help – Raphael at Digital Pianism Aug 11 '15 at 6:49
1

You are making a wrong assumption. In the _construct() method of Toolbar block, $this->_availableMode array gets set from what you have in configuration. So, when you arrive at that setModes() method call, your variable is already present. The condition is applied for a fail safe in case something happens with the admin config.

The reason behind not using empty would be that empty() doesn't generate any warnings if something wrong happens, so you'll have problems while debugging. BUT it's just a guess based upon my knowledge, might be wrong.

And, setModes() method is defined inside Toolbar block, and you are trying to call it for List block. You'll need to first get the Toolbar block from within the List block

$toolbar = $this->getToolbarBlock();
$toolbar->setModes($modes);

, and then set Modes on it.

  • Thanks for your answer. First I have tried to do it using the toolbar block instead of the list block but I didn't work. I used the list block because in the beforeToHtml() function of the list block there is a part of the code (see in the OP) where it does set the modes of the toolbar block, I assumed it was the right way of doing it. Plus when I log the _availableModes variable of the toolbar block, I always get an empty array because my mode is not listed in the original _construct() method. – Raphael at Digital Pianism Aug 10 '15 at 17:01
  • 1
    Let me try it my side. – Prateek Aug 10 '15 at 17:11
1

I answer my own question:

  • am I doing something wrong ? No, definitely was the good idea.

  • shouldn't Magento use if(empty()) instead of if (!isset()) ? Yes and No, see details in OP.

  • can I do it WITHOUT rewriting the toolbar block NOR rewriting the setModes function ? It is actually not possible to add a new mode without rewriting the toolbar block.

See the details in the OP.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.