Magento 1.7+: How to use the page layout handle

2020-07-25 09:52发布

问题:

After trying to debug for hours I'm out of ideas and hope for some clarification (I guess I missunderstood a concept at some point).

The backstory: Some base categories need an "overview page" which should be generated automatically from child categories and products. So my approach was to add a sub category to every base category and create a custom page layout which is being used from all these sub categories. For my client this would be very easy to manage in the Magento backend since he would only need to change the value in one drop down. So I created a simple module defining the new page layout. Within the backend I was able to select this one as well.

The module config:

<?xml version="1.0"?>
<config>
    <modules>
        <Company_Layouts>
            <version>0.1.0</version>
        </Company_Layouts>
    </modules>  
    <global>
        <page>
            <layouts>
                <company_category_overview module="page" translate="label">
                    <label>Kategorie-Übersicht</label>
                    <template>page/1column.phtml</template>
                    <layout_handle>company_category_overview</layout_handle>
                </company_category_overview>
            </layouts>
        </page>
    </global>
    <frontend>
        <layout>
            <updates>
                <company_layouts>
                    <file>company_layouts.xml</file>
                </company_layouts>
            </updates>
        </layout>
    </frontend>
</config>

Since these special overview pages require some layout changes I was hoping to reference the layout in a specific layout file (company_layouts.xml)... and here my logic is leaving me:

With <layout_handle>company_category_overview</layout_handle> I was hoping to define a handle which I can use to change the layout only when this specific page template is being used. Exactly this is not the case. My layout updates which are inside the handle company_category_overview are just being ignored.

After digging deeper I realized, it doesn't seem to be my code but more like a general issue. In an old Magento 1.4 installation the page layout handle is being carried to all sites, like page_one_column. In Magento 1.7 and (what I'm using now) 1.8 this is only on the home page the case. I'm using Commerce Bug for debugging. I just tried this with a fresh 1.7 and a freh 1.8 installation.

Is this some concept I don't understand or just a plain bug?

Also, I'm aware that layout updates can be achieved within the backend but this would only be my last option since I feel it's much cleaner having this in a seperate file without the need of copy/pasting such stuff.

回答1:

Is this some concept I don't understand or just a plain bug?

Both? Neither? The information in the <page><layout>...</layout></page> node is used by both the category pages and CMS pages, but each system uses the the information differently, and neither system uses it in a way you'd expect. Here's a rundown on how category pages use this information.

The category page is rendered by the following controller action

#File: app/code/core/Mage/Catalog/controllers/CategoryController.php
public function viewAction()
{
    ...
}

This controller action doesn't have the standard loadLayout and renderLayout method calls. Instead, there's a lot of extra code in this method for adding layout handles and doing things between generating the blocks and rendering the final layout. The section we're interested in is this

$design = Mage::getSingleton('catalog/design');
$settings = $design->getDesignSettings($category);

#...other stuff we don't care about...

if ($settings->getPageLayout()) {
    $this->getLayout()->helper('page/layout')->applyTemplate($settings->getPageLayout());
}

When you save a category with your "Page Layout" in the Custom Design tab, the getPageLayout method call above should return company_category_overview. On category pages, Magento doesn't use this to apply a handle, instead it passes the values to the applyTemplate method. Here's that method in full.

#File: app/code/core/Mage/Page/Helper/Layout.php
public function applyTemplate($pageLayout = null)
{
    if ($pageLayout === null) {
        $pageLayout = $this->getCurrentPageLayout();
    } else {
        $pageLayout = $this->_getConfig()->getPageLayout($pageLayout);
    }

    if (!$pageLayout) {
        return $this;
    }

    if ($this->getLayout()->getBlock('root') &&
        !$this->getLayout()->getBlock('root')->getIsHandle()) {
            // If not applied handle
            $this->getLayout()
                ->getBlock('root')
                ->setTemplate($pageLayout->getTemplate());
    }

    return $this;
}

The pertinent parts are this line,

$pageLayout = $this->_getConfig()->getPageLayout($pageLayout);

which will load the information from your configuration

<label>Kategorie-Übersicht</label>
<template>page/1column.phtml</template>
<layout_handle>company_category_overview</layout_handle>

as a Varien_Object. Then, it will use this information to apply a template to the root block.

$this->getLayout()
->getBlock('root')
>setTemplate($pageLayout->getTemplate());

So, for category pages, the information in the <layout_handle/> node is never used. That's why your layout updates aren't being applied — Magento actually applies your handle.