So fügen Sie der Admin-Kundenauftragsansicht in Magento2 eine benutzerdefinierte Schaltfläche hinzu


12

Geben Sie hier die Bildbeschreibung ein

Hinzufügen einer benutzerdefinierten Schaltfläche zur Kundenauftragsansicht in magento2, da einige der Ereignisse zugunsten von Plugins entfernt wurden.

  • Einige Ereignisse wurden entfernt (stattdessen müssen Plugins verwendet werden):
    • adminhtml_widget_container_html_before ( Verwendung in Magento 1.x )
    • admin_session_user_logout
    • model_config_data_save_before
    • ...

Siehe Magento2-Änderungsprotokoll

Antworten:


17

Die sauberste Lösung, die ich bisher gesehen habe, ist die Verwendung eines Plugins, das auf "beforeSetLayout" abzielt.

Dies kann auf den genauen Block abzielen und die Prüfung für die aktuelle Anforderung speichern. Außerdem wird vermieden, dass sich das Plugin in 'getOrderId' befindet, was in meinem Fall nicht verwendet werden konnte, da ich getOrderId in meiner Plugin-Methode aufrufen musste.

Also das in di.xml

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

Und das dann in der Datei 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}')"
        ]
    );


}

Arbeitete wie ein Zauber
Raul Sanchez

16

Nachdem ich viele verschiedene Möglichkeiten ausprobiert habe, ist dies die einzige Lösung, die zu funktionieren scheint, ohne andere Module zu beeinflussen. Ich würde gerne andere Lösungen sehen.

Option 1

Erstellen Sie ein Plugin in 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>

Dann in Plugin / 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
            );
        }

    }
}

Option 2

Erstellen Sie ein Plugin in 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>

Dann in Plugin / 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;
    }

}

Siehe Vollständiger Quellcode


@rs Ich habe die zweite Option ausprobiert und sie verursacht einen Fehler - 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, da die Methode __callPlugin () hinzufügt, welche beforeGetOrderId()Methode zu den Argumenten der getOrderId()Methode zurückgibt . \ vendor \ magento \ framework \ Interception \ Interceptor.php [Zeile 124] - $arguments = $beforeResult;. Also ich denke, es muss etwas anderes zurückgegeben werden, aber kein Objekt, was $ subject bedeutet
Kate Suykovskaya

1
Ich teste gerade auf Magento 2.0.2 ... Schauen Sie sich mein Update für Option 2 an ... Siehe github.com/magepal/stackexchange/tree/develop/91071
Renon Stewart

Gibt es eine Möglichkeit, Ajax beim Klicken auf diese Schaltfläche aufzurufen?
Nuwaus

@nuwaus ... Sie könnten den 'onclick' in 'onclick = "processAjax ()" "ändern und dann Ihre Ajax-Funktion dort oder eine andere auf Klick-JQuery-Bindung hinzufügen
Renon Stewart


9

Erstellen DI - Datei: 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>

Was wir hier machen ist:

  1. Setzen Sie ein benutzerdefiniertes contextArgument in dasOrder\View Block. Dieser Kontext ist als virtueller Typ definiert.
  2. Definieren Sie den virtuellen Typ für einen Widget-Kontext. Wir setzen benutzerdefinierte buttonListArgumente mit unserer eigenen Schaltflächenlistenklasse.

Implementieren Sie Ihre Schaltflächenlistenklasse:

<?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')
       ]);
   }
}

1
Vielen Dank für diese Lösung! Ich denke, das ist das Beste und das Eleganteste.
eInyzant

Das sah gut aus, elegant und leicht zu verstehen, aber leider funktioniert es nicht. In Magento 2.3.4 wird beim Klicken auf eine Bestellung ein Fehler ausgegebenException occurred during order load
Gianni Di Falco

3

Dies ist eine der besten Lösungen, die ich bisher ohne Plugins gesehen habe

MagePal / CustomButton / view / adminhtml / layout / 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;
    }

}

Es ist ein Fehler in adminhtml_sales_order_view.xmlsollte seinsales_order_view.xml
Zaheerabbas

2

Erstellen Sie die folgende di.xml-Position

app / code / Learning / RewriteSales / etc / di.xml

Inhalt sollte sein

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

Erstellen Sie Context.php nach der Aktion

app / code / Learning / RewriteSales / Plugin / Widget / Context.php

Inhalt sollte sein

Namespace Learning \ RewriteSales \ Plugin \ Widget;


Klassenkontext
{
    öffentliche Funktion 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-> add (
                'custom_button',
                [
                    'label' => __ ('Benutzerdefinierter Button'),
                    'onclick' => 'setLocation (\' '. $ this-> getCustomUrl ().' \ ')',
                    'Klasse' => 'Schiff'
                ]]
            );
        }}

        return $ buttonList;
    }}

    öffentliche Funktion getCustomUrl ()
    {
        $ objectManager = \ Magento \ Framework \ App \ ObjectManager :: getInstance ();
        $ urlManager = $ objectManager-> get ('Magento \ Framework \ Url');
        return $ urlManager-> getUrl ('sales / * / custom');
    }}
}}

Leeren Sie den Magento-Cache und führen Sie den Befehl update aus

PHP Bin / Magento Setup: Upgrade

Korrigieren Sie mich, wenn ich falsch preferenceliege , aber nach all meinen bisherigen Tests entspricht der Typ dem Umschreiben in Magento 1. Daher kann nur ein Modul davon profitieren
Renon Stewart,

Ja. Sie können jedoch kein Plugin für geschützte Funktionen erstellen.
Sohel Rana

Aktualisiere einfach meine Antwort mit dem Plugin
Sohel Rana

1
Anstatt den objectManager zu laden, hätten Sie es tun können$subject->getRequest()->getFullActionName()
Renon Stewart

füge dies vor der afterGetButtonList-Funktion hinzu ....... protected $ urlBuider; öffentliche Funktion __construct (\ Magento \ Framework \ UrlInterface $ urlBuilder) {$ this-> urlBuilder = $ urlBuilder; } Fügen Sie dann in der Funktion getCustomUrl () nur diese Zeile hinzu ..... return $ this-> urlBuilder-> getUrl ('Modulname / Controllername / Methodenname', Array ('Parameter' => Parameterwert));
KA9
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.