Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Magento use own handle in widgets doesn't work

Tags:

widget

magento

I find that I can add own layout handles with this script:

$this->getLayout()->getUpdate()->addHandle('myhandle');

Then I checked Alan Storm Layout viewers: http://alanstorm.com/2005/projects/MagentoLayoutViewer.tar.gz

?showLayout=handles

Handles For This Request

  1. default
  2. cms_page
  3. STORE_default
  4. THEME_frontend_default_default
  5. cms_index_index
  6. page_two_columns_left
  7. customer_logged_out
  8. myhandle

There was my handle, but my custom layout xml didn't used.

Here is my xml:

<?xml version="1.0"?>
<layout version="0.1.0">

    <myhandle>
        <reference name="head">
          <action method="addJs"><script>test/your.js</script></action>
        </reference>
    </myhandle>
</layout>

This works fine, so the xml file is loaded:

<?xml version="1.0"?>
<layout version="0.1.0">

    <default>
        <reference name="head">
          <action method="addJs"><script>test/your.js</script></action>
        </reference>
    </default>
</layout>

What's wrong? Why doesn't work this solution?

If it's not the right way, how can I add custom css and javascript for the page where the widget used?

Update: Here is something which maybe get close to the solution:

If I add this code after I add the new handle to the page:

$this->getLayout()->getUpdate()->fetchPackageLayoutUpdates('myhandle');
$this->getLayout()->generateXml();

After this the "index.php?showLayout=page" call writes handle code in the xml, but the page don't use it.

like image 618
Roland Soós Avatar asked Jan 22 '23 15:01

Roland Soós


2 Answers

The long and the short of this is you really don't want to inject layout handles this way. It gets pretty complicated (complicated enough that I can't follow it all the way down quickly enough for a Stack Overflow answer), but

  1. If you add your handle before you call $this->loadLayout() from a controller it's too soon.

  2. If you add your handle after you call $this->loadLayout() it's too late.

Here's an experiment, try modifying the loadLayout method in the base Action Controller

File: app/code/core/Mage/Core/Controller/Varien/Action.php
public function loadLayout($handles=null, $generateBlocks=true, $generateXml=true)
{    
    // if handles were specified in arguments load them first
    if (false!==$handles && ''!==$handles) {
        $this->getLayout()->getUpdate()->addHandle($handles ? $handles : 'default');
    }

    //YOUR NEW CALL HERE
    $this->getLayout()->getUpdate()->addHandle('myhandle');         

    ...

This should work and apply your layout. Now, doing this in production would be a Bad Idea, I only mention it to show you that handles need to be added at a very specific time layout rendering process. As an end-programmer, it's not really your job to insert layout handles.

The layout system is intended to be a layer that sits between designers and raw PHP system code. Since you're clearly able to write PHP code, I'd look into just directly injecting your javascript into the head block pre-render.

    //from a controller, but could be modified to be used elsewhere
    //also pseudo code
$this->getLayout()->getBlock('header')->append(
    $this->getLayout()
    ->createBlock('core/text', 'some-unique-name')
    ->setText('<script type="text/javascript" src="/foo/baz/bar.js"></script>')
);
like image 177
Alan Storm Avatar answered Jan 28 '23 02:01

Alan Storm


If you want to add a brand new handle, the best solution probably is to add the handle with an observer. If you have a module that has its own URL, it already has it's unique handle.

Create a module that calls the correct handle.

Create your etc/config.xml

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <modules>
        <Ho_AttributeSetHandle>
            <version>0.1.0</version>
        </Ho_AttributeSetHandle>
    </modules>
    <global>
        <events>
            <controller_action_layout_load_before>
                <observers>
                    <attributesethandle>
                        <class>Ho_AttributeSetHandle_Model_Observer</class>
                        <method>addAttributeSetHandle</method>
                    </attributesethandle>
                </observers>
            </controller_action_layout_load_before>
        </events>
    </global>
</config>

In my case the code for Model/Observer.php:

<?php
class Ho_AttributeSetHandle_Model_Observer
{
    /**
     * Converts attribute set name of current product to nice name ([a-z0-9_]+).
     * Adds layout handle PRODUCT_ATTRIBUTE_SET_<attribute_set_nicename> after
     * PRODUCT_TYPE_<product_type_id> handle
     *
     * Event: controller_action_layout_load_before
     *
     * @param Varien_Event_Observer $observer
     */
    public function addAttributeSetHandle(Varien_Event_Observer $observer)
    {
        $product = Mage::registry('current_product');

        /**
         * Return if it is not product page
         */
        if (!($product instanceof Mage_Catalog_Model_Product)) {
            return;
        }

        $attributeSet = Mage::getModel('eav/entity_attribute_set')->load($product->getAttributeSetId());

        /* Convert attribute set name to alphanumeric + underscore string */
        $niceName = strpos($product->formatUrlKey($attributeSet->getAttributeSetName()), '-') !== FALSE
                    ? str_replace('-', '_', $product->formatUrlKey($attributeSet->getAttributeSetName()))
                    : $product->formatUrlKey($attributeSet->getAttributeSetName());
        $niceName = strpos($niceName, ' ') !== FALSE ? str_replace(' ', '_', $product->formatUrlKey($niceName)) : $niceName;

        /* @var $update Mage_Core_Model_Layout_Update */
        $update = $observer->getEvent()->getLayout()->getUpdate();
        $handles = $update->getHandles(); // Store all handles in a variable
        $update->resetHandles(); // Remove all handles

        /**
         * Rearrange layout handles to ensure PRODUCT_ATTRIBUTE_SET_<attribute_set>
         * handle is added last
         */
        foreach ($handles as $handle) {
            $update->addHandle($handle);
            if ($handle == 'PRODUCT_TYPE_' . $product->getTypeId()) {
                $update->addHandle('PRODUCT_ATTRIBUTE_SET_' . $niceName);
            }
        }
    }
}

Dont forget to create a app/etc/modules/Ho_AttributeSetHandle.xml:

<config>
    <modules>
        <Ho_AttributeSetHandle>
            <active>true</active>
            <codePool>local</codePool>
        </Ho_AttributeSetHandle>
    </modules>
</config>  
like image 20
Paul Hachmang Avatar answered Jan 28 '23 01:01

Paul Hachmang