Как использовать нестандартные элементы управления на административных экранах товара и товарного раздела

Базовый класс административных форм \Magento\Backend\Block\Widget\Form содержит метод _getAdditionalElementTypes, предназначенный для регистрации нестандартных элементов управления для данной формы:

https://github.com/magento/magento2/blob/d59a6fd3013833ac55f6c50a4cf668ef7adc2294/app/code/Magento/Backend/Block/Widget/Form.php#L265-L268

Потомки базового класса административных форм могут перекрыть этот метод и тем самым зарегистрировать свои нестандартные элементы управления.

https://github.com/magento/magento2/blob/d59a6fd3013833ac55f6c50a4cf668ef7adc2294/app/code/Magento/Backend/Block/Widget/Form.php#L254

Эту возможность используют, например, стандартные классы административных форм товара и товарного раздела.

\Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Attributes::_getAdditionalElementTypes():

https://github.com/magento/magento2/blob/d59a6fd3013833ac55f6c50a4cf668ef7adc2294/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Attributes.php#L138-L158

Как Вы можете заметить, код выше класса административной формы товара зарегистрировал в системе нестандартные элементы управления: price, weight, gallery, image, boolean, textarea.

Затем он оповещает подписчиков о событии adminhtml_catalog_product_edit_element_types:

https://github.com/magento/magento2/blob/d59a6fd3013833ac55f6c50a4cf668ef7adc2294/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Attributes.php#L151

Ваш модуль может подписаться на это событие, и тем самым добавить на административную страницу товара свои нестандартные элементы управления:

<?xml version='1.0'?>
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:noNamespaceSchemaLocation='../../../../../../lib/internal/Magento/Framework/Event/etc/events.xsd'>
	<event name='adminhtml_catalog_product_edit_element_types'>
		<observer
			name='Dfe\Markdown\Observer\ElementTypes'
			instance='Dfe\Markdown\Observer\ElementTypes'
		/>
	</event>
</config>
<?php
namespace Dfe\Markdown\Observer;
use Magento\Framework\Event\ObserverInterface;
class ElementTypes implements ObserverInterface {
	/**
	 * @override
	 * @see ObserverInterface::execute()
	 * @used-by \Magento\Framework\Event\Invoker\InvokerDefault::_callObserverMethod()
	 * @see \Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Attributes::_getAdditionalElementTypes()
	 * https://github.com/magento/magento2/blob/0be91a56d050791ac0b67a47185d79df31e79329/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Attributes.php#L151
		$response = new \Magento\Framework\DataObject();
		$response->setTypes([]);
		$this->_eventManager->dispatch(
			'adminhtml_catalog_product_edit_element_types', ['response' => $response]
		);
	 * https://3v4l.org/UidhW
	 * @param \Magento\Framework\Event\Observer $o
	 * @return void
	 */
	public function execute(\Magento\Framework\Event\Observer $o) {
		if (\Dfe\Markdown\Settings::s()->enable()) {
			$o['response']['types'] = ['textarea' => 'Dfe\Markdown\FormElement'];
		}
	}
}

Это прекрасно работает для административного экрана товара, однако для административного экрана товарного раздела не заработает, потому что соответствующий класс о событии не оповещает:

Пока в ядре это не исправлено, я использую своё обходное решение с перекрытием административной формы товарного раздела своим классом:

<?xml version='1.0'?>
<config
	xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
	xsi:noNamespaceSchemaLocation='../../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd'
>
	<preference
		for='Magento\Catalog\Block\Adminhtml\Category\Tab\Attributes'
		type='Df\Catalog\Block\Adminhtml\Category\Tab\Attributes'
	/>
</config>
<?php
namespace Df\Catalog\Block\Adminhtml\Category\Tab;
class Attributes extends \Magento\Catalog\Block\Adminhtml\Category\Tab\Attributes {
	/**
	 * @override
	 * @see \Magento\Catalog\Block\Adminhtml\Category\Tab\Attributes::_getAdditionalElementTypes()
	 * @return string[]
	 */
	protected function _getAdditionalElementTypes() {
		/** @var string[] $result */
		$result = parent::_getAdditionalElementTypes();
		$response = new \Magento\Framework\DataObject();
		$response['types'] = [];
		$this->_eventManager->dispatch(
			'adminhtml_catalog_category_edit_element_types', ['response' => $response]
		);
		foreach ($response['types'] as $typeName => $typeClass) {
			/** @var string $typeName */
			/** @var string $typeClass */
			$result[$typeName] = $typeClass;
		}
		return $result;
	}
}
<?xml version='1.0'?>
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:noNamespaceSchemaLocation='../../../../../../lib/internal/Magento/Framework/Event/etc/events.xsd'>
	<event name='adminhtml_catalog_category_edit_element_types'>
		<observer
			name='Dfe\Markdown\Observer\ElementTypes'
			instance='Dfe\Markdown\Observer\ElementTypes'
		/>
	</event>
</config>