Удалить блок из макета без имени
Я хочу удалить блок из макета в magento 2, который объявлен в стороннем расширении, но у блока нет имени.
Могу ли я это сделать?
Блок объявляется следующим образом
<referenceContainer name="before.body.end">
<block class="Magento\Backend\Block\Template" template="[Vendor_Module]::template.phtml"/>
</referenceContainer>
Я не могу использовать
<referenceBlock name="..." remove="true" />
Потому что, как вы можете видеть, на нем нет имени.
3 answers
Я нашел эту проблему в классе Magento\Framework\View\Layout\ScheduledStructure\Helper
Существует функция _generateAnonymousName
:
protected function _generateAnonymousName($class)
{
$position = strpos($class, '\\Block\\');
$key = $position !== false ? substr($class, $position + 7) : $class;
$key = strtolower(trim($key, '_'));
return $key . $this->counter++;
}
Это вызов функции scheduleStructure
:
public function scheduleStructure(
Layout\ScheduledStructure $scheduledStructure,
Layout\Element $currentNode,
Layout\Element $parentNode
) {
// if it hasn't a name it must be generated
if (!(string)$currentNode->getAttribute('name')) {
$name = $this->_generateAnonymousName($parentNode->getElementName() . '_schedule_block'); // CALL HERE
$currentNode->setAttribute('name', $name);
}
$path = $name = (string)$currentNode->getAttribute('name');
// Prepare scheduled element with default parameters [type, alias, parentName, siblingName, isAfter]
$row = [
self::SCHEDULED_STRUCTURE_INDEX_TYPE => $currentNode->getName(),
self::SCHEDULED_STRUCTURE_INDEX_ALIAS => '',
self::SCHEDULED_STRUCTURE_INDEX_PARENT_NAME => '',
self::SCHEDULED_STRUCTURE_INDEX_SIBLING_NAME => null,
self::SCHEDULED_STRUCTURE_INDEX_IS_AFTER => true,
];
$parentName = $parentNode->getElementName();
//if this element has a parent element, there must be reset [alias, parentName, siblingName, isAfter]
if ($parentName) {
$row[self::SCHEDULED_STRUCTURE_INDEX_ALIAS] = (string)$currentNode->getAttribute('as');
$row[self::SCHEDULED_STRUCTURE_INDEX_PARENT_NAME] = $parentName;
list($row[self::SCHEDULED_STRUCTURE_INDEX_SIBLING_NAME],
$row[self::SCHEDULED_STRUCTURE_INDEX_IS_AFTER]) = $this->_beforeAfterToSibling($currentNode);
// materialized path for referencing nodes in the plain array of _scheduledStructure
if ($scheduledStructure->hasPath($parentName)) {
$path = $scheduledStructure->getPath($parentName) . '/' . $path;
}
}
$this->_overrideElementWorkaround($scheduledStructure, $name, $path);
$scheduledStructure->setPathElement($name, $path);
$scheduledStructure->setStructureElement($name, $row);
return $name;
}
В этом случае имя блока может быть:
before.body.end_schedule_block1
before.body.end_schedule_block2
- ...
Я думаю, вам следует определить блок итогов без имени в контейнере, а имя блока заказа необходимо удалить в контейнере.
Я действительно подаю тебе плохую идею.
Здесь идея не в том, чтобы остановить вывод вашего блока
Использование события view_block_abstract_to_html_after
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="view_block_abstract_to_html_after">
<observer name="myObserverName" instance="Stack\Work\Observer\MyObserver" />
</event>
</config>
И с помощью этого наблюдателя отключите вывод вашего блока
<?php
namespace Stack\Work\Observer;
use Magento\Framework\Event\ObserverInterface;
class MyObserver implements ObserverInterface
{
public function __construct()
{
//Observer initialization code...
//You can use dependency injection to get any class this observer may need.
}
public function execute(\Magento\Framework\Event\Observer $observer)
{
$block = $observer->getData('block');
if('[Vendor_Module]::template.phtml' == $block->getTemplate()){
$transport = $observer->getData('transport');
$transport->setHtml('');
}
}
}
Я получил идею из ответа Амита и в итоге получил рабочее решение, которое не выглядит очень навязчивым, и это не перебор, так как мой код выполняется только один раз.
Я создал наблюдателя для события layout_generate_blocks_after
, которое выполняется после загрузки макетов и создания блоков.
Это может иметь недостаток, потому что блок, который я пытаюсь удалить, все еще создается, но в моем случае мне просто нужно было удалить его со страницы.
Поэтому я у вас есть файл etc/adminhtml/events.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="layout_generate_blocks_after">
<observer name="remove-the-block" instance="[MyVendor]\[MyModule]\Observer\RemoveBlock" />
</event>
</config>
И мой класс наблюдателей:
<?php
namespace [MyVendor]\[MyModule]\Observer;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
class RemoveBlock implements ObserverInterface
{
const TEMPLATE_TO_REMOVE = '[OtherVendor]_[OtherModule]::template.phtml';
public function execute(Observer $observer)
{
/** @var \Magento\Framework\View\Layout $layout */
$layout = $observer->getLayout();
$blocks = $layout->getAllBlocks();
foreach ($blocks as $key => $block) {
/** @var \Magento\Framework\View\Element\Template $block */
if ($block->getTemplate() == self::TEMPLATE_TO_REMOVE) {
$layout->unsetElement($key);
}
}
}
}