In this blog we will see how to add a grid with tab in an admin page. I have added a grid for showing news in admin side and there is option for adding,editing and deleting news. I have implemented the WYSIWYG editor also. In the last of this tutorial, i have explained how to add the WYSIWYG editor also. You can check the screen shot to get basic idea of what we are going to do in this tutorial. The folder structure will be The grid will be Here is the first tab for adding new news and the second one is the second tab for adding the content with WYSIWYG editor. Create the module News in the namespace of Threemauto. Step 1 : First we will create the directory structure for our module
app/code/local/Threemauto/News/Block
app/code/local/Threemauto/News/controllers
app/code/local/Threemauto/News/etc
app/code/local/Threemauto/News/Helper
app/code/local/Threemauto/News/Model
app/code/local/Threemauto/News/sql
Step 2 : Create a configuration file for the module in the location app/code/local/Threemauto/News/etc/config.xml

    
        
            true 
            local
        
    

Step 4 : Now we are going to configure the route. For that add the following code in the tag of the config.xml file

        
            
                standard
                
                    Threemauto_News
                    news 
                
            
        

Here inside the tag , what will be given you will be the name of the url of your module. So here, it is , your url become www.magentoproject.com/index.php/news. Step 5 : Next we will add a helper configuration in our config.xml file. Because in the going forward steps, we will use some helper method in our module. So add this code in the config.xml file. Note that the code should be inside the tab.

        
            
                Threemauto_News_Helper 
                
            
        

Step 6 : So we want create a helper class that we specified in the congig file. For that go to app/code/local/Threemauto/News/Helper and create a Data.php file there. That file should extends the Mage_Core_Helper_Abstract class of magento. The file will be
class Threemauto_News_Helper_Data extends Mage_Core_Helper_Abstract { 
}
Step 7 : Create an action controller for our route. Go to app/code/local/Threemauto/News/controllers/IndexController.php. The code in this file will be
class Threemauto_News_indexController extends Mage_Core_Controller_Front_Action {
    public function indexAction() {
        echo $this->__('Our News module is ready');
    }
}
Thats it. We created our module. Go to your browser and type www.yourproject.com/index.php/news. It will display 'Our News module is ready'. Developing Model Next we are going to develop the model. The model is responsible for the database connectivity in magento. In magento, model is devided in to two. First one is the Model file-which is responsible for the logical operations and second one is the Resource file-which is responsible for the database queries. Update the config.xml file with the following code to get the model and resource in our module.

        
            
                Threemauto_News_Block 
            
        
        
            
                Threemauto_News_Model
                test_mysql4
            
            
                Threemauto_News_Model_Mysql4
                
                    
                        news
Threemauto_News core_setup core_write core_read
There is one additional block is there (which is not related to the model and resource) in thetag. This is the path of our block folder, where all the php files for the view is located. Threemauto_News_Model is the location of our model class file and test_mysql4 is the location of our resource model. Also we can see that news
, here news is the name of the table in the database. Next in the tag we are giving permision for the read and write operations for our module in the database. In the next step, we will create the model file. So create the News.php file in the location Threemauto/News/Model. The code for this file will be
class Threemauto_News_Model_News extends Mage_Core_Model_Abstract {
 
    public function _construct() {
        parent::_construct();
        $this->_init('news/news');
    }
}
We can see that $this->_init('news/news') . This is actually the location of our resource file. So now we want to create the resource file. Let us create the Mysql4 folder in the Model folder and create the file News.php in it . The code for this file is
class Threemauto_News_Model_Mysql4_News extends Mage_Core_Model_Mysql4_Abstract {
 
    public function _construct() {
        $this->_init('news/news', 'news_id');
    }
}
Here the news_id is the primary key in our table news. In the next step we will create the sql file for creating our database table. Our table name is 'news'. So create the table news_setup in the sql folder and create the file mysql4-install-0.1.0.php in it.
$installer = $this;
$installer->startSetup();
$installer->run("
-- DROP TABLE IF EXISTS {$this->getTable('news')};
CREATE TABLE {$this->getTable('news')} (
  `news_id` int(11) unsigned NOT NULL auto_increment,
  `title` varchar(255) NOT NULL default '',
  `description` varchar(255) NOT NULL default '',
  PRIMARY KEY (`news_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
");
$installer->endSetup();
Now we created our table. Referesh your project and check the table 'core_resource' in the database. There you can find 'news_setup' with version. So your table is created. Check table 'news' exist in the database. Developing Grid Here we are going to create the grid with tab in the admin side. For that create the folder Adminhtml in the Block folder of our module. Let us create the News.php file in it. The code for this file will be
class Threemauto_News_Block_Adminhtml_News extends Mage_Adminhtml_Block_Widget_Grid_Container {
 
    public function __construct() {
        $this->_controller = 'adminhtml_news';
        $this->_blockGroup = 'news';
        $this->_headerText = Mage::helper('news')->__('News Manager');
        $this->_addButtonLabel = Mage::helper('news')->__('Add News');
        parent::__construct();
    }
}
Here we can see two variables. $this->_controller = 'adminhtml_news'; $this->_blockGroup = 'news'; This tells the path of our Grid file , so here the path will be news/adminhtml/news. So create our Grid.php file in the location Threemauto/News/Block/Adminhtml/News.
class Threemauto_News_Block_Adminhtml_News_Grid extends Mage_Adminhtml_Block_Widget_Grid {
 
    public function __construct() {
        parent::__construct();
        $this->setId('news_grid');
        $this->setDefaultSort('news_id');
        $this->setDefaultDir('ASC');
        $this->setSaveParametersInSession(true);
    }
 
    protected function _prepareCollection() {
        $collection = Mage::getModel('news/news')->getCollection();
        $this->setCollection($collection);
        return parent::_prepareCollection();
    }
 
    protected function _prepareColumns() {
        $this->addColumn('news_id', array(
            'header' => Mage::helper('news')->__('ID'),
            'align' => 'right',
            'width' => '10px',
            'index' => 'news_id',
        ));
 
        $this->addColumn('title', array(
            'header' => Mage::helper('news')->__('Title'),
            'align' => 'left',
            'index' => 'title',
            'width' => '50px',
        ));
 
 
        $this->addColumn('description', array(
            'header' => Mage::helper('news')->__('Description'),
            'width' => '150px',
            'index' => 'description',
        ));
 
        $this->addColumn('tag', array(
            'header' => Mage::helper('news')->__('Tag'),
            'width' => '150px',
            'index' => 'tag',
        ));
 
 
        $this->addColumn('date', array(
            'header' => Mage::helper('news')->__('Posted On'),
            'width' => '150px',
            'index' => 'date',
        ));
 
        return parent::_prepareColumns();
    }
 
 
    public function getRowUrl($row) {
        return $this->getUrl('*/*/edit', array('id' => $row->getId()));
    }
}
Note some few thisg here, $this->setId('news_grid') : This is the grid id. $this->setDefaultSort('news_id') : Indicates which column will be used for the default sorting. $this->setDefaultDir('ASC') : Sorting order In the method _prepareColumns(), we are creating the columns . $this->addColumn('news_id', array( 'header' => Mage::helper('news')->__('ID'), 'align' => 'right', 'width' => '10px', 'index' => 'news_id', )); now we created the first column, that will display the ID in the grid. $this->addColumn('title', array( 'header' => Mage::helper('news')->__('Title'), 'align' => 'left', 'index' => 'title', 'width' => '50px', )); this will add the column Title, which will display the title and so on. Next we want to add this menu in admin page. So update the config.xml file with the following codes. Note that this should be in the tag of the tag

    
        
            News
            1212              
            
                
                    Manage News
                    news/adminhtml_news
                
            
        
    
    
        
            
                Allow Everything
            
            
                
                    
                        News Module
                        10
                    
                
            
        
    
    
        
            
                news.xml
            
        
    

In the tag we should provide the dropdown menu details, in our case it is 'Mange News'. Note that in the tag we added news.xml. This is the layout file in our adminhtml layouts. So create the file news.xml in the location app/design/adminhtml/default/default/layout.

    
        
            
        
    

    
        
            
                1
            
            
                
            
            
                
            
            
                
            
            
                
            
            
                
            
            
                
            
            
                
            
            
                js_css
                prototype/windows/themes/default.css
            
            
                js_css
                prototype/windows/themes/magento.css
            
            
                lib/prototype/windows/themes/magento.css
                   
        
    

In the next step we will create the controller file. So create 'Adminhtml' folder in the controllers folder of our module. And create the file NewsController.php in it.
class Threemauto_News_Adminhtml_NewsController extends Mage_Adminhtml_Controller_action {
 
    public function indexAction() {
        $this->loadLayout();
        $this->renderLayout();
    }
 
    public function newAction(){
        $this->loadLayout();
        $this->_addContent($this->getLayout()->createBlock('news/adminhtml_news_edit'))
                ->_addLeft($this->getLayout()->createBlock('news/adminhtml_news_edit_tabs'));
        $this->renderLayout();
    }
 
    public function deleteAction() {
        if ($this->getRequest()->getParam('id') > 0) {
            try {
                $model = Mage::getModel('news/news');
 
                $model->setId($this->getRequest()->getParam('id'))
                        ->delete();
 
                Mage::getSingleton('adminhtml/session')->addSuccess(Mage::helper('adminhtml')->__('Item was successfully deleted'));
                $this->_redirect('*/*/');
            } catch (Exception $e) {
                Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
                $this->_redirect('*/*/edit', array('id' => $this->getRequest()->getParam('id')));
            }
        }
        $this->_redirect('*/*/');
    }
 
    public function saveAction() {
 
        if ($data = $this->getRequest()->getPost())
        {
            $model = Mage::getModel('news/news');
            $id = $this->getRequest()->getParam('id');
            foreach ($data as $key => $value)
            {
                if (is_array($value))
                {
                        $data[$key] = implode(',',$this->getRequest()->getParam($key));
                }
            }
 
            if ($id) {
                $model->load($id);
            }
            $model->setData($data);
 
            Mage::getSingleton('adminhtml/session')->setFormData($data);
            try {
                if ($id) {
                    $model->setId($id);
                }
 
                $model->save();
 
                if (!$model->getId()) {
                    Mage::throwException(Mage::helper('news')->__('Error saving news details'));
                }
 
                Mage::getSingleton('adminhtml/session')->addSuccess(Mage::helper('news')->__('Details was successfully saved.'));
 
                Mage::getSingleton('adminhtml/session')->setFormData(false);
 
                // The following line decides if it is a "save" or "save and continue"
                if ($this->getRequest()->getParam('back')) {
                    $this->_redirect('*/*/edit', array('id' => $model->getId()));
                } else {
                    $this->_redirect('*/*/');
                }
 
            } catch (Exception $e) {
                Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
                if ($model && $model->getId()) {
                    $this->_redirect('*/*/edit', array('id' => $model->getId()));
                } else {
                    $this->_redirect('*/*/');
                }
            }
 
          return;
        }
        Mage::getSingleton('adminhtml/session')->addError(Mage::helper('news')->__('No data found to save'));
        $this->_redirect('*/*/');
    }
 
 
    public function editAction() {
 
        $id = $this->getRequest()->getParam('id', null);
 
        $model = Mage::getModel('news/news');
        if ($id) {
            $model->load((int) $id);
            if ($model->getId()) {
                $data = Mage::getSingleton('adminhtml/session')->getFormData(true);
                if ($data) {
                    $model->setData($data)->setId($id);
                }
            } else {
                Mage::getSingleton('adminhtml/session')->addError(Mage::helper('news')->__('news does not exist'));
                $this->_redirect('*/*/');
            }
        }
        Mage::register('news_data', $model);
 
        $this->_title($this->__('News'))->_title($this->__('Edit news'));
        $this->loadLayout();
        $this->getLayout()->getBlock('head')->setCanLoadExtJs(true);
 
        $this->_addContent($this->getLayout()->createBlock('news/adminhtml_news_edit'))
                ->_addLeft($this->getLayout()->createBlock('news/adminhtml_news_edit_tabs'));
        $this->renderLayout();
    }    
}
Note the function newAction() : This function is responsible for displaying the form in our controller. Here we addeded two blocks. One is for the 'Tabs' in the left side and other is the 'content' in the right side. Pease note the attached screen shot. There are so many methods are there. They are responsible for save the news, delete the news and edit the news. In the next step we will develop the form container. For that we will create the file Edit.php in the location Threemauto/News/Block/Adminhtml/News.
class Threemauto_News_Block_Adminhtml_News_Edit extends Mage_Adminhtml_Block_Widget_Form_Container {
 
    public function __construct() {
        parent::__construct();
 
        $this->_objectId = 'id';
        $this->_blockGroup = 'news';
        $this->_controller = 'adminhtml_news';
        $this->_mode = 'edit';
        $this->_updateButton('save', 'label', Mage::helper('news')->__('Save News'));
        $this->_updateButton('delete', 'label', Mage::helper('news')->__('Delete'));
        $this->_addButton('saveandcontinue', array(
            'label' => Mage::helper('news')->__('Save And Continue Edit'),
            'onclick' => 'saveAndContinueEdit()',
            'class' => 'save',
                ), -100);
 
        $this->_formScripts[] = "
            function toggleEditor() {
                if (tinyMCE.getInstanceById('form_content') == null) {
                    tinyMCE.execCommand('mceAddControl', false, 'edit_form');
                } else {
                    tinyMCE.execCommand('mceRemoveControl', false, 'edit_form');
                }
            }
 
            function saveAndContinueEdit(){
                editForm.submit($('edit_form').action+'back/edit/');
            }
        ";
    }
/*
 * This function is responsible for Including TincyMCE in Head.
 */
    protected function _prepareLayout() {
        parent::_prepareLayout();
        if (Mage::getSingleton('cms/wysiwyg_config')->isEnabled()) {
            $this->getLayout()->getBlock('head')->setCanLoadTinyMce(true);
            $this->getLayout()->getBlock('head')->setCanLoadExtJs(true);
        }
    }
 
 
    public function getHeaderText() {
        if (Mage::registry('news_data') && Mage::registry('news_data')->getId()) {
            return Mage::helper('news')->__('Edit News "%s"', $this->htmlEscape(Mage::registry('news_data')->getTitle()));
        } else {
            return Mage::helper('news')->__('New News');
        }
    }
}
Next we will create the form tag. So create the file Form.php in the location Threemauto_News_Block_Adminhtml_News_Edit
class Threemauto_News_Block_Adminhtml_News_Edit_Form extends Mage_Adminhtml_Block_Widget_Form {
 
    protected function _prepareForm() {
 
        if (Mage::registry('news_data')) {
            $data = Mage::registry('news_data')->getData();
        } else {
            $data = array();
        }
 
        $form = new Varien_Data_Form(array(
            'id' => 'edit_form',
            'action' => $this->getUrl('*/*/save', array('id' => $this->getRequest()->getParam('id'))),
            'method' => 'post',
            'enctype' => 'multipart/form-data'
                )
        );
 
        $form->setUseContainer(true);
        $this->setForm($form);
        $form->setValues($data);
        return parent::_prepareForm();
    }
}
Next we want to develop the form tabs. There are two tabs in our form. You
class Threemauto_News_Block_Adminhtml_News_Edit_Tabs extends Mage_Adminhtml_Block_Widget_Tabs {
 
    public function __construct() {
        parent::__construct();
        $this->setId('news_tabs');
        $this->setDestElementId('edit_form'); // this should be same as the form id define above
        $this->setTitle(Mage::helper('news')->__('News Information'));
    }
 
    protected function _beforeToHtml() {
        $this->addTab('form_section', array(
            'label' => Mage::helper('news')->__('News Information'),
            'title' => Mage::helper('news')->__('News Information'),
            'content' => $this->getLayout()->createBlock('news/adminhtml_news_edit_tab_form')->toHtml(),
        ));
 
        $this->addTab('form_section1', array(
            'label' => Mage::helper('news')->__('Content'),
            'title' => Mage::helper('news')->__('Content'),
            'content' => $this->getLayout()->createBlock('news/adminhtml_news_edit_tab_content')->toHtml(),
        ));
 
        return parent::_beforeToHtml();
    }
}
Note that there are two tabs are there . One is 'News Information' and the other is 'Content' . So in the _beforeToHtml() function we specified the actual form field's location. ie for the first tab, we want to create the file Form.php in the location Threemauto/News/Block/Adminhtml/News/Edit/Tab and for the second tab we want to create Content.php in the location Threemauto/News/Block/Adminhtml/News/Edit/Tab. The code in the two files follows
class Threemauto_News_Block_Adminhtml_News_Edit_Tab_Form extends Mage_Adminhtml_Block_Widget_Form {
 
    protected function _prepareForm() {
 
        if (Mage::registry('news_data')) {
            $data = Mage::registry('news_data')->getData();
        } else {
            $data = array();
        }
 
        $form = new Varien_Data_Form();
        $this->setForm($form);
        $fieldset = $form->addFieldset('news_news', array('legend' => Mage::helper('news')->__('news information')));
 
        $fieldset->addField('title', 'text', array(
            'label' => Mage::helper('news')->__('News Title'),
            'class' => 'required-entry',
            'required' => true,
            'name' => 'title',
        ));
 
        $fieldset->addField('tag', 'text', array(
            'label' => Mage::helper('news')->__('Tag'),
            'class' => 'required-entry',
            'required' => true,
            'name' => 'tag',
        ));
 
        $form->setValues($data);
 
        return parent::_prepareForm();
    }
}
class Threemauto_News_Block_Adminhtml_News_Edit_Tab_Content extends Mage_Adminhtml_Block_Widget_Form {
 
    protected function _prepareForm() {
 
        if (Mage::registry('news_data')) {
            $data = Mage::registry('news_data')->getData();
        } else {
            $data = array();
        }
 
        $form = new Varien_Data_Form();
        $this->setForm($form);
        $fieldset = $form->addFieldset('news_news', array('legend' => Mage::helper('news')->__('More information')));
 
        /*
         * Editing the form field in wysiwyg editor.
         */
 
        $wysiwygConfig = Mage::getSingleton('cms/wysiwyg_config')->getConfig();
        $wysiwygConfig->addData(array('add_variables' => false,
            'add_widgets' => true,
            'add_images' => true,
            'directives_url' => Mage::getSingleton('adminhtml/url')->getUrl('adminhtml/cms_wysiwyg/directive'),
            'directives_url_quoted' => preg_quote(Mage::getSingleton('adminhtml/url')->getUrl('adminhtml/cms_wysiwyg/directive')),
            'widget_window_url' => Mage::getSingleton('adminhtml/url')->getUrl('adminhtml/widget/index'),
            'files_browser_window_url' => Mage::getSingleton('adminhtml/url')->getUrl('adminhtml/cms_wysiwyg_images/index'),
            'files_browser_window_width' => (int) Mage::getConfig()->getNode('adminhtml/cms/browser/window_width'),
            'files_browser_window_height' => (int) Mage::getConfig()->getNode('adminhtml/cms/browser/window_height')
        ));
 
 
        $fieldset->addField('description', 'editor', array(
            'name' => 'description',
            'label' => Mage::helper('news')->__('Description'),
            'title' => Mage::helper('news')->__('Description'),
            'style' => 'width:800px; height:500px;',
            'config' => $wysiwygConfig,
            'required' => false,
            'wysiwyg' => true
        ));
 
        $form->setValues($data);
    }
}
Thats it.... Finally we developed our module with Grid in admin page. Here i have added the WYSIWYG editor too. There is only 3 steps for implementing this editor in our module. These steps are already covered in this tutorial, but here is a breaf information about implementing wysiwyg editor Step 1 : Including WYSIWYG editor in head. Please note in the file app/code/local/Threemauto/News/Block/Adminhtml/News/Edit.php i have added the following code
protected function _prepareLayout() {
        parent::_prepareLayout();
        if (Mage::getSingleton('cms/wysiwyg_config')->isEnabled()) {
            $this->getLayout()->getBlock('head')->setCanLoadTinyMce(true);
            $this->getLayout()->getBlock('head')->setCanLoadExtJs(true);
        }
    }
 
this is enough.
Step 2 : Add the content filed in the Adminhtml form class Please go to app/code/local/Threemauto/News/Block/Adminhtml/News/Edit/Tab/Content.php there i have added
$wysiwygConfig = Mage::getSingleton('cms/wysiwyg_config')->getConfig();
        $wysiwygConfig->addData(array('add_variables' => false,
            'add_widgets' => true,
            'add_images' => true,
            'directives_url' => Mage::getSingleton('adminhtml/url')->getUrl('adminhtml/cms_wysiwyg/directive'),
            'directives_url_quoted' => preg_quote(Mage::getSingleton('adminhtml/url')->getUrl('adminhtml/cms_wysiwyg/directive')),
            'widget_window_url' => Mage::getSingleton('adminhtml/url')->getUrl('adminhtml/widget/index'),
            'files_browser_window_url' => Mage::getSingleton('adminhtml/url')->getUrl('adminhtml/cms_wysiwyg_images/index'),
            'files_browser_window_width' => (int) Mage::getConfig()->getNode('adminhtml/cms/browser/window_width'),
            'files_browser_window_height' => (int) Mage::getConfig()->getNode('adminhtml/cms/browser/window_height')
        ));
 
 
        $fieldset->addField('description', 'editor', array(
            'name' => 'description',
            'label' => Mage::helper('news')->__('Description'),
            'title' => Mage::helper('news')->__('Description'),
            'style' => 'width:800px; height:500px;',
            'config' => $wysiwygConfig,
            'required' => false,
            'wysiwyg' => true
        ));
Step 3 : Add the JS files in the location app/design/adminhtml/default/default/layout/news.xml. (Check in this file) Thats all.... Hope that this blog will help you Thanks and Regards