Magento: Add Tab to Admin Order Details Page

adminhtmlmagentooverriding

I have created a custom Magento module which extends the core sales order functionality with some custom user input. After an order has been placed I would like to display this data in a custom tab on the order detail page of the admin area. I have managed to get the new tab displaying in the tab list however when I click on the tab it gives me a 404.

Here's my code:

app/code/local/Zac/Attack/etc/config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <modules>
        <Zac_Attack>
            <version>0.1.0</version>
        </Zac_Attack>
    </modules>
    <admin>
        <routers>
            <adminhtml>
                <args>
                    <modules>
                        <!-- Override Adminhtml module here. -->
                        <Zac_Attack_Adminhtml before="Mage_Adminhtml">Zac_Attack_Adminhtml</Zac_Attack_Adminhtml>
                    </modules>
                </args>
            </adminhtml>
        </routers>
    </admin>
    <adminhtml>
        <layout>
            <updates>
                <attack>
                    <file>attack.xml</file>
                </attack>
            </updates>
        </layout>
    </adminhtml>
    <global>
        <blocks>
            <attack>
                <class>Zac_Attack_Block</class>
            </attack>
        </blocks>
    <!-- models, resources, etc -->
    </global>
</config>

app/code/local/Zac/Attack/Block/Adminhtml/Sales/Order/View/Tab/Attack.php:

<?php

class Zac_Attack_Block_Adminhtml_Sales_Order_View_Tab_Design extends Mage_Adminhtml_Block_Template
    implements Mage_Adminhtml_Block_Widget_Tab_Interface
{
    protected function _construct()
    {
        parent::_construct();
        $this->setTemplate( 'attack/sales/order/view/tab/attack.phtml' );
    }

    public function getTabLabel()
    {
        return $this->__( 'Attack' );
    }

    public function getTabTitle()
    {
        return $this->__( 'Attack' );
    }

    public function getTabClass()
    {
        return '';
    }

    public function getClass()
    {
        return $this->getTabClass();
    }

    public function getTabUrl()
    {
        // Here the url gets rewritten to my custom name, throws 404 when called...
        // The url takes the form:
        // http://mydomain.com/admin/sales_order/attack/order_id/1/key/65cbb0c2956dd9413570a2ec8761bef5/
        return $this->getUrl('*/*/attack', array('_current' => true));
    }

    public function canShowTab()
    {
        return true;
    }

    public function isHidden()
    {
        return false;
    }

    public function getOrder()
    {
        return Mage::registry( 'current_order' );
    }
}

app/code/local/Zac/Attack/controllers/Adminhtml/Sales/OrderController.php:

<?php

require_once "Mage/Adminhtml/controllers/Sales/OrderController.php";

class Zac_Attack_Adminhtml_Sales_OrderController extends Mage_Adminhtml_Sales_OrderController
{
    public function viewAction()
    {
        // This doesn't get called when viewing the default order detail page.
        // I should see the <h1> output as the only content on the page but I don't.
        die( '<h1>viewAction()</h1>' );
    }

    public function attackAction()
    {
        // This should be called when the url has the pattern '*/*/attack' (as it does
        // when displaying my custom tab) however clicking this tab gives a 404.
        die('<h1>attackAction()</h1>');
    }
}

app/design/adminhtml/default/default/layout/attack.xml

<?xml version="1.0" encoding="UTF-8"?>
<layout>
    <adminhtml_sales_order_view>
        <reference name="sales_order_tabs">
            <action method="addTab">
                <name>order_design_details</name>
                <block>attack/adminhtml_sales_order_view_tab_design</block>
            </action>
        </reference>
    </adminhtml_sales_order_view>
</layout>

What appears to be failing is the controller override. Neither the overriden method "viewAction()" nor the custom action "attackAction()" get called. I can tell that the config is being picked up because when I print "Mage::getConfig()->getNode('admin/routers/adminhtml')" I can see the following output:

Mage_Core_Model_Config_Element Object
(
    [args] => Mage_Core_Model_Config_Element Object
        (
            [module] => Mage_Adminhtml
            [modules] => Mage_Core_Model_Config_Element Object
                (
                    [Mage_Index] => Mage_Index_Adminhtml
                    [Mage_Paygate] => Mage_Paygate_Adminhtml
                    [Mage_Paypal] => Mage_Paypal_Adminhtml
                    [widget] => Mage_Widget_Adminhtml
                    [Mage_GoogleOptimizer] => Mage_GoogleOptimizer_Adminhtml
                    [Mage_GoogleBase] => Mage_GoogleBase_Adminhtml
                    [Mage_Authorizenet] => Mage_Authorizenet_Adminhtml
                    [Mage_Bundle] => Mage_Bundle_Adminhtml
                    [Mage_Centinel] => Mage_Centinel_Adminhtml
                    [Mage_Compiler] => Mage_Compiler_Adminhtml
                    [connect] => Mage_Connect_Adminhtml
                    [Mage_Downloadable] => Mage_Downloadable_Adminhtml
                    [importexport] => Mage_ImportExport_Adminhtml
                    [Mage_PageCache] => Mage_PageCache_Adminhtml
                    [xmlconnect] => Mage_XmlConnect_Adminhtml
                    [EM_DeleteOrder_Adminhtml] => EM_DeleteOrder_Adminhtml
                    [find_feed] => Find_Feed_Adminhtml
                    [moneybookers] => Phoenix_Moneybookers
                    [Zac_Attack_Adminhtml] => Zac_Attack_Adminhtml
                )

            [frontName] => admin
        )

    [use] => admin
)

So, my first question is: Am I following the correct approach for adding a custom tab to the page?

If I am not following the correct approach can you please advise me what the correct approach is or provide a link which clearly outlines the whole approach (there are too many answer fragments when searching for Magento information, not enough whole answers).

If I am following the correct approach, why is my controller not overriding?

Well, I hope that I've provided enough detail to make the problem clear. If not, feel free to post follow up questions in the comments and I'll be happy to elaborate – if I know how.

Thanks in advance for any help offered.

Cheers,
Zac

P.S. I noticed that there is another module in the community section overriding the same controller – however that override doesn't appear to be taking effect either. Regardless, I have completely removed the 3rd party module for the purposes of debugging to ensure that there is no interference.

Best Answer

Well, this isn't the first time the solution wasn't what I was expecting it to be. As I mentioned in reply to OSDave's comments above, my module code was written exactly as it should be - the problem was with another module overriding the same controller.

For future reference, if you think you've got your controller override done right (admin or frontend - should be the same either way) but it isn't working, I highly recommend using "Mage::getConfig()->getNode('admin/routers/adminhtml')" to debug. Just make sure the XPath in the getNode method is appropriate for the module you're overriding and then look for any entries that aren't clearly Magento.

Hopefully this will save some others the hours I wasted on the problem.

Cheers, Zac

Related Topic