24

How to add custom button to order view page near "Back" and "Edit"?

silex
  • 4,312
  • 4
  • 22
  • 27

4 Answers4

41

Instead of core hacks or rewrites, just use an observer to add the button to the order:

<adminhtml>
    <events>
        <adminhtml_widget_container_html_before>
            <observers>
                <your_module>
                    <class>your_module/observer</class>
                    <type>singleton</type>
                    <method>adminhtmlWidgetContainerHtmlBefore</method>
                </your_module>
            </observers>
        </adminhtml_widget_container_html_before>
    </events>
</adminhtml>

Then just check in the observer if the type of the block matches the order view:

public function adminhtmlWidgetContainerHtmlBefore($event)
{
    $block = $event->getBlock();

    if ($block instanceof Mage_Adminhtml_Block_Sales_Order_View) {
        $message = Mage::helper('your_module')->__('Are you sure you want to do this?');
        $block->addButton('do_something_crazy', array(
            'label'     => Mage::helper('your_module')->__('Export Order'),
            'onclick'   => "confirmSetLocation('{$message}', '{$block->getUrl('*/yourmodule/crazy')}')",
            'class'     => 'go'
        ));
    }
}

The "getUrl" function of the block will automatically append the current order id to the controller call.

Matthias Kleine
  • 1,228
  • 17
  • 15
  • 1
    no class rewrite, no corefile changed - awesome solution, I can confirm it works at least in 1.8 – simonthesorcerer May 19 '15 at 10:14
  • 2
    This is a MUCH better answer. Answers that require subclassing to override the default Magento classes like this will cause lots of problems with extension conflicts and upgrade incompatibilities. If Magento has a method using an Observer, it is usually the approach. – Phil M Jun 15 '15 at 16:14
23

config.xml:

<global>
    <blocks>
         <adminhtml>
            <rewrite>
                <sales_order_view>Namespace_Module_Block_Adminhtml_Sales_Order_View</sales_order_view>
            </rewrite>
        </adminhtml>
    </blocks>
 </global>

Namespace/Module/Block/Adminhtml/Sales/Order/View.php:

class Namespace_Module_Block_Adminhtml_Sales_Order_View extends Mage_Adminhtml_Block_Sales_Order_View {
    public function  __construct() {

        parent::__construct();

        $this->_addButton('button_id', array(
            'label'     => Mage::helper('xxx')->__('Some action'),
            'onclick'   => 'jsfunction(this.id)',
            'class'     => 'go'
        ), 0, 100, 'header', 'header');
    }
}
Alex Rashkov
  • 9,833
  • 3
  • 32
  • 58
silex
  • 4,312
  • 4
  • 22
  • 27
  • 3
    an example for the 'onclick' method is "confirmSetLocation('{$message}', '{$this->getOkToShipUrl()}')", – Jonathan Day Oct 24 '11 at 23:00
  • needed to call parent::__construct(); in your custom __construct() function, or I would get "Invalid block type" exception. – James Mar 08 '12 at 20:36
  • I'm getting an error when implementing this. @james what did you mean by the parent::__construct? – Tom Mar 25 '12 at 17:03
  • Just got it, for anyone else, I've added it as an answer below – Tom Mar 25 '12 at 17:11
  • 4
    Please use an observer instead of adding a rewrite to such an important core class. With this solution you can get trouble with other extensions and the rewrite is not necessary to achieve this! – Matthias Kleine Feb 02 '15 at 12:06
2

In reference to the comments above about the parent::__constructor, here is what worked for me:

class Name_Module_Block_Adminhtml_Sales_Order_View extends Mage_Adminhtml_Block_Sales_Order_View {

    public function  __construct() {
        $this->_addButton('testbutton', array(
            'label'     => Mage::helper('Sales')->__('Toms Button'),
            'onclick'   => 'jsfunction(this.id)',
            'class'     => 'go'
        ), 0, 100, 'header', 'header');

        parent::__construct();

    }
}
Tom
  • 427
  • 6
  • 27
-2

If you want to do it quick-and-dirty (i.e. editing core files), open app/code/core/Mage/Adminhtml/Block/Sales/Order/View.php and add something like:

    $this->_addButton('order_reorder', array(
        'label'     => Mage::helper('sales')->__('Print Labels'),
        'onclick'   => 'window.open(\'/printouts/' . $this->getOrder()->getRealOrderId() . '.pdf\')',
    ));

You can place that before this block:

    if ($this->_isAllowedAction('emails') && !$order->isCanceled()) {
        $message = Mage::helper('sales')->__('Are you sure you want to send order email to customer?');
        $this->addButton('send_notification', array(
            'label'     => Mage::helper('sales')->__('Send Email'),
            'onclick'   => "confirmSetLocation('{$message}', '{$this->getEmailUrl()}')",
        ));
    }

Your challenge, should you choose to accept is to create a file in local that is an over-ride of the core file, and to post it here!

ʍǝɥʇɐɯ
  • 4,012
  • 7
  • 32
  • 53