I find that I can add own layout handles with this script:
开发者_JAVA百科$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
- default
- cms_page
- STORE_default
- THEME_frontend_default_default
- cms_index_index
- page_two_columns_left
- customer_logged_out
- 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.
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
If you add your handle before you call $this->loadLayout() from a controller it's too soon.
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>')
);
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>
精彩评论