8

I need add a tab tabs of sales order.

enter image description here

I think the tabs are defined in sales_order_view but I create a module in Vendor/ModuleName/view/adminhtml/layout/sales_order_view.xml and I put this:

<?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>
        <referenceBlock name="order_info">
          <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>
    </body>
</page>

And I create in Sistel\Transzuri\Block\Adminhtml\Order\View\Tab\Custom this:

<?php
/**
 * Copyright © 2016 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Sistel\Transzuri\Block\Adminhtml\Order\View\Tab;

/**
 * Order transactions tab
 *
 * @author     Magento Core Team <[email protected]>
 */
class Custom extends \Magento\Framework\View\Element\Text\ListText implements
    \Magento\Backend\Block\Widget\Tab\TabInterface
{
    /**
     * @var \Magento\Framework\AuthorizationInterface
     */
    protected $_authorization;

    /**
     * Core registry
     *
     * @var \Magento\Framework\Registry
     */
    protected $_coreRegistry = null;

    /**
     * @param \Magento\Framework\View\Element\Context $context
     * @param \Magento\Framework\AuthorizationInterface $authorization
     * @param \Magento\Framework\Registry $registry
     * @param array $data
     */
    public function __construct(
        \Magento\Framework\View\Element\Context $context,
        \Magento\Framework\AuthorizationInterface $authorization,
        \Magento\Framework\Registry $registry,
        array $data = []
    ) {
        $this->_authorization = $authorization;
        $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()
    {
        return !$this->getOrder()->getPayment()->getMethodInstance()->isOffline();
    }

    /**
     * {@inheritdoc}
     */
    public function isHidden()
    {
        return !$this->_authorization->isAllowed('Sistel_Transzuri::transzuri');
    }
}

But It not shows in admin panel. Why?

3
  • Have you cleared caches and put/static/adminhtml? Jan 27, 2017 at 11:46
  • Yes but not works
    – AndresF
    Jan 27, 2017 at 11:57
  • I used to build new tab using the above code but have a problem with loading data from ajax URL, It showing 404 error Nov 2, 2018 at 12:12

2 Answers 2

17

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.

2
  • i tried this ... not working
    – Zorox
    Aug 31, 2019 at 9:07
  • Good solution. Worked perfectly. +1 on your answer :) Sep 27, 2019 at 12:35
1

The problem is in your layout. You are defining <referenceBlock name="order_info"> that node is not for the order view tabs. You need to replace that with this:

<referenceBlock name="name="sales_order_tabs">

As always don't forget to clear your caches.

3
  • I think that my loyout is not working. I don't know if this is the error because I do the changes but not show anything. I put errors to do a blank page but it charge the same. I think that layout not do anything and I don't know anything to do.
    – AndresF
    Jan 27, 2017 at 12:24
  • You need to do that under the theme not under a module. Jan 27, 2017 at 12:27
  • but I need a module to install in other magento's
    – AndresF
    Jan 27, 2017 at 12:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.