Пользовательские макеты для catalog_category_view в Magento

Мне нужно иметь возможность использовать разные макеты для разных категорий, выбранных на вкладке Пользовательский дизайн в категории и в поле Макет страницы.

Я использую Magento 1.9.1.0.

В моем config.xml у меня есть:

<global>
    <page>
        <layouts>
            <module_home module="page" translate="label">
                <label>Module Home</label>
                <template>page/base.phtml</template>
                <layout_handle>module_home</layout_handle>
            </module_home>

            <module_categories module="page" translate="label">
                <label>Module Categories</label>
                <template>page/base.phtml</template>
                <layout_handle>module_categories</layout_handle>
            </module_categories>
        </layouts>
    </page>
    ...

И в моем файле layouts.xml у меня есть:

<default>
    <reference name="root">...</reference>
</default>
<module_home translate="label">...</module_home>
<module_categories translate="label">...</module_categories>

Когда я выбираю макет Категории модуля от администратора категории, я не получаю изменений для обработчика module_categories, только те, которые установлены на <default>.

Если я заставлю это так:

<catalog_category_view>
    <update handle="module_categories" />
</catalog_category_view>

Я получаю изменения, но мне нужно несколько обработчиков, выбранных в качестве макетов в админке.

Может я что-то не так делаю? Не удалось найти пример, как это сделать, может быть, вы можете указать где-нибудь? Спасибо!


person PabloRosales    schedule 30.01.2015    source источник


Ответы (1)


Вы правильно поняли директиву <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() отвечает за применение соответствующего layout_handle, как определено в XML конфигурации:

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() применяет фактический шаблон страницы.

Таким образом, это объясняет, почему вы можете полагаться на layout_handle, как определено в XML конфигурации, когда речь идет о страницах CMS. Теперь давайте выясним, почему он не надежен для категорий.

Давайте посмотрим на 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() для применения layout_handle, как определено в XML конфигурации. Это означает, что вы можете использовать поле Page Layout для присвоения категории определенного шаблона страницы, но ваш layout_update, сопровождающий шаблон, не будет применен!

Надеюсь, это прояснит, почему ваш узел layout_update не используется на странице категории так, как вы ожидаете. Magento полон странного поведения и подобных несоответствий :)

person Agop    schedule 31.01.2015
comment
Спасибо за помощь. Я не понимаю, почему мне нужно установить дескриптор обновления в Custom Layout Update, если я уже выбрал тот же дескриптор, что и макет в Page Layout? Может быть, я чего-то не понимаю в том, как работает Magento? - person PabloRosales; 31.01.2015
comment
Я отредактировал свой ответ и добавил дополнительные подробности о том, почему ваш layout_handle не применяется так, как вы себе это представляете. Надеюсь, это поможет прояснить ситуацию! :) - person Agop; 31.01.2015
comment
Очень ценю время, чтобы написать это, поскольку теперь я понимаю некоторые вещи. Действительно, это не то, что я ожидал от Magento. Спасибо! - person PabloRosales; 01.02.2015