0

I want to add a custom tab in catalog_product_edit page with my custom module. I want this tab of ajax type, since the tab holds grid content.

To achieve this I rewrite the Mage/Adminhtml/Block/Catalog/Product/Edit/Tabs.php block with my Mysite/Combooffers/Block/Adminhtml/Catalog/Product/Edit/Tabs.php block. It successfully rewrote the core block. My custom tab appeared in the edit page, but while click on the tab, it didnt work properly.

I have gone through the core files, and I found that, for ajax tabs, the action is defined in the controller Mage/Adminhtml/controllers/Catalog/ProductController.php. So I assumed the problem occurs due to my tabs action is not present in the core controller. So I planned to rewrite the above controller with myown Mysite/Combooffers/controllers/Adminhtml/Catalog/ProductController.php. When I rewrote the controller, edit page now shows nothing.

my app/code/local/Mysite/Combooffers/etc/config.xml

<config>
<modules>
    <Mysite_Combooffers>
        <version>0.1.0</version>
    </Mysite_Combooffers>
</modules>
<frontend>
    <routers>
        <Combooffers>
            <use>standard</use>
            <args>
                <module>Mysite_Combooffers</module>
                <frontName>combooffers</frontName>
            </args>
        </Combooffers>
    </routers>
    <layout>
        <updates>
            <combooffers>
                <file>combooffers.xml</file>
            </combooffers>
        </updates>
    </layout>
</frontend>
<admin>
    <routers>
         <adminhtml>
            <args>
                <modules>
                    <Mysite_Combooffers before="Mage_Adminhtml">Mysite_Combooffers_Adminhtml</Mysite_Combooffers>
                </modules>
            </args>
        </adminhtml>
    </routers>
</admin>
<adminhtml>
    <layout>
        <updates>
            <combooffers>
                <file>combooffers.xml</file>
            </combooffers>
        </updates>
    </layout>
</adminhtml>
<global>
    <blocks>
        <combooffers>
            <class>Mysite_Combooffers_Block</class>
            <sort_order>200</sort_order>
        </combooffers>
        <adminhtml>            
            <rewrite>  
                <catalog_product_edit_tabs>
                        Mysite_Combooffers_Block_Adminhtml_Catalog_Product_Edit_Tabs
                </catalog_product_edit_tabs> 
            </rewrite>  
        </adminhtml>
    </blocks>
    <routers>
        <adminhtml>
           <rewrite>
                  <mysite_combooffers_adminhtml_catalog_product>
                      <from><![CDATA[#^admin/catalog_product/$#]]></from>
                      <to>/admin/catalog_product/</to>
                  </mysite_combooffers_adminhtml_catalog_product>
            </rewrite>
       </adminhtml>
    </routers>
    <helpers>
        <combooffers>
            <class>Mysite_Combooffers_Helper</class>
        </combooffers>
    </helpers>
</global>
</config>

app/code/local/Mysite/Combooffers/Block/Adminhtml/Catalog/Product/Edit/Tabs.php

<?php

class Mysite_Combooffers_Block_Adminhtml_Catalog_Product_Edit_Tabs extends Mage_Adminhtml_Block_Catalog_Product_Edit_Tabs
{
    protected function _prepareLayout()
    {
        /**Loads our tab using ajax.
            * ajax tab loads while click on the tab on edit page. Normally use to load grid content.
            * its complex
            * url is the important  one. when click on the tab, it will search for action correspond to the url in the controller.
            * here the action name should be `comboofferAction()`
        */
        $this->addTab('combooffer', array(
                'label'     => Mage::helper('catalog')->__('Combo Products'),
                'url'       => $this->getUrl('*/*/combooffer', array('_current' => true)),
                'class'     => 'ajax',
                'after'     => 'crosssell', //this will set tab after cross-sell tab.
            ));

        return parent::_prepareLayout();
    }
} 

app/code/local/Mysite/Combooffers/Block/Adminhtml/Catalog/Products/Edit/Tab/Combooffer.php

<?php

 class Mysite_Combooffers_Block_Adminhtml_Catalog_Product_Edit_Tab_Combooffer extends Mage_Adminhtml_Block_Widget_Form
 {
/**
 * Set grid params
 *
 */
public function __construct()
{
    parent::__construct();
    $this->setId('combo_offers_product_grid');
    $this->setDefaultSort('entity_id');
    $this->setUseAjax(true);  // Using ajax grid is important
    if ($this->_getProduct()->getId()) {
        $this->setDefaultFilter(array('in_products'=>1)); // By default we have added a filter for the rows, 
                                                          //that in_products value to be 1
    }
   // if ($this->isReadonly()) {
   //     $this->setFilterVisibility(false);
    //}
    $this->setSaveParametersInSession(false);  //Dont save paramters in session or else it creates problems
}

/**
 * Retirve currently edited product model
 *
 * @return Mage_Catalog_Model_Product
 */
protected function _getProduct()
{
    return Mage::registry('current_product');
}

/**
 * Add filter
 *
 * @param object $column
 * @return Mysite_Combooffers_Adminhtml_Block_Catalog_Product_Edit_Tab_Combooffer
 */
protected function _addColumnFilterToCollection($column)
{
    // Set custom filter for in product flag
    if ($column->getId() == 'in_products') {
        $productIds = $this->_getSelectedComboOffers();
        if (empty($productIds)) {
            $productIds = 0;
        }
        if ($column->getFilter()->getValue()) {
            $this->getCollection()->addFieldToFilter('entity_id', array('in'=>$productIds));
        } else {
            if($productIds) {
                $this->getCollection()->addFieldToFilter('entity_id', array('nin'=>$productIds));
            }
        }
    } else {
        parent::_addColumnFilterToCollection($column);
    }
    return $this;
}


/**
 * Prepare collection
 *
 * @return Mage_Adminhtml_Block_Widget_Grid
 */
protected function _prepareCollection()
{
    $collection = Mage::getModel('catalog/product_link')->useUpSellLinks()
        ->getProductCollection()
        ->setProduct($this->_getProduct())
        ->addAttributeToSelect('*');

    if ($this->isReadonly()) {
        $productIds = $this->_getSelectedProducts();
        if (empty($productIds)) {
            $productIds = array(0);
        }
        $collection->addFieldToFilter('entity_id', array('in'=>$productIds));
    }

    $this->setCollection($collection);
    return parent::_prepareCollection();
}

/**
 * Add columns to grid
 *
 * @return Mage_Adminhtml_Block_Widget_Grid
 */
protected function _prepareColumns()
{
    if (!$this->_getProduct()->getUpsellReadonly()) {
        $this->addColumn('in_products', array(
            'header_css_class' => 'a-center',
            'type'      => 'checkbox',
            'name'      => 'in_products',
            'values'    => $this->_getSelectedComboOffers(),
            'align'     => 'center',
            'index'     => 'entity_id'
        ));
    }

    $this->addColumn('entity_id', array(
        'header'    => Mage::helper('catalog')->__('ID'),
        'sortable'  => true,
        'width'     => 60,
        'index'     => 'entity_id'
    ));
    $this->addColumn('name', array(
        'header'    => Mage::helper('catalog')->__('Name'),
        'index'     => 'name'
    ));

    $this->addColumn('type', array(
        'header'    => Mage::helper('catalog')->__('Type'),
        'width'     => 100,
        'index'     => 'type_id',
        'type'      => 'options',
        'options'   => Mage::getSingleton('catalog/product_type')->getOptionArray(),
    ));

    $sets = Mage::getResourceModel('eav/entity_attribute_set_collection')
        ->setEntityTypeFilter(Mage::getModel('catalog/product')->getResource()->getTypeId())
        ->load()
        ->toOptionHash();

    $this->addColumn('set_name', array(
        'header'    => Mage::helper('catalog')->__('Attrib. Set Name'),
        'width'     => 130,
        'index'     => 'attribute_set_id',
        'type'      => 'options',
        'options'   => $sets,
    ));

    $this->addColumn('status', array(
        'header'    => Mage::helper('catalog')->__('Status'),
        'width'     => 90,
        'index'     => 'status',
        'type'      => 'options',
        'options'   => Mage::getSingleton('catalog/product_status')->getOptionArray(),
    ));

    $this->addColumn('visibility', array(
        'header'    => Mage::helper('catalog')->__('Visibility'),
        'width'     => 90,
        'index'     => 'visibility',
        'type'      => 'options',
        'options'   => Mage::getSingleton('catalog/product_visibility')->getOptionArray(),
    ));

    $this->addColumn('sku', array(
        'header'    => Mage::helper('catalog')->__('SKU'),
        'width'     => 80,
        'index'     => 'sku'
    ));

    $this->addColumn('price', array(
        'header'        => Mage::helper('catalog')->__('Price'),
        'type'          => 'currency',
        'currency_code' => (string) Mage::getStoreConfig(Mage_Directory_Model_Currency::XML_PATH_CURRENCY_BASE),
        'index'         => 'price'
    ));

    $this->addColumn('position', array(
        'header'            => Mage::helper('catalog')->__('Position'),
        'name'              => 'position',
        'type'              => 'number',
        'width'             => 60,
        'validate_class'    => 'validate-number',
        'index'             => 'position',
        'editable'          => true,  //!$this->_getProduct()->getUpsellReadonly(),
        'edit_only'         => true  //!$this->_getProduct()->getId()
    ));

    return parent::_prepareColumns();
}

/**
 * Rerieve grid URL
 *
 * @return string
 */
public function getGridUrl()
{
    return $this->_getData('grid_url') ? $this->_getData('grid_url') : $this->getUrl('*/*/combooffer', array('_current'=>true));
}

/**
 * Retrieve selected combo offers
 *
 * @return array
 */
protected function _getSelectedComboOffers()
{
    $products = $this->getSelectedComboOffers();
    if (!is_array($products)) {
        $products = array_keys($this->getSelectedComboOffers());
    }
    return $products;
}

/**
 * Retrieve combo offers
 *
 * @return arraygetSelectedComboOffers
 */
public function getSelectedComboOffers()
{
    $products = array();
    foreach (Mage::registry('current_product')->getUpSellProducts() as $product) {
        $products[$product->getId()] = array('position' => $product->getPosition());
    }
    return $products;
}

}

app/code/local/Mysite/Combooffers/controllers/Adminhtml/Catalog/ProductController.php

<?php

require_once('Mage/Adminhtml/controllers/Catalog/ProductController.php');

class Mysite_Combooffers_Adminhtml_Catalog_ProductController extends Mage_Adminhtml_Catalog_ProductController
{
    /** Use to set content of combo offer tab.
        * Defines layout of combo offer tab.
        * The layout defined here should present in app/design/adminhtml/default/default/<layout>.xml
    */
    public function comboofferAction()
    {
        $this->_initProduct();
        $this->loadLayout();
        $this->getLayout()->getBlock('catalog.product.edit.tab.combooffer')
            ->setProductsUpsell($this->getRequest()->getPost('products_combooffer', null));
        $this->renderLayout();
    }



}

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

<combooffers_adminhtml_combooffer_combooffer>
<adminhtml_catalog_product_upsell>
    <block type="core/text_list" name="root" output="toHtml">
        <block type="adminhtml/catalog_product_edit_tab_upsell" name="catalog.product.edit.tab.combooffer"/>
        <block type="adminhtml/widget_grid_serializer" name="upsell_grid_serializer">
            <reference name="upsell_grid_serializer">
                <action method="initSerializerBlock">                       
                 <grid_block_name>catalog.product.edit.tab.combooffer</grid_block_name>
                    <data_callback>getSelectedComboOffers</data_callback>
                    <hidden_input_name>links[combooffers]</hidden_input_name>
                    <reload_param_name>products_combooffer</reload_param_name>
                </action>
                <action method="addColumnInputName">
                    <input_name>position</input_name>
                </action>
            </reference>
        </block>
    </block>
</adminhtml_catalog_product_upsell>
</combooffers_adminhtml_combooffer_combooffer>

Is there any problem with my approach ? Am I in the right path? What is the error that I have made here? Please give your suggestions. Thanks in advance

4 Answers 4

2

It would be easier if you'd change url for ajax call on tab In

$this->addTab('combooffer', array(
            'label'     => Mage::helper('catalog')->__('Combo Products'),
            'url'       => $this->getUrl('*/*/combooffer', array('_current' => true)),
            'class'     => 'ajax',
            'after'     => 'crosssell', //this will set tab after cross-sell tab.
        ));

url key is creating the path for ajax call. Asteriks means to use the same as current, so */*/combooffer is translated to admin/catalog_product/combooffer. You can change it to */my_controller/combooffer and it should work.

So change file app/code/local/Mysite/Combooffers/controllers/Adminhtml/Catalog/ProductController.php to app/code/local/Mysite/Combooffers/controllers/Adminhtml/Catalog/ComboofferController.php so it would not overwrite core controller and make it extend Mage_Adminhtml_Controller_Action

and in app/code/local/Mysite/Combooffers/Block/Adminhtml/Catalog/Product/Edit/Tabs.php use code: 'url' => $this->getUrl('*/catalog_combooffer/combooffer', array('_current' => true)),

1
  • I have tried your suggestion. It didnt work. Please not that, my edit page does not show any tabs, while I am trying to extend controller. But If I am overwriting block only, all tabs including my tab is displaying and all other tabs except mine are working perfectly. So when I extend controller, eventhough I am including the default controller in my controller file, it does not working. Thats why tabs are not present in edit page. Apr 28, 2014 at 7:16
0

Isn't deprecated (after Magento 1.4 or greater) this:

<routers>
  <adminhtml>
    <rewrite>

You need only:

<admin>
  <routers>
    <adminhtml>
      <args>
        <modules>
          <Mysite_Combooffers before="Mage_Adminhtml">Mysite_Combooffers_Adminhtml</Mysite_Combooffers>

Add a function from the core controller in your controller and add a debug message as first line inside function: with exit(..); - to see if your controller is used.

0

I think the error is caused by the require statement. Try this:

require_once Mage::getModuleDir('controllers', 'Mage_Adminhtml').DS.'Catalog'.DS.'ProductController.php';
4
  • I have used this one. After going through several tutorials, I notice that, most of them use the method that I have used above. Do you see any other errors ? Apr 28, 2014 at 6:23
  • Not really, but since you get a blank page, it must be an error early in the stack. Anything in logs?
    – user4351
    Apr 28, 2014 at 7:18
  • nope. I have one doubt. Is it necessary to overwrite the controller file. Can I use my controller directly (Block/Adminhtml/CombooffersContoller.php) to define the action for ajax tab. Do you have any idea about it? Apr 28, 2014 at 7:40
  • Sorry for the delay. Is this still an issue or did you solve it? I'll try to reproduce locally now if it isn't solved yet.
    – user4351
    May 2, 2014 at 19:10
0

This part was the villain in my case

   <adminhtml>            
        <rewrite>  
            <catalog_product_edit_tabs>
                    Mysite_Combooffers_Block_Adminhtml_Catalog_Product_Edit_Tabs
            </catalog_product_edit_tabs> 
        </rewrite>  
    </adminhtml>

As you can see, I have put unwanted spaces inside the node <catalog_product_edit_tabs /> and thats what make problem in my case.

So it should be like this.

   <adminhtml>            
        <rewrite>  
            <catalog_product_edit_tabs>Mysite_Combooffers_Block_Adminhtml_Catalog_Product_Edit_Tabs</catalog_product_edit_tabs> 
        </rewrite>  
    </adminhtml>
1

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.