Как добавить пользовательскую кнопку для администрирования представления заказа клиента в Magento2

12

введите описание изображения здесь

Как добавить пользовательскую кнопку в представление заказа клиента в magento2, поскольку некоторые события были удалены в пользу плагинов.

  • Удалены некоторые события (вместо них должны использоваться плагины):

Смотрите Magento2 Журнал изменений

Ренон Стюарт
источник

Ответы:

19

Самое чистое решение, которое я видел до сих пор, - это использовать плагин с таргетингом 'beforeSetLayout'

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

Так это в di.xml

   <type name="Magento\Sales\Block\Adminhtml\Order\View">
    <plugin name="addMyButton" type="My\Module\Plugin\Block\Adminhtml\Order\View"/>
   </type>

И тогда это в файле My \ Module \ Plugin \ Block \ Adminhtml \ Order \ View.php

public function beforeSetLayout(\Magento\Sales\Block\Adminhtml\Order\View $view)
{
    $message ='Are you sure you want to do this?';
    $url = '/mymodule/controller/action/id/' . $view->getOrderId();


    $view->addButton(
        'order_myaction',
        [
            'label' => __('My Action'),
            'class' => 'myclass',
            'onclick' => "confirmSetLocation('{$message}', '{$url}')"
        ]
    );


}
Крис
источник
Работал как шарм
Рауль Санчес
17

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

Опция 1

Создайте плагин в Company / Module / etc / adminhtml / di.xml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Backend\Block\Widget\Button\Toolbar">
        <plugin name="MagePal_TestBed::pluginBefore" type="MagePal\TestBed\Plugin\PluginBefore" />
    </type>
</config>

Затем в плагин / PluginBefore.php

namespace MagePal\TestBed\Plugin;

class PluginBefore
{
    public function beforePushButtons(
        \Magento\Backend\Block\Widget\Button\Toolbar\Interceptor $subject,
        \Magento\Framework\View\Element\AbstractBlock $context,
        \Magento\Backend\Block\Widget\Button\ButtonList $buttonList
    ) {

        $this->_request = $context->getRequest();
        if($this->_request->getFullActionName() == 'sales_order_view'){
              $buttonList->add(
                'mybutton',
                ['label' => __('My Button'), 'onclick' => 'setLocation(window.location.href)', 'class' => 'reset'],
                -1
            );
        }

    }
}

Вариант 2

Создайте плагин в Company / Module / etc / adminhtml / di.xml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="\Magento\Sales\Block\Adminhtml\Order\View">
        <plugin name="MagePal_TestBed::pluginBeforeView" type="MagePal\TestBed\Plugin\PluginBeforeView" />
    </type>
</config>

Затем в плагин / PluginBeforeView.php

namespace MagePal\TestBed\Plugin;

class PluginBeforeView
{

    public function beforeGetOrderId(\Magento\Sales\Block\Adminhtml\Order\View $subject){
        $subject->addButton(
                'mybutton',
                ['label' => __('My Buttion'), 'onclick' => 'setLocation(window.location.href)', 'class' => 'reset'],
                -1
            );

        return null;
    }

}

Смотрите полный исходный код

Ренон Стюарт
источник
@rs Я попробовал 2-й вариант, и это вызывает ошибку - Warning: call_user_func_array() expects parameter 2 to be array, object given in D:\new\OpenServer\domains\graffiticaps-m2.loc\vendor\magento\framework\Interception\Interceptor.php on line 144, так как метод __callPlugin () добавляет, какой beforeGetOrderId()метод возвращает аргументы getOrderId()метода. \ vendor \ magento \ framework \ Interception \ Interceptor.php [строка 124] - $arguments = $beforeResult;. Поэтому я думаю, что должно быть возвращено что-то еще, но не объект, то есть $ subject
Кейт Суйковская
1
Я просто тестирую на Magento 2.0.2 ... Взгляните на мое обновление для варианта №2 .... См. Github.com/magepal/stackexchange/tree/develop/91071
Ренон Стюарт,
Есть ли способ вызвать ajax по нажатию этой кнопки?
nuwaus
@nuwaus ... вы можете изменить 'onclick' на 'onclick = "processAjax ()" ", а затем добавить туда свою функцию ajax или какую-либо другую привязку jquery для клика
Ренон Стюарт,
вот похожая проблема. magento.stackexchange.com/questions/251458/…
Аджвад Сайед
9

Создать DI-файл app/code/YourVendor/YourModule/etc/di.xml::

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <virtualType name="SalesOrderViewWidgetContext" type="\Magento\Backend\Block\Widget\Context">
        <arguments>
            <argument name="buttonList" xsi:type="object">YourVendor\YourModule\Block\Adminhtml\Order\View\ButtonList
            </argument>
        </arguments>
    </virtualType>
    <type name="Magento\Sales\Block\Adminhtml\Order\View">
        <arguments>
            <argument name="context" xsi:type="object">SalesOrderViewWidgetContext</argument>
        </arguments>
    </type>
</config>

Что мы делаем здесь:

  1. Установить пользовательский contextаргумент в Order\Viewблок. Этот контекст определяется как виртуальный тип.
  2. Определите виртуальный тип для контекста виджета. Мы устанавливаем пользовательский buttonListаргумент с нашим собственным классом списка кнопок.

Реализуйте свой класс списка кнопок:

<?php
namespace YourVendor\YourModule\Block\Adminhtml\Order\View;

class ButtonList extends \Magento\Backend\Block\Widget\Button\ButtonList
{
   public function __construct(\Magento\Backend\Block\Widget\Button\ItemFactory $itemFactory)
   {
       parent::__construct($itemFactory);
       $this->add('mybutton', [
           'label' => __('My button label')
       ]);
   }
}
dan.kocherga
источник
1
Спасибо за это решение! Я думаю, что это самый лучший и самый элегантный.
eInyzant
Это выглядело красиво, элегантно и легко понять, но, к сожалению, это не работает. В Magento 2.3.4 при нажатии на ордер выдает ошибкуException occurred during order load
Джанни Ди Фалько
3

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

MagePal / CustomButton / просмотреть / adminhtml / макет / sales_order_view.xml

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="sales_order_edit">
            <block class="MagePal\CustomButton\Block\Adminhtml\Order\View\Buttons" name="custom_buttons">
                <action method="addButtons"/>
            </block>
        </referenceBlock>
    </body>
</page>

MagePal / CustomButton / Block / Adminhtml / Order / View / Buttons.php

namespace MagePal\CustomButton\Block\Adminhtml\Order\View;

class Buttons extends \Magento\Sales\Block\Adminhtml\Order\View
{    
    public function __construct(
        \Magento\Backend\Block\Widget\Context $context,
        \Magento\Framework\Registry $registry,
        \Magento\Sales\Model\Config $salesConfig,
        \Magento\Sales\Helper\Reorder $reorderHelper,
        array $data = []
    ) {
        parent::__construct($context, $registry, $salesConfig, $reorderHelper, $data);
    }

    public function addButtons()
    {
        $parentBlock = $this->getParentBlock();

        if(!$parentBlock instanceof \Magento\Backend\Block\Template || !$parentBlock->getOrderId()) {
            return;
        }

        $buttonUrl = $this->_urlBuilder->getUrl(
            'adminhtml/custombutton/new',
            ['order_id' => $parentBlock->getOrderId()]
        );

        $this->getToolbar()->addChild(
              'create_custom_button',
              \Magento\Backend\Block\Widget\Button::class,
              ['label' => __('Custom Button'), 'onclick' => 'setLocation(\'' . $buttonUrl . '\')']
            );
        }
        return $this;
    }

}
Ренон Стюарт
источник
В этом adminhtml_sales_order_view.xmlдолжна быть ошибкаsales_order_view.xml
Захираббас
В этом нет необходимостиpublic function __construct
Сергей Коваль
2

Создать di.xml следующую локацию

Приложение / код / ​​Обучение / RewriteSales / и т.д. / di.xml

Содержание должно быть

<? xml version = "1.0"?>
<config xmlns: xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi: noNamespaceSchemaLocation = "urn: magento: framework: ObjectManager / etc / config.xsd">
    <type name = "Magento \ Backend \ Block \ Widget \ Context">
        <plugin name = "add_custom_button_sales_veiw" type = "Learning \ RewriteSales \ Plugin \ Widget \ Context" sortOrder = "1" />
    </ Тип>
</ Config>

Создать Context.php после loaction

Приложение / код / ​​Обучение / RewriteSales / плагин / виджет / Context.php

Содержание должно быть

Изучение пространства имен \ RewriteSales \ Plugin \ Widget;


Контекст класса
{
    публичная функция afterGetButtonList (
        \ Magento \ Backend \ Block \ Widget \ Context $ subject,
        $ buttonList
    )
    {
        $ objectManager = \ Magento \ Framework \ App \ ObjectManager :: getInstance ();
        $ request = $ objectManager-> get ('Magento \ Framework \ App \ Action \ Context') -> getRequest ();
        if ($ request-> getFullActionName () == 'sales_order_view') {
            $ ButtonList-> добавить (
                'Custom_button',
                [
                    'label' => __ ('Custom Button'),
                    'onclick' => 'setLocation (\' '. $ this-> getCustomUrl ().' \ ')',
                    'class' => 'ship'
                ]
            );
        }

        return $ buttonList;
    }

    публичная функция getCustomUrl ()
    {
        $ objectManager = \ Magento \ Framework \ App \ ObjectManager :: getInstance ();
        $ urlManager = $ objectManager-> get ('Magento \ Framework \ Url');
        return $ urlManager-> getUrl ('sales / * / custom');
    }
}

Очистить кеш Magento и запустить команду обновления

Настройка php bin / magento: обновление
Сохель Рана
источник
Поправьте меня, если я ошибаюсь, но из всех моих тестов до сих пор preferenceтип является эквивалентом перезаписи в magento 1. Поэтому только один модуль может воспользоваться этим
Ренон Стюарт,
да. Но вы не можете создать плагин для защищенной функции.
Сохель Рана
Просто обновите мой ответ, используя плагин
Sohel Rana
1
Вместо загрузки objectManager вы могли бы это сделать$subject->getRequest()->getFullActionName()
Ренон Стюарт
добавьте это перед функцией afterGetButtonList ....... protected $ urlBuider; публичная функция __construct (\ Magento \ Framework \ UrlInterface $ urlBuilder) {$ this-> urlBuilder = $ urlBuilder; } Затем в функцию getCustomUrl () добавьте только эту строку ..... return $ this-> urlBuilder-> getUrl ('modulename / controllername / methodname', array ('parameter' => parameter_value));
KA9