Magento - переместить блок справа налево
Не уверен, почему это так сложно. Если я правильно понимаю ЭТО, я смогу быстро достичь своих целей... Но без радости.
Итак, я создаю свою первую тему и все еще думаю о макете...
Я работаю специально над Catalog Product View
страницы, и я преобразую эту страницу из макета правого столбца в макет левого столбца. Я просто хочу переместить блоки справа налево.
В каталоге catalog.xml по умолчанию product_list_related
определено:
</catalog_product_view>
//...
<reference name="right">
<block type="catalog/product_list_related" name="catalog.product.related" before="-" template="catalog/product/list/related.phtml"/>
</reference>
</catalog_product_view>
В моем local.xml я просто пытаюсь переместить этот блок:
<layout>
// bunch other page directives
<catalog_product_view>
<reference name="root">
<action method="setTemplate"><template>page/2columns-left.phtml</template></action>
</reference>
<reference name="right">
<action method="unsetChild"><name>catalog.product.related</name></action>
</reference>
<reference name="left">
<action method="insert"><blockName>catalog.product.related</blockName></action>
// note that that "catalog.leftnav" gets inserted as expected
<block type="catalog/layer_view" name="catalog.leftnav" after="-" template="catalog/layer/view.phtml"/>
</reference>
</catalog_product_view>
</layout>
Как отмечено - вставка catalog.leftnav
работает как положено, поэтому я предполагаю, что все остальное настроено правильно. Целевой блок рендерится, как и ожидалось, если я оставлю шаблон и другие директивы без изменений, что говорит мне, что блок должен рендериться после того, как его правильно установили и вставили...
Это сводит меня с ума... но что еще нового в Magento.
Ура -
б [] х
UPDATE
Потому что я просто не могу получить local.xml
переопределить на работу, я просто отступаю на модифицированный catalog.xml
, Я достаточно умный парень... меня беспокоит то, что я не могу заставить это работать (и что magento просто молча терпит неудачу, в любом случае) - но я не могу больше тратить время на обсуждение этой глупой проблемы.
Двигаемся дальше.
UPDATE, again.
Потратил некоторое время, сейчас, работая в magento и знакомясь с его сложностями. Я вернулся к этой проблеме сегодня, так как мне нужно, чтобы мой local.xml работал правильно.
Я действительно не знаю, в чем я был неправ, но этот набор директив наконец сработал.
<reference name="right">
<action method="unsetChild">
<alias>catalog.product.related</alias>
</action>
</reference>
<reference name="left">
<action method="insert">
<block>catalog.product.related</block>
</action>
</reference>
Ключевой момент, на который я обращу внимание, для тех, кто занимается этим:
Директивы Layout xml вызывают доступные методы внутри классов magento. В этом случае блок Page.xmls "Left" имеет тип Mage_Core_Block_Text
, который наследует от Mage_Core_Block_Abstract
который содержит методы unsetChild
а также insert
,
от Mage_Core_Block_Abstract
:
/**
* Unset child block
*
* @param string $alias
* @return Mage_Core_Block_Abstract
*/
public function unsetChild($alias)
{
if (isset($this->_children[$alias])) {
unset($this->_children[$alias]);
}
if (!empty($this->_sortedChildren)) {
$key = array_search($alias, $this->_sortedChildren);
if ($key !== false) {
unset($this->_sortedChildren[$key]);
}
}
return $this;
}
а также
/**
* Insert child block
*
* @param Mage_Core_Block_Abstract|string $block
* @param string $siblingName
* @param boolean $after
* @param string $alias
* @return object $this
*/
public function insert($block, $siblingName = '', $after = false, $alias = '')
{
if (is_string($block)) {
$block = $this->getLayout()->getBlock($block);
}
if (!$block) {
/*
* if we don't have block - don't throw exception because
* block can simply removed using layout method remove
*/
//Mage::throwException(Mage::helper('core')->__('Invalid block name to set child %s: %s', $alias, $block));
return $this;
}
if ($block->getIsAnonymous()) {
$this->setChild('', $block);
$name = $block->getNameInLayout();
} elseif ('' != $alias) {
$this->setChild($alias, $block);
$name = $block->getNameInLayout();
} else {
$name = $block->getNameInLayout();
$this->setChild($name, $block);
}
if ($siblingName === '') {
if ($after) {
array_push($this->_sortedChildren, $name);
} else {
array_unshift($this->_sortedChildren, $name);
}
} else {
$key = array_search($siblingName, $this->_sortedChildren);
if (false !== $key) {
if ($after) {
$key++;
}
array_splice($this->_sortedChildren, $key, 0, $name);
} else {
if ($after) {
array_push($this->_sortedChildren, $name);
} else {
array_unshift($this->_sortedChildren, $name);
}
}
$this->_sortInstructions[$name] = array($siblingName, (bool)$after, false !== $key);
}
return $this;
}
Значит, локальные параметры xml важны не по названию (конкретно), а по порядку:
<reference name="left">
<action method="insert">
<block>catalog.product.related</block>
<siblingName>catalog.leftnav</siblingName>
<after>1</after>
<alias>catalog_product_related</alias>
</action>
</reference>
В конечном счете, это делает local.xml действительно мощным методом манипулирования системой, но если вы не знакомы с ней и с системой magento, будьте готовы к неделям или месяцам работы, чтобы по-настоящему разобраться с ней.
ура
Еще одно обновление
Я столкнулся с проблемой несколько раз, когда блок, который я хочу переместить, был удален. Это проблема, поскольку любой блок, который был удален из макета, обнуляется навсегда.
Однако, с очень удобным плагином Unremove Alan Storm вы можете отменить то, что было сделано:
<checkout_onepage_index>
<x-unremove name="left" />
<reference name="right">
<action method="unsetChild">
<alias>checkout.progress.wrapper</alias>
</action>
</reference>
<reference name="left">
<action method="insert">
<block>checkout.progress.wrapper</block>
</action>
</reference>
</checkout_onepage_index>
Он управляет этим умением, наблюдая за объектом макета и создавая список удаленных блоков, на которые можно ссылаться позже.
Ницца!
7 ответов
Сейчас это пыльная тема, но, к сведению, это последний ответ, с которым я согласился.
<reference name="right">
<action method="unsetChild">
<alias>checkout.progress.wrapper</alias>
</action>
</reference>
<reference name="left">
<action method="insert">
<block>checkout.progress.wrapper</block>
</action>
</reference>
Magento рекомендует включить это в свой local.xml
и это доказало свою эффективность.
Альтернативный подход состоит в том, чтобы переименовать "правый" блок в "левый", а не перемещать блоки справа налево. Однако, это не будет работать, если "правильный" блок удаляется в первую очередь, как я предположил, может иметь место в моем другом ответе.
<remove name="left" />
<reference name="right">
<action method="setNameInLayout"><name>left</name></action>
</reference>
<reference name="root">
<action method="setChild"><alias>left</alias><name>left</name></action>
<action method="unsetChild"><alias>right</alias></action>
</reference>
<!-- make sure nothing referencing "right" comes after this! -->
Если вы просто хотите изменить вывод с 2col-right на 2col-left, было бы намного проще изменить
<reference name="right" ...
в
<reference name="left" ...
Нет необходимости сбрасывать или вставлять какие-либо дочерние элементы или что-либо повторно объявлять. Вы слишком усложняете вещи и дублируете код без необходимости.
Если вы тоже создаете свой собственный дизайн, я бы предложил начать копирование всего ./app/design/frontend/base
каталог для ./app/design/frontend/mypackage
- тогда работай от mypackage/default
каталог для повторного оформления вашего сайта. Это чище и проще. Другие могут прокомментировать потенциальные проблемы, связанные с возможностью обновления, если вы копируете каждый файл (а не только те, которые вы намереваетесь изменить), но это гораздо лучшая практика и гораздо менее подвержена ошибкам, трудностям и общему обслуживанию.
Изменить: чтобы узнать об этом более подробно - посмотрите /questions/11692027/luchshij-sposob-poluchit-innerxml-xelement/11692048#11692048
Я бы сделал это так: в вашем local.xml под eg
<reference name="right"></reference>
Вы удаляете блоки, например:
<remove name="right.poll">
а затем вы добавляете блоки в
<reference name="left"></reference>
"Правильный" блок, вероятно, удаляется с <remove name="right" />
в какой-то момент в макете. Если это так, то это приведет к тому, что блок "catalog.product.related" никогда не будет добавлен в макет в первую очередь, поэтому нет блока для вставки в "левый" блок.
Я почти уверен, что это проблема, но для подтверждения добавьте Mage::log("Removed $blockName"); в Mage_Core_Model_Layout->generateXml() внутри цикла for и проверьте журнал после загрузки страницы.
Если я прав, просто скопируйте <block..>
в ваш local.xml и удалите действия "unsetChild" и "insert".
Копирование base/default в локальную тему - ужасная идея. Каждое обновление файла основной темы при обновлении версии Magento приводит к одной и той же уязвимости при изменении файлов приложения / кода / ядра - что требует от вас изменения файлов при обновлении.
Ваш правильный курс действий - это изменение одного local.xml с вашими дополнениями или переопределениями. Если этого недостаточно, используйте правильный синтаксис для создания модуля в приложении / коде / сообществе с определениями макетов и XML-файлами пользовательских макетов.
Я думаю, что лучший ответ для изменения макетов Magento дан на Classyllama.com
http://www.classyllama.com/development/magento-development/the-better-way-to-modify-magento-layout
Когда вы используете тег удаления, он удаляет все блоки с указанным именем из всего макета, независимо от контекста. Итак, если я удаляю right.newsletter в контексте и это имя используется, скажем, в контексте, то оба блока будут удалены. Поскольку удаление действует в глобальном контексте, вы можете удалить элемент только один раз. Так как вызывается в catalogsearch.xml, мы должны сбросить его, иначе мы получим ошибку.
<action method="unsetChild"><name>right.newsletter</name></action>;