我有一个我编写的特色产品模块,它在页面上放置一个自定义块,其中列出了与块中定义的任何属性相匹配的产品。最初我通过在CMS页面的“内容”部分添加{{block...}}
行来实现它。这很好,但我没有得到寻呼机。所以,我通过从Content部分删除{{block...}}
行并将XML添加到Layout Update XML部分来解决这个问题:
<reference name="content">
<block type="cms/block" name="product_list_top" />
<block type="vps_featured/list" name="vps_featured_list" template="catalog/product/sale_list.phtml">
<block type="catalog/product_list_toolbar" name="product_list_toolbar" template="catalog/product/list/toolbar.phtml">
<block type="page/html_pager" name="product_list_toolbar_pager"/>
</block>
<action method="setToolbarBlockName"><name>product_list_toolbar</name></action>
<action method="setAttributeName"><name>my_attribute</name></action>
</block>
</reference>
这也很有效。然后我决定,因为这个块的实例太多了,如果我将XML文件添加到我的主题的布局文件夹中并将此代码放在那里,那将会更加清晰。然后,在布局更新部分,我可以简单地改为:
<reference name="vps_featured_list">
<action method="setAttributeName"><name>other_attribute</name></action>
</reference>
因此,我创建了一个名为vps_featured.xml
的文件,并将其添加到其中:
<layout version="0.1.0">
<default>
<reference name="content">
<block type="cms/block" name="product_list_top" />
<block type="vps_featured/list" name="vps_featured_list" template="catalog/product/sale_list.phtml">
<block type="catalog/product_list_toolbar" name="product_list_toolbar" template="catalog/product/list/toolbar.phtml">
<block type="page/html_pager" name="product_list_toolbar_pager" />
</block>
<action method="setToolbarBlockName"><name>product_list_toolbar</name></action>
</block>
</reference>
</default>
</layout>
我的自定义功能模块的config.xml
中引用了此布局更新XML文件。我天真地认为vps_featured.xml
只有当我的VPS特色块在页面上时才会被合并到页面布局中,这只会发生在特殊CMS页面上的这几个实例中。显然事实并非如此。这打破了其他每一页,我猜是因为它覆盖了默认句柄。
因此,这引出了我的问题#1:布局xml文件何时包含在页面布局中?它们是否用于所有页面,无论是否实际使用引用它们的模块?
然后我决定尝试添加一个新的布局句柄,我可以在我的CMS页面中引用它。我修改了布局XML文件,因此主要部分位于<vps_featured_list>
标记内,而不是<default>
标记内。这使其他页面恢复了生机,但当然,我的CMS页面不再有效,因为那些页面上没有使用布局更新句柄。我尝试将<update handle="vps_featured_list" />
添加到CMS页面的布局更新XML部分,但这不起作用(我没想到)。
所以这让我想到了问题#2:实现这个目标的正确方法是什么?
这听起来不应该是这么困难,但显然我错过了一些东西。我已经阅读了所有我可以在布局上找到的内容,但它们总是很简单的例子,例如“将它添加到每个产品页面”。我不希望在每个cms页面添加一些东西......只是其中一些。我是否坚持使用布局更新XML部分来处理相关的CMS页面?我觉得必须有一个更清洁的方式。
谢谢,
布赖恩
答案 0 :(得分:17)
节点<default/>
称为“布局句柄”。每个进入Magent的请求都会生成许多这样的句柄。查看Layout tab on the Commerce Bug demo网站,了解生成的各种句柄。
Magento将所有布局XML文件合并到一个称为包布局的巨树中。然后,句柄确定哪些Layout XML Update片段用于特定请求。这些片段组合到页面布局中。正如您所知,<default/>
句柄始终添加,这就是为什么要对系统中的每个网站进行加密。
坏消息是,虽然有一个CMS页面的句柄,(<cms_page_view />
),它仍然是一个全有或全无的事情。您可以向所有 CMS页面添加内容,但不能添加特定的CMS页面。所以,是的,CMS管理员的布局更新XML部分是“正确”的方式来做你想要的。
好消息是,你可以采取两种方法,比你迄今为止提出的更清洁。 首先,您可以通过在XML文件中定义自己的句柄来稍微清理一下,然后使用特殊的Layout XML命令来包含该句柄。
在XML中,在自定义句柄中添加Layout Update XML片段。
<layout version="0.1.0"> <my_fancy_pants_unique_handle_name_which_doesnt_conflict_with_existing_names> <reference name="content"> <block type="cms/block" name="product_list_top" /> <block type="vps_featured/list" name="vps_featured_list" template="catalog/product/sale_list.phtml"> <block type="catalog/product_list_toolbar" name="product_list_toolbar" template="catalog/product/list/toolbar.phtml"> <block type="page/html_pager" name="product_list_toolbar_pager" /> </block> <action method="setToolbarBlockName"><name>product_list_toolbar</name></action> </block> </reference> </my_fancy_pants_unique_handle_name_which_doesnt_conflict_with_existing_names> </layout>
然后在CMS管理员中,为您想要的页面添加以下布局更新XML
<update handle="my_fancy_pants_unique_handle_name_which_doesnt_conflict_with_existing_names" />
Magento允许布局更新XML片段为请求添加其他句柄。这就是你上面所做的。这样可以清理一些事情,如果你想改变一些XML,那么就有一个集中的地方。
更新:事实证明&lt; update /&gt;命令只能 从布局XML文件本身使用。加载CMS页面的布局更新XML的代码与加载和处理XML文件更新的代码不同。 Magento将字面在CMS表单中添加任何内容作为布局更新。它不会为递归更新处理它。因此,将此类内容添加到local.xml
将起作用
<mock_product_list>
<reference name="head">
<label>Mock Product List</label>
<action method="addItem"><type>skin_js</type><name>js/sw/wall.js</name></action>
</reference>
</mock_product_list>
<cms_page_view>
<update handle="mock_product_list" />
</cms_page_view>
但是,您无法通过CMS管理员应用更新直接执行此操作。活到老,学到老。
所有这一切,小部件方法可能仍然可行,并且可以替代上述方法。
使用自定义块类创建自定义模块
块类不呈现HTML
块类包含一个名为“addFooToLayout”的单个方法
然后,在您的CMS页面中,添加此类更新
<block type="yourmodule/yourblock" name="unique_name" alias="unique_name">
<action method="addFooToLayout" />
</block>
然后在您的块定义中
public addFooToLayout()
{
$layout = Mage::getSingleton('core/layout');
$head = $layout->getBlock('head');
$head->addItem('skin_js','js/sw/wall.js');
//etc...
}
类似应该的工作并且更清晰一些(取决于您要添加多少布局更新XML)。但是,我没有对它进行过测试,而且我的可信度在这个问题上受到了影响,所以买家要小心。
第二种方法是create a single widget包含您要添加到页面的内容,然后使用窗口小部件实例管理员将该窗口小部件添加到特定页面上的特定块。这些链接应该让你开始。
最后,冒着成为先令的风险,我最近自我出版a book on Magento Layouts,深入探讨了这些问题。如果您有兴趣了解整个系统的工作原理,那值得花时间。
答案 1 :(得分:3)
然而,这个问题已经很老了,我通过谷歌找到了它,并希望为将来阅读这篇文章的人添加一些信息。
昨天当我读到这个问题和答案,以及this和this帖子时,我非常确定仅仅为了覆盖/扩展CMS页面布局句柄是不可能的或者很难具体页面。这导致我开发了一个小扩展,它在任何特定页面中注入任何自定义布局句柄。我将很快用公共链接更新这篇文章。
但后来我发现实际上可以为CMS页面创建一个新模板,并为该模板分配任何自定义布局句柄,例如,请参阅Marius的this question and answer。以下是该代码示例的重要部分:
<global>
<page>
<layouts>
<lookbook module="page" translate="label">
<label>Lookbook</label>
<template>page/1column-lookbook.phtml</template>
<layout_handle>lookbook</layout_handle>
</lookbook>
</layouts>
</page>
</global>
将任何自定义布局句柄注入任何页面都很容易,并且只对使用此模板和自定义布局句柄的页面执行任何操作。我希望我之前知道这一点,希望这篇文章能节省一些时间。