<update /> 指令让您有了正确的想法。只需将其放在管理员中您类别的Custom Layout Update 字段中,该类别应应用该布局句柄。您仍然可以使用Page Layout 字段设置页面模板。
您需要使用 <update /> 指令显式指定布局句柄的原因是因为 Magento 的类别控制器不使用 layout_handle 节点,而 Magento 的其他部分,如 Magento 的 CMS 页面控制器,使用它。
比如我们看Mage_Cms_PageController,它负责渲染一个CMS页面:
public function viewAction()
{
$pageId = $this->getRequest()
->getParam('page_id', $this->getRequest()->getParam('id', false));
if (!Mage::helper('cms/page')->renderPage($this, $pageId)) {
$this->_forward('noRoute');
}
}
让我们深入挖掘,看看Mage_Cms_Helper_Page::renderPage(),它调用了Mage_Cms_Helper_Page::_renderPage():
protected function _renderPage(Mage_Core_Controller_Varien_Action $action, $pageId = null, $renderLayout = true)
{
$page = Mage::getSingleton('cms/page');
/* ... */
if ($page->getRootTemplate()) {
$handle = ($page->getCustomRootTemplate()
&& $page->getCustomRootTemplate() != 'empty'
&& $inRange) ? $page->getCustomRootTemplate() : $page->getRootTemplate();
$action->getLayout()->helper('page/layout')->applyHandle($handle);
}
/* ... */
if ($page->getRootTemplate()) {
$action->getLayout()->helper('page/layout')
->applyTemplate($page->getRootTemplate());
}
/* ... */
}
我们在这里看到两个重要的逻辑。
首先,_renderPage() 调用 $action->getLayout()->helper('page/layout')->applyHandle($handle)。如果您深入挖掘,您会发现 Mage_Page_Helper_Layout::applyHandle() 负责应用配置 XML 定义的适当 layout_handle:
public function applyHandle($pageLayout)
{
$pageLayout = $this->_getConfig()->getPageLayout($pageLayout);
if (!$pageLayout) {
return $this;
}
$this->getLayout()
->getUpdate()
->addHandle($pageLayout->getLayoutHandle());
return $this;
}
其次,_renderPage() 调用 $action->getLayout()->helper('page/layout')->applyTemplate($page->getRootTemplate())。与applyHandle() 类似,applyTemplate() 应用实际的页面模板。
因此,这就解释了为什么在涉及 CMS 页面时,您可以依赖配置 XML 中定义的 layout_handle。现在,让我们找出为什么它对类别不可靠。
我们看Mage_Catalog_CategoryController::viewAction(),它负责显示一个分类页面:
public function viewAction()
{
if ($category = $this->_initCatagory()) {
$design = Mage::getSingleton('catalog/design');
$settings = $design->getDesignSettings($category);
/* ... */
// apply custom layout update once layout is loaded
if ($layoutUpdates = $settings->getLayoutUpdates()) {
if (is_array($layoutUpdates)) {
foreach($layoutUpdates as $layoutUpdate) {
$update->addUpdate($layoutUpdate);
}
}
}
/* ... */
// apply custom layout (page) template once the blocks are generated
if ($settings->getPageLayout()) {
$this->getLayout()->helper('page/layout')->applyTemplate($settings->getPageLayout());
}
/* ... */
}
elseif (!$this->getResponse()->isRedirect()) {
$this->_forward('noRoute');
}
}
剥离所有默认布局逻辑,我们只剩下两部分:
// apply custom layout update once layout is loaded
if ($layoutUpdates = $settings->getLayoutUpdates()) {
if (is_array($layoutUpdates)) {
foreach($layoutUpdates as $layoutUpdate) {
$update->addUpdate($layoutUpdate);
}
}
}
这将通过类别的布局更新(如管理员中的 Custom Layout Update 字段中所定义)并应用它们。这就是使用 <update handle="some_handle" /> 有效的原因。
还有……
// apply custom layout (page) template once the blocks are generated
if ($settings->getPageLayout()) {
$this->getLayout()->helper('page/layout')->applyTemplate($settings->getPageLayout());
}
这将应用自定义页面模板,类似于 CMS 页面逻辑的做法,使用 Mage_Page_Helper_Layout::applyTemplate()。
现在,发现有什么遗漏了吗?
是的,类别控制器不会调用 Mage_Page_Helper_Layout::applyHandle() 来应用配置 XML 中定义的 layout_handle。这意味着您可以使用 Page Layout 字段为类别指定特定的页面模板,但不会应用模板随附的 layout_update!
希望这可以弄清楚为什么您的 layout_update 节点没有像您期望的那样在类别页面上得到使用。 Magento 充满了像这样的奇怪行为和不一致:)