Magento Grid Inside Catalog Product Edit Tab

adminhtmlgridmagento-1Wordpress

I'm looking to pull a custom model (wordpress posts) into a grid, and display it on a tab on the side of the new product and product edit pages in the admin panel. I've removed the model and the function that will be used to pull posts for the grid (replaced with simple mage logs that will be enough for me to indicate everything is working thus far) for the sake of brevity.

Currently, you'll get an error stating "Wrong tab configuration." when you go to edit a product in the admin panel. I have, however, been able to get a .phtml template to render inside the tab (not sure if I remember how), as well as just white space inside the tab. I have not been able to figure out how to get that grid in there, though. Here's my code, help greatly appreciated!

app/code/local/Company/WordpressIntegration/etc/config.xml

<?xml version="1.0"?>
<config>
    <modules>
        <Company_wordpressintegration>
            <version>0.1.0</version>
        </Company_wordpressintegration>
    </modules>
    <global>

        <blocks>
            <company_wordpressintegration>
                <class>Company_WordpressIntegration_Block</class>
            </company_wordpressintegration>
        </blocks>
        <helpers>
            <company_wordpressintegration>
                <class>Company_WordpressIntegration_Helper</class>
            </company_wordpressintegration>
        </helpers>
    </global>
    <adminhtml>
        <layout>
            <updates>
                <company_wordpressintegration>
                    <file>producttabs.xml</file>
                </company_wordpressintegration>
            </updates>
        </layout>
        <events>
            <catalog_product_save_after>
                <observers>
                    <wordpressintegration_save_product_data>
                        <type>singleton</type>
                        <class>wordpressintegration/observer/observer</class>
                        <method>saveProductTabData</method>
                    </wordpressintegration_save_product_data>
                </observers>
            </catalog_product_save_after>
        </events>
    </adminhtml>

</config>

app/design/adminhtml/deafult/default/layout/producttabs.xml:

<?xml version="1.0"?>

<layout>
    <adminhtml_catalog_product_edit>
        <reference name="product_tabs">
            <action method="addTabAfter">
                <name>Related Posts</name>
                <block>company_wordpressintegration/adminhtml_catalog_product_tab</block>
                <after>related</after>
            </action>
        </reference>
    </adminhtml_catalog_product_edit>
</layout>

app/code/local/Company/WordpressIntegration/Block/Adminhtml/Tabs/Adminhtml/Catalog/Product/Posts/Tab.php:

<?php

class Company_WordpressIntegration_Block_Adminhtml_Catalog_Product_Tab
    extends Mage_Adminhtml_Block_Template
    implements Mage_Adminhtml_Block_Widget_Tab_Interface
{

    /**
     * Set the template for the block
     *
     */
    public function __construct()
    {

        $this->loadLayout();
        $this->getLayout()->getBlock('wordpressintegration/catalog_product_posts_related');
        $this->renderLayout();

        //$this->setTemplate('wordpressintegration/catalog/product/tab.phtml');
        parent::__construct();
    }

    /**
     * Retrieve the label used for the tab relating to this block
     *
     * @return string
     */
    public function getTabLabel()
    {
        return $this->__('Related Posts');
    }

    /**
     * Retrieve the title used by this tab
     *
     * @return string
     */
    public function getTabTitle()
    {
        return $this->__('Click here to view custom tab content');
    }

    /**
     * Determines whether to display the tab
     * Add logic here to decide whether you want the tab to display
     *
     * @return bool
     */
    public function canShowTab()
    {
        return true;
    }

    /**
     * Stops the tab being hidden
     *
     * @return bool
     */
    public function isHidden()
    {
        return false;
    }

}

app/code/local/Company/WordpressIntegration/Block/Adminhtml/Tabs/Adminhtml/Catalog/Product/Posts/Related/Grid.php:

<?php

class Company_WordpressIntegration_Block_Adminhtml_Catalog_Product_Posts_Related_Grid extends Mage_Adminhtml_Block_Widget_Grid
{
    public function __construct()
    {
        Mage::log('getting to the grid', null, 'grid_test.log');
        parent::__construct();
        $this->setId('company_wordpressintegration_grid');
        $this->setDefaultSort('increment_id');
        $this->setDefaultDir('DESC');
        $this->setSaveParametersInSession(true);
        $this->setUseAjax(true);
    }

    protected function _prepareCollection()
    {
        $collection = Mage::getModel('wordpressintegration/post')->getCollection();

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

    protected function _prepareColumns()
    {
        $helper = Mage::helper('company_wordpressintegration');
        $currency = (string) Mage::getStoreConfig(Mage_Directory_Model_Currency::XML_PATH_CURRENCY_BASE);

        $this->addColumn('increment_id', array(
            'header' => $helper->__('Order #'),
            'index'  => 'increment_id'
        ));

        $this->addColumn('purchased_on', array(
            'header' => $helper->__('Purchased On'),
            'type'   => 'datetime',
            'index'  => 'created_at'
        ));

        $this->addColumn('products', array(
            'header'       => $helper->__('Products Purchased'),
            'index'        => 'products',
            'filter_index' => '(SELECT GROUP_CONCAT(\' \', x.name) FROM sales_flat_order_item x WHERE main_table.entity_id = x.order_id AND x.product_type != \'configurable\')'
        ));

        $this->addColumn('fullname', array(
            'header'       => $helper->__('Name'),
            'index'        => 'fullname',
            'filter_index' => 'CONCAT(customer_firstname, \' \', customer_lastname)'
        ));

        $this->addColumn('city', array(
            'header' => $helper->__('City'),
            'index'  => 'city'
        ));

        $this->addColumn('country', array(
            'header'   => $helper->__('Country'),
            'index'    => 'country_id',
            'renderer' => 'adminhtml/widget_grid_column_renderer_country'
        ));

        $this->addColumn('customer_group', array(
            'header' => $helper->__('Customer Group'),
            'index'  => 'customer_group_code'
        ));

        $this->addColumn('grand_total', array(
            'header'        => $helper->__('Grand Total'),
            'index'         => 'grand_total',
            'type'          => 'currency',
            'currency_code' => $currency
        ));

        $this->addColumn('shipping_method', array(
            'header' => $helper->__('Shipping Method'),
            'index'  => 'shipping_description'
        ));

        $this->addColumn('order_status', array(
            'header'  => $helper->__('Status'),
            'index'   => 'status',
            'type'    => 'options',
            'options' => Mage::getSingleton('sales/order_config')->getStatuses(),
        ));

        $this->addExportType('*/*/exportRelatedCsv', $helper->__('CSV'));
        $this->addExportType('*/*/exportRelatedExcel', $helper->__('Excel XML'));

        return parent::_prepareColumns();
    }

    public function getGridUrl()
    {
        return $this->getUrl('*/*/grid', array('_current'=>true));
    }
}

app/code/local/Company/WordpressIntegration/Block/Adminhtml/Tabs/Adminhtml/Catalog/Product/Posts/Related.php:

<?php

class Company_WordpressIntegration_Block_Adminhtml_Catalog_Product_Posts_Related extends Mage_Adminhtml_Block_Widget_Grid_Container
{
    public function __construct()
    {
        Mage::log('container online!', null, 'grid_test.log');

        $this->_blockGroup = 'wordpressintegration';
        $this->_controller = 'adminhtml_wordpress';
        $this->_headerText = Mage::helper('wordpressintegration')->__('Related Posts');

        parent::__construct();
        //$this->_removeButton('add');
    }
}

app/code/local/Company/WordpressIntegration/Block/Adminhtml/Tabs/Tabid.php:

<?php

class Company_WordpressIntegration_Block_Adminhtml_Tabs_Tabid extends Mage_Adminhtml_Block_Widget
{
    public function __construct()
    {
        parent::__construct();
        $this->setTemplate('wordpressintegration/tab.phtml');
    }
}

app/code/local/Company/WordpressIntegration/controllers/Adminhtml/Catalog/ProductController.php:

<?php

class Company_WordpressIntegration_OrderController extends Mage_Adminhtml_Controller_Action
{
    public function indexAction()
    {
        $this->_title($this->__('Sales'))->_title($this->__('Related Posts'));
        $this->loadLayout();
        $this->_setActiveMenu('sales/sales');
        $this->_addContent($this->getLayout()->createBlock('company_wordpressintegration/adminhtml_posts'));
        $this->renderLayout();
    }

    public function gridAction()
    {
        $this->loadLayout();
        $this->getResponse()->setBody(
            $this->getLayout()->createBlock('company_wordpressintegration/adminhtml_catalog_products_posts_related_grid')->toHtml()
        );
    }

    public function exportPostsCsvAction()
    {
        $fileName = 'company_wordpressintegration.csv';
        $grid = $this->getLayout()->createBlock('company_wordpressintegration/adminhtml_products_posts_related_grid');
        $this->_prepareDownloadResponse($fileName, $grid->getCsvFile());
    }

    public function exportPostsExcelAction()
    {
        $fileName = 'company_wordpressintegration.xml';
        $grid = $this->getLayout()->createBlock('company_wordpressintegration/adminhtml_products_posts_related_grid');
        $this->_prepareDownloadResponse($fileName, $grid->getExcelFile($fileName));
    }
}

app/code/local/Company/WordpressIntegration/controllers/Adminhtml/WordpressController.php:

<?php

class Company_WordpressIntegration_Adminhtml_WordpressController extends Mage_Adminhtml_Controller_Action {


    public function indexAction() {
        Mage::log('wordpress controller online!', null, 'grid_test.log');
        $this->loadLayout()->renderLayout();
    }

    public function postAction() {
        $post = $this->getRequest()->getPost();

        try {
            if (empty($post)) {
                Mage::throwException($this->__('Invalid form data.'));
            }


            $message = $this->__('Your form has been submitted successfully.');
            Mage::getSingleton('adminhtml/session')->addSuccess($message);
        } catch (Exception $e) {
            Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
        }

        $this->_redirect('*/*');
    }

}

app/code/local/Company/WordpressIntegration/Helper/Data.php:

<?php

class Company_wordpressintegration_Helper_Data extends Mage_Core_Helper_Abstract {


    function test() {
        echo 'inside test function'; die('dead');
    }

}

Best Answer

The final solution ended up being modifying Tab.php to look like:

    <?php

class Company_WordpressIntegration_Block_Adminhtml_Catalog_Product_Tab
    extends Mage_Adminhtml_Block_Widget_Grid
    implements Mage_Adminhtml_Block_Widget_Tab_Interface
{

    public function __construct()
    {
        parent::__construct();
        $this->setId('company_wordpressintegration_grid');
        $this->setDefaultSort('ID');
        $this->setDefaultDir('DESC');
        $this->setSaveParametersInSession(true);
        $this->setUseAjax(true);
    }

    protected function _prepareCollection()
    {
        $collection = Mage::getModel('wordpressintegration/post')->getCollection();

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

    protected function _prepareColumns()
    {
        $helper = Mage::helper('company_wordpressintegration');
        $currency = (string) Mage::getStoreConfig(Mage_Directory_Model_Currency::XML_PATH_CURRENCY_BASE);

        $this->addColumn('itemCheckbox', array(
            'index'     => 'ID',
            'type'      => 'checkbox',
            'width'     => 20,
            'sortable'  => false,
            'field_name' => 'map[]'
        ));

        $this->addColumn('ID', array(
            'header' => $helper->__('ID'),
            'index'  => 'ID'
        ));

        $this->addColumn('post_author', array(
            'header' => $helper->__('Author'),
            'index'  => 'post_author'
        ));

        $this->addColumn('post_date', array(
            'header' => $helper->__('Date'),
            'type'   => 'datetime',
            'index'  => 'post_date'
        ));

        $this->addColumn('post_title', array(
            'header' => $helper->__('Title'),
            'index'  => 'post_title'
        ));

        $this->addColumn('post_content', array(
            'header' => $helper->__('Content'),
            'index'  => 'post_content'
        ));

        $this->addColumn('post_status', array(
            'header' => $helper->__('Status'),
            'index'  => 'post_status'
        ));



        $this->addExportType('*/*/exportRelatedCsv', $helper->__('CSV'));
        $this->addExportType('*/*/exportRelatedExcel', $helper->__('Excel XML'));

        return parent::_prepareColumns();
    }

    public function getGridUrl()
    {
        return $this->getUrl('*/*/grid', array('_current'=>true));
    }


    /**
     * Retrieve the label used for the tab relating to this block
     *
     * @return string
     */
    public function getTabLabel()
    {
        return $this->__('Related Projects');
    }

    /**
     * Retrieve the title used by this tab
     *
     * @return string
     */
    public function getTabTitle()
    {
        return $this->__('Click here to view your custom tab content');
    }

    /**
     * Determines whether to display the tab
     * Add logic here to decide whether you want the tab to display
     *
     * @return bool
     */
    public function canShowTab()
    {
        return true;
    }

    /**
     * Stops the tab being hidden
     *
     * @return bool
     */
    public function isHidden()
    {
        return false;
    }

}

This negates the need for the additional grid and grid containers. Notice aside from the grid functions being moved into the tab file, the file now extends the grid, but continues to implement the tab interface.

Related Topic