Order View Page in the Magento 2 Admin allows you to perform certain actions for a specific Order. Sometimes these actions have to be adjusted based on Merchant’s needs and business expectations. In this article we will modify existing Order Buttons for the Order View Page.
Our Goal
For this excercise let’s imagine we have the following expectations from a Merchant (this is a real example from real Magento developer life):
- We expect to use Invoice button as our next step in order processing flow.
- We aren’t going to use Hold button since our Orders are imported into ERP (Enterprise Resource Planning) system.
- Our integration with Email Marketing platform allows to Send Email notification automatically once an Order is placed.
Looks pretty much clear. Our Magento development skills will help Merchant to achieve these expectations.
Where Should We Start?
First of all we have to navigate to Magento Admin -> Sales -> Orders page and click one of existing Orders from the Orders grid. Page should look simular to mine version:
Pic 1. Magento 2 Admin Order Grid Page
If there are no orders, you might want to create it. URL of Order View page is:
[php]
http://magento2.dev/admin/sales/order/view/order_id/1/
[/php]
From the above URL we may assume that:
1. The admin/sales/order/view
page is managed by the Magento\Sales module.
2. The sales/order/view
URI part has to have a corresponding layout file where all blocks for Order View page are defined.
Let’s see. In the Magento\Sales\view\adminhtml\layout
directory there is a sales_order_view.xml
file.
[php]
<referenceContainer name="content">
<block class="Magento\Sales\Block\Adminhtml\Order\View" name="sales_order_edit"/>
</referenceContainer>
[/php]
The content
container has been used in sales_order_view.xml
file to assign Magento\Sales\Block\Adminhtml\Order\View
class.
The Magento\Sales\Block\Adminhtml\Order\View
class prepares Information Tab content for the Order View page. This class also prepares buttons which we are going to change:
1. Edit order. Primary page button.
2. Cancel order.
3. Send Email.
4. Creditmemo. The button will be shown once an Invoice is created.
5. Void payment. Depends on Payment Gateway settings.
6. Hold order.
7. Unhold order.
8. Accept Payment. Shows in case Order Status is in “payment_review”.
9. Deny Payment. Same as 8.
10. Get Payment Update.
11. Invoice or Invoice and Ship.
12. Ship
13. Reorder
These buttons provide full control for an Order:
Pic 2. Magento 2 Order Form Buttons – Before
Mechanics for Changes
All buttons are hard-coded in the Magento\Sales\Block\Adminhtml\Order\View
class. There is no container or array of buttons defined in a di.xml
configuration file. It means we have to find alternative way of changing order buttons.
The Magento\Sales\Block\Adminhtml\Order\View
class adds buttons into buttonList
protected variable. The variable is an object of the Magento\Backend\Block\Widget\Button\ButtonList
class.
In the Magento\Backend\Block\Widget\Container
class (this is parent class for the Magento\Sales\Block\Adminhtml\Order\View
class) we may see that the buttonList
has been passed into pushButtons() method:
[php]
protected function _prepareLayout()
{
$this->toolbar->pushButtons($this, $this->buttonList);
return parent::_prepareLayout();
}
[/php]
We are going to inject our changes right before buttons will be pushed into Forms Toolbar.
This is a good place to extend logic by adding a Plugin for the Toolbar class. The Magento\Sales\Block\Adminhtml\Order\View
class does not provide enough methods with public visibility that is why we have to look deeper into the implementation.
Always look for proper ways of extending Magento 2 code, even if it’s not obvious – Tweet This
Development
Once we know where to start it is a time to create our new module.
1. Recommended to Read
2. How to create Magento 2 Module in a separate repository
3. Development Design Patterns in Magento 2
4. Useful Magento Links #1
The following actions are must have for our module:
1. Create new etc/module.xml
configuration file with module name and setup version.
2. Create registration.php
file in order to include module into composer autoload workflow.
3. Add Pronko_Magento2OrderButtons
module into the app/etc/config.php
file.
4. Run bin/magento setup:upgrade
command
In order to add a Plugin which will inject Magento\Backend\Block\Widget\Button\Toolbar::pushButtons()
method call and provide control over to our Plugin class we have to declare it first. This di.xml configuration file should be placed into the app\code\Pronko\Magento2OrderButtons\etc\adminhtml
directory:
[php]
<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="orderFormToolbarButtons" type="Pronko\Magento2OrderButtons\Plugin\Block\Widget\Button\Toolbar" />
</type>
</config>
[/php]
The plugin
node allows to add an Interceptor class for the Magento\Backend\Block\Widget\Button\Toolbar
class. The code has to be regenerated before the configuration will take affect. Content of the
directory should be removed.
The Pronko\Magento2OrderButtons\Plugin\Block\Widget\Button\Toolbar
class might look like the following:
[php]
namespace Pronko\Magento2OrderButtons\Plugin\Block\Widget\Button;
use Magento\Backend\Block\Widget\Button\Toolbar as ToolbarContext;
use Magento\Framework\View\Element\AbstractBlock;
use Magento\Backend\Block\Widget\Button\ButtonList;
class Toolbar
{
/**
* @param ToolbarContext $toolbar
* @param AbstractBlock $context
* @param ButtonList $buttonList
* @return array
*/
public function beforePushButtons(
ToolbarContext $toolbar,
\Magento\Framework\View\Element\AbstractBlock $context,
\Magento\Backend\Block\Widget\Button\ButtonList $buttonList
) {
if (!$context instanceof \Magento\Sales\Block\Adminhtml\Order\View) {
return [$context, $buttonList];
}
$buttonList->update(‘order_edit’, ‘class’, ‘edit’);
$buttonList->update(‘order_invoice’, ‘class’, ‘invoice primary’);
$buttonList->update(‘order_invoice’, ‘sort_order’, (count($buttonList->getItems()) + 1) * 10);
$buttonList->add(‘order_review’,
[
‘label’ => __(‘Review’),
‘onclick’ => ‘setLocation(\” . $context->getUrl(‘sales/*/review’) . ‘\’)’,
‘class’ => ‘review’
]
);
$buttonList->remove(‘order_hold’);
$buttonList->remove(‘send_notification’);
return [$context, $buttonList];
}
}
[/php]
How it works
The beforePushButtons()
method listens for the Toolbar::pushButtons()
call and triggered before original Toolbar::pushButtons()
method call.
Once we are inside the beforePushButtons()
method the $context
argument has to be checked first. It allows to modify buttonList
only when execution is in context of the Magento\Sales\Block\Adminhtml\Order\View
class:
[php]
if (!$context instanceof \Magento\Sales\Block\Adminhtml\Order\View) {
return [$context, $buttonList];
}
[/php]
Once this is checked we have some control over buttonList
object prepared in the
Magento\Sales\Block\Adminhtml\Order\View::_construct()
method. Changing class of Primary Edit button to become secondary button:
[php]
$buttonList->update(‘order_edit’, ‘class’, ‘edit’);
[/php]
Updating Invoice button to become a Primary Button:
[php]
$buttonList->update(‘order_invoice’, ‘class’, ‘invoice primary’);
[/php]
Since Invoice became Primary Button it has to be moved right side to be consistent with other pages:
[php]
$buttonList->update(‘order_invoice’, ‘sort_order’, (count($buttonList->getItems()) + 1) * 10);
[/php]
Adding new Review button:
[php]
$buttonList->add(‘order_review’,
[
‘label’ => __(‘Review’),
‘onclick’ => ‘setLocation(\” . $context->getUrl(‘sales/*/review’) . ‘\’)’,
‘class’ => ‘review’
]
);
[/php]
And finally, removing Hold and Send Email buttons from the page:
[php]
$buttonList->remove(‘order_hold’);
$buttonList->remove(‘send_notification’);
[/php]
As a result of adding new Plugin we have changed Order View Form Buttons Toolbar:
Pic 3. Magento 2 Order Form Buttons – After
Summary
By looking for better way of extending existing Magento 2 functionality we invest into the future upgrades. There are other ways of achieving Merchant’s goal for this task. You may want to post it in the comments below this article.
Follow me @max_pronko on Twitter. I will post more articles and update you once it is ready.
Leave your comments and feedback.
The image for this article is created by great photograph Thomas Hawk.
Leave a Reply
You must be logged in to post a comment.