Magento 2 add tab to sales order
You're really close. Here's what I did to make this work.
First create app/code/VENDOR/MODULE/view/adminhtml/layout/sales_order_view.xml and add
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="admin-2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="left">
<referenceBlock name="sales_order_tabs">
<action method="addTab">
<argument name="name" xsi:type="string">order_transzuri</argument>
<argument name="block" xsi:type="string">Sistel\Transzuri\Block\Adminhtml\Order\View\Tab\Custom</argument>
</action>
</referenceBlock>
</referenceContainer>
</body>
</page>
Next we'll create app/code/VENDOR/MODULE/Block/Adminhtml/Order/View/Tab/Custom.php
<?php
namespace Sistel\Transzuri\Block\Adminhtml\Order\View\Tab;
class Custom extends \Magento\Backend\Block\Template implements \Magento\Backend\Block\Widget\Tab\TabInterface
{
/**
* Template
*
* @var string
*/
protected $_template = 'order/view/tab/custom.phtml';
/**
* Core registry
*
* @var \Magento\Framework\Registry
*/
protected $coreRegistry = null;
/**
* @param \Magento\Backend\Block\Template\Context $context
* @param \Magento\Framework\Registry $registry
* @param array $data
*/
public function __construct(
\Magento\Backend\Block\Template\Context $context,
\Magento\Framework\Registry $registry,
array $data = []
) {
$this->coreRegistry = $registry;
parent::__construct($context, $data);
}
/**
* Retrieve order model instance
*
* @return \Magento\Sales\Model\Order
*/
public function getOrder()
{
return $this->coreRegistry->registry('current_order');
}
/**
* {@inheritdoc}
*/
public function getTabLabel()
{
return __('Transzuri');
}
/**
* {@inheritdoc}
*/
public function getTabTitle()
{
return __('Transzuri');
}
/**
* {@inheritdoc}
*/
public function canShowTab()
{
// For me, I wanted this tab to always show
// You can play around with the ACL settings
// to selectively show later if you want
return true;
}
/**
* {@inheritdoc}
*/
public function isHidden()
{
// For me, I wanted this tab to always show
// You can play around with conditions to
// show the tab later
return false;
}
/**
* Get Tab Class
*
* @return string
*/
public function getTabClass()
{
// I wanted mine to load via AJAX when it's selected
// That's what this does
return 'ajax only';
}
/**
* Get Class
*
* @return string
*/
public function getClass()
{
return $this->getTabClass();
}
/**
* Get Tab Url
*
* @return string
*/
public function getTabUrl()
{
// customtab is a adminhtml router we're about to define
// the full route can really be whatever you want
return $this->getUrl('customtab/*/customTab', ['_current' => true]);
}
}
Next up we want to create app/code/VENDOR/MODULE/etc/adminhtml/routes.xml
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../lib/internal/Magento/Framework/App/etc/routes.xsd">
<router id="admin">
<route id="transzuri_tab" frontName="customtab">
<module name="VENDOR_MODULE" />
</route>
</router>
</config>
Next let's create our controller at app/code/VENDOR/MODULE/Controller/Adminhtml/Order/CustomTab.php
<?php
namespace Sistel\Transzuri\Controller\Adminhtml\Order;
use Magento\Backend\App\Action;
use Magento\Sales\Api\OrderManagementInterface;
use Magento\Sales\Api\OrderRepositoryInterface;
use Psr\Log\LoggerInterface;
class CustomTab extends \Magento\Sales\Controller\Adminhtml\Order
{
/**
* @var \Magento\Framework\View\LayoutFactory
*/
protected $layoutFactory;
/**
* @param Action\Context $context
* @param \Magento\Framework\Registry $coreRegistry
* @param \Magento\Framework\App\Response\Http\FileFactory $fileFactory
* @param \Magento\Framework\Translate\InlineInterface $translateInline
* @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
* @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory
* @param \Magento\Framework\View\Result\LayoutFactory $resultLayoutFactory
* @param \Magento\Framework\Controller\Result\RawFactory $resultRawFactory
* @param OrderManagementInterface $orderManagement
* @param OrderRepositoryInterface $orderRepository
* @param LoggerInterface $logger
* @param \Magento\Framework\View\LayoutFactory $layoutFactory
*
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
public function __construct(
Action\Context $context,
\Magento\Framework\Registry $coreRegistry,
\Magento\Framework\App\Response\Http\FileFactory $fileFactory,
\Magento\Framework\Translate\InlineInterface $translateInline,
\Magento\Framework\View\Result\PageFactory $resultPageFactory,
\Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory,
\Magento\Framework\View\Result\LayoutFactory $resultLayoutFactory,
\Magento\Framework\Controller\Result\RawFactory $resultRawFactory,
OrderManagementInterface $orderManagement,
OrderRepositoryInterface $orderRepository,
LoggerInterface $logger,
\Magento\Framework\View\LayoutFactory $layoutFactory
) {
$this->layoutFactory = $layoutFactory;
parent::__construct(
$context,
$coreRegistry,
$fileFactory,
$translateInline,
$resultPageFactory,
$resultJsonFactory,
$resultLayoutFactory,
$resultRawFactory,
$orderManagement,
$orderRepository,
$logger
);
}
/**
* Generate order history for ajax request
*
* @return \Magento\Framework\Controller\Result\Raw
*/
public function execute()
{
$this->_initOrder();
$layout = $this->layoutFactory->create();
// Yes, this is the same block class that we defined in sales_order_view.xml
$html = $layout->createBlock('Sistel\Transzuri\Block\Adminhtml\Order\View\Tab\Custom')
->toHtml();
$this->_translateInline->processResponseBody($html);
/** @var \Magento\Framework\Controller\Result\Raw $resultRaw */
$resultRaw = $this->resultRawFactory->create();
$resultRaw->setContents($html);
return $resultRaw;
}
}
The last thing you'll need to create is app/code/VENDOR/MODULE/view/adminhtml/templates/order/view/tab/custom.phtml
<section class="admin__page-section custom-tab-content">
<h1>Hello New Tab!</h1>
</section>
After that, just flush your cache and reload the page.