Как правильно выполнять обновления макета на страницах CMS?

#layout #magento

#макет #magento

Вопрос:

У меня есть модуль featured products, который я написал, который помещает пользовательский блок на страницу со списком продуктов, соответствующих любому атрибуту (ам), который я определил в блоке. Изначально я заставлял это работать, добавляя {{block...}} строку в раздел содержимого страницы CMS. Это сработало нормально, но я не получал пейджер. Итак, я исправил это, удалив {{block...}} строку из раздела содержимого и добавив XML в раздел 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-файл в папку layout для моей темы и поместил туда этот код. Тогда в разделе обновления макета я мог бы просто использовать это вместо:

 <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>
  

На этот XML-файл обновления макета была ссылка в config.xml для моего пользовательского модуля featured. Я наивно предполагал, что vps_featured.xml это будет включено в макет страницы только тогда, когда на странице будет мой VPS Featured block, что произойдет только в этих нескольких случаях на специальных страницах CMS. Очевидно, это не тот случай. Это нарушало работу всех остальных страниц, я думаю, потому что это переопределяло дескриптор по умолчанию.

Итак, это подводит меня к вопросу № 1: Когда XML-файлы макета включаются в макет страницы? Используются ли они для ВСЕХ страниц, независимо от того, действительно ли используется модуль, ссылающийся на них?

Затем я решил попробовать добавить новый дескриптор макета, на который я мог бы ссылаться, когда захочу, на своих страницах CMS. Я изменил свой XML-файл макета, чтобы основная часть находилась внутри <vps_featured_list> тегов, а не <default> самих тегов. Это вернуло к жизни другие страницы, но, конечно, мои страницы CMS больше не работали, потому что этот дескриптор обновления макета не используется на этих страницах. Я попытался добавить <update handle="vps_featured_list" /> в раздел XML «Обновление макета» страницы CMS XML, но это не сработало (я этого не ожидал).

Итак, это подводит меня к вопросу № 2: каков правильный способ добиться этого?

Не похоже, что это должно быть так сложно, но, очевидно, я чего-то не понимаю. Я прочитал все, что смог найти о макетах, но это всегда простые примеры, например «добавляйте это на страницу КАЖДОГО продукта». Я не хочу, чтобы что-то добавлялось на КАЖДУЮ страницу cms…лишь некоторые из них. Я застрял в использовании XML-раздела обновления макета для рассматриваемых страниц CMS? Я чувствую, что должен быть более чистый способ.

Спасибо,

Брайан

Ответ №1:

Узел <default/> — это нечто, называемое «дескриптором макета». Каждый запрос в Magent генерирует несколько таких дескрипторов. Перейдите на вкладку Layout на демонстрационном сайте Commerce Bug Bug demo, чтобы получить представление о типах создаваемых дескрипторов.

Magento объединяет все XML-файлы макета в одно гигантское дерево, называемое макетом пакета. Затем дескрипторы определяют, какие фрагменты обновления XML макета используются для конкретного запроса. Эти фрагменты объединяются в макет страницы. Как вы интуитивно поняли, <default/> дескриптор всегда добавляется, вот почему вы загружаете каждый сайт в своей системе.

Плохая новость в том, что, хотя для страниц CMS есть дескриптор ( <cms_page_view /> ), это все равно будет вопросом «все или ничего». Вы могли бы добавить что-нибудь на все страницы CMS, но не на конкретные страницы CMS. Итак, раздел XML «Обновление макета» администратора CMS — это «правильный» способ сделать то, что вы хотите.

Хорошая новость в том, что вы можете воспользоваться двумя подходами, которые чище того, что вы предлагали до сих пор. Сначала вы можете немного почистить вещи, определив свой собственный дескриптор в вашем XML-файле, а затем использовать специальную команду Layout XML для включения этого дескриптора.

В вашем XML добавьте фрагмент 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 Admin добавьте следующий XML-файл обновления макета для нужных вам страниц

 <update handle="my_fancy_pants_unique_handle_name_which_doesnt_conflict_with_existing_names" />  

Magento позволяет обновлять XML-фрагменты макета, чтобы добавлять дополнительные дескрипторы к запросу. Это то, что вы делаете выше. Это немного проясняет ситуацию, и если вы хотите изменить что-то в XML, для этого есть централизованное место.

Обновить: Оказывается, что команда <update/> может использоваться только из самих XML-файлов макета. Код, который загружает XML-файл обновления макета для страниц CMS, отличается от кода, который загружает и обрабатывает обновления для файлов 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. Живи и учись.

Все это говорит о том, что подход с виджетами, вероятно, все еще жизнеспособен, и альтернативой вышеупомянутому было бы.

  1. Создайте пользовательский модуль с пользовательским классом блоков

  2. Класс block не отображает HTML

  3. Класс block содержит единственный метод с именем что-то вроде "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-файлов для обновления макета вы хотите добавить). Тем не менее, я не тестировал это, и мое доверие к этому подорвано, поэтому покупатель остерегается.

Второй подход заключается в создании единого виджета, который охватывает то, что вы хотели бы добавить на страницу, а затем с помощью администратора экземпляра виджета добавляет этот виджет в определенные блоки на определенных страницах. Эти ссылки должны помочь вам начать.

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

Комментарии:

1. Обновлено, чтобы исправить ошибочную информацию о тегах обновления, работающих на страницах CMS.

2. Огромное спасибо @alan-storm за невероятно подробный ответ. Я действительно нашел вашу недавнюю книгу в поисках ответа на этот вопрос и, скорее всего, возьму копию. Интересно, что я попробовал именно то, что вы предложили вначале, что, конечно, не сработало. Скоро я рассмотрю другие ваши предложения. Тем временем XML-файл обновления, похоже, работает просто отлично. Хотя, конечно, хотелось бы обновить дескрипторы для страниц CMS....

3. ОГО!! Я добавил больше, но это заняло слишком много времени и превысило лимит редактирования в 5 минут. Я так устал от всех этих чертовых правил! Я просто хочу быть частью сообщества! Перестаньте заставлять меня проходить через столько бюрократических проволочек!!

4. @BrianVPS Вначале это отстой, но как только вы получите здесь небольшую репутацию, эти проблемы начнут исчезать. Я думаю, что большинство из нас, которые часто используют тег Magento, склонны голосовать за любой вопрос или ответ, который не имеет формы "Halp, это не работает", так что вы моментально станете участником с хорошей репутацией.

5. @BrianVPS: не стесняйтесь покупать книгу Алана. Я только что прочитал это сам и нашел это наиболее интересным и полезным. Много моментов "АГА!" 🙂

Ответ №2:

Тем не менее, этот вопрос уже довольно старый, я нашел его через Google и хотел бы добавить некоторую информацию для тех, кто будет читать этот пост в будущем.

Вчера, когда я прочитал этот вопрос и ответ, а также этот и эту публикации, я стал совершенно уверен, что переопределить / расширить дескриптор макета страницы CMS только для определенных страниц невозможно или довольно сложно. Это привело меня к разработке одного небольшого расширения, которое вставляет любой пользовательский дескриптор макета на любой конкретной странице. Я скоро обновлю этот пост общедоступной ссылкой на расширение.

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

 <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>
  

Довольно легко внедрить любой пользовательский дескриптор макета на любую страницу и делать все, что вы хотите, только со страницами, которые используют этот шаблон и ваш пользовательский дескриптор макета. Хотел бы я знать это раньше, надеюсь, этот пост сэкономит чье-то время.