Create Admin (Backend) Module in Magento with Grids

If you are creating an admin module for Magento (learn creating admin module in Magento) then you would surely be asked to create grids (eg. for order listing). Creating grids can be somewhat difficult for the novice Magento programmers, but in this tutorial we will create a grid in the admin module in the simplest possible way. It is assumed that you are familiar with creating admin module in Magento.

Download Magento Backend Module

Namespace : Company
Module name : Web

Note: Please create necessary xmls for our module (this step has been skipped for simplicity).

Step 1:
Create Web/Block/Adminhtml/Web.php
<?php
class Company_Web_Block_Adminhtml_Web extends Mage_Adminhtml_Block_Widget_Grid_Container
{
public function __construct()
{
$this->_controller = 'adminhtml_web';
$this->_blockGroup = 'web';
$this->_headerText = Mage::helper('web')->__('Item Manager');
$this->_addButtonLabel = Mage::helper('web')->__('Add Item');
parent::__construct();
}
}

Step 2:
Create Web/Block/Adminhtml/Web/Grid.php
<?php

class Company_Web_Block_Adminhtml_Web_Grid extends Mage_Adminhtml_Block_Widget_Grid
{
public function __construct()
{
parent::__construct();
$this->setId('webGrid');
$this->setDefaultSort('web_id');
$this->setDefaultDir('ASC');
$this->setSaveParametersInSession(true);
}

protected function _prepareCollection()
{
$collection = Mage::getModel('web/web')->getCollection();
$this->setCollection($collection);
return parent::_prepareCollection();
}

protected function _prepareColumns()
{
$this->addColumn('web_id', array(
'header' => Mage::helper('web')->__('ID'),
'align' =>'right',
'width' => '50px',
'index' => 'web_id',
));

$this->addColumn('title', array(
'header' => Mage::helper('web')->__('Title'),
'align' =>'left',
'index' => 'title',
));

/*
$this->addColumn('content', array(
'header' => Mage::helper('web')->__('Item Content'),
'width' => '150px',
'index' => 'content',
));
*/

$this->addColumn('status', array(
'header' => Mage::helper('web')->__('Status'),
'align' => 'left',
'width' => '80px',
'index' => 'status',
'type' => 'options',
'options' => array(
1 => 'Enabled',
2 => 'Disabled',
),
));

$this->addColumn('action',
array(
'header' => Mage::helper('web')->__('Action'),
'width' => '100',
'type' => 'action',
'getter' => 'getId',
'actions' => array(
array(
'caption' => Mage::helper('web')->__('Edit'),
'url' => array('base'=> '*/*/edit'),
'field' => 'id'
)
),
'filter' => false,
'sortable' => false,
'index' => 'stores',
'is_system' => true,
));

$this->addExportType('*/*/exportCsv', Mage::helper('web')->__('CSV'));
$this->addExportType('*/*/exportXml', Mage::helper('web')->__('XML'));

return parent::_prepareColumns();
}

protected function _prepareMassaction()
{
$this->setMassactionIdField('web_id');
$this->getMassactionBlock()->setFormFieldName('web');

$this->getMassactionBlock()->addItem('delete', array(
'label' => Mage::helper('web')->__('Delete'),
'url' => $this->getUrl('*/*/massDelete'),
'confirm' => Mage::helper('web')->__('Are you sure?')
));

$statuses = Mage::getSingleton('web/status')->getOptionArray();

array_unshift($statuses, array('label'=>'', 'value'=>''));
$this->getMassactionBlock()->addItem('status', array(
'label'=> Mage::helper('web')->__('Change status'),
'url' => $this->getUrl('*/*/massStatus', array('_current'=>true)),
'additional' => array(
'visibility' => array(
'name' => 'status',
'type' => 'select',
'class' => 'required-entry',
'label' => Mage::helper('web')->__('Status'),
'values' => $statuses
)
)
));
return $this;
}

public function getRowUrl($row)
{
return $this->getUrl('*/*/edit', array('id' => $row->getId()));
}

}

Step 3:
Create Web/controllers/Adminhtml/WebController.php
<?php

class Company_Web_Adminhtml_WebController extends Mage_Adminhtml_Controller_action
{

protected function _initAction() {
$this->loadLayout()
->_setActiveMenu('web/items')
->_addBreadcrumb(Mage::helper('adminhtml')->__('Items Manager'), Mage::helper('adminhtml')->__('Item Manager'));

return $this;
}

public function indexAction() {
$this->_initAction()
->renderLayout();
}

public function editAction() {
$id = $this->getRequest()->getParam('id');
$model = Mage::getModel('web/web')->load($id);

if ($model->getId() || $id == 0) {
$data = Mage::getSingleton('adminhtml/session')->getFormData(true);
if (!empty($data)) {
$model->setData($data);
}

Mage::register('web_data', $model);

$this->loadLayout();
$this->_setActiveMenu('web/items');

$this->_addBreadcrumb(Mage::helper('adminhtml')->__('Item Manager'), Mage::helper('adminhtml')->__('Item Manager'));
$this->_addBreadcrumb(Mage::helper('adminhtml')->__('Item News'), Mage::helper('adminhtml')->__('Item News'));

$this->getLayout()->getBlock('head')->setCanLoadExtJs(true);

$this->_addContent($this->getLayout()->createBlock('web/adminhtml_web_edit'))
->_addLeft($this->getLayout()->createBlock('web/adminhtml_web_edit_tabs'));

$this->renderLayout();
} else {
Mage::getSingleton('adminhtml/session')->addError(Mage::helper('web')->__('Item does not exist'));
$this->_redirect('*/*/');
}
}

public function newAction() {
$this->_forward('edit');
}

public function saveAction() {
if ($data = $this->getRequest()->getPost()) {

if(isset($_FILES['filename']['name']) && $_FILES['filename']['name'] != '') {
try {
/* Starting upload */
$uploader = new Varien_File_Uploader('filename');

// Any extention would work
$uploader->setAllowedExtensions(array('jpg','jpeg','gif','png'));
$uploader->setAllowRenameFiles(false);

// Set the file upload mode
// false -> get the file directly in the specified folder
// true -> get the file in the product like folders
// (file.jpg will go in something like /media/f/i/file.jpg)
$uploader->setFilesDispersion(false);

// We set media as the upload dir
$path = Mage::getBaseDir('media') . DS ;
$uploader->save($path, $_FILES['filename']['name'] );

} catch (Exception $e) {

}

//this way the name is saved in DB
$data['filename'] = $_FILES['filename']['name'];
}


$model = Mage::getModel('web/web');
$model->setData($data)
->setId($this->getRequest()->getParam('id'));

try {
if ($model->getCreatedTime == NULL || $model->getUpdateTime() == NULL) {
$model->setCreatedTime(now())
->setUpdateTime(now());
} else {
$model->setUpdateTime(now());
}

$model->save();
Mage::getSingleton('adminhtml/session')->addSuccess(Mage::helper('web')->__('Item was successfully saved'));
Mage::getSingleton('adminhtml/session')->setFormData(false);

if ($this->getRequest()->getParam('back')) {
$this->_redirect('*/*/edit', array('id' => $model->getId()));
return;
}
$this->_redirect('*/*/');
return;
} catch (Exception $e) {
Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
Mage::getSingleton('adminhtml/session')->setFormData($data);
$this->_redirect('*/*/edit', array('id' => $this->getRequest()->getParam('id')));
return;
}
}
Mage::getSingleton('adminhtml/session')->addError(Mage::helper('web')->__('Unable to find item to save'));
$this->_redirect('*/*/');
}

public function deleteAction() {
if( $this->getRequest()->getParam('id') > 0 ) {
try {
$model = Mage::getModel('web/web');

$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 massDeleteAction() {
$webIds = $this->getRequest()->getParam('web');
if(!is_array($webIds)) {
Mage::getSingleton('adminhtml/session')->addError(Mage::helper('adminhtml')->__('Please select item(s)'));
} else {
try {
foreach ($webIds as $webId) {
$web = Mage::getModel('web/web')->load($webId);
$web->delete();
}
Mage::getSingleton('adminhtml/session')->addSuccess(
Mage::helper('adminhtml')->__(
'Total of %d record(s) were successfully deleted', count($webIds)
)
);
} catch (Exception $e) {
Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
}
}
$this->_redirect('*/*/index');
}

public function massStatusAction()
{
$webIds = $this->getRequest()->getParam('web');
if(!is_array($webIds)) {
Mage::getSingleton('adminhtml/session')->addError($this->__('Please select item(s)'));
} else {
try {
foreach ($webIds as $webId) {
$web = Mage::getSingleton('web/web')
->load($webId)
->setStatus($this->getRequest()->getParam('status'))
->setIsMassupdate(true)
->save();
}
$this->_getSession()->addSuccess(
$this->__('Total of %d record(s) were successfully updated', count($webIds))
);
} catch (Exception $e) {
$this->_getSession()->addError($e->getMessage());
}
}
$this->_redirect('*/*/index');
}

}

Step 4:
Create Web/Model/Web.php
<?php
class Company_Web_Model_Web extends Mage_Core_Model_Abstract
{
public function _construct()
{
parent::_construct();
$this->_init('web/web');
}
}

Step 5:
Create Web/Model/Mysql4/Web.php
<?php

class Company_Web_Model_Mysql4_Web extends Mage_Core_Model_Mysql4_Abstract
{
public function _construct()
{
$this->_init('web/web', 'web_id');
}
}

Step 6:
Create Web/Model/Mysql4/Web/Collection.php
<?php

class Company_Web_Model_Mysql4_Web_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
{
public function _construct()
{
parent::_construct();
$this->_init('web/web');
}
}

But your grid will not appear in the backend until you create the following xml file.

Step 7:
Create app/design/adminhtml/default/default/layout/web.xml
<?xml version="1.0"?>
<layout version="0.1.0">
<web_adminhtml_web_index>
<reference name="content">
<block type="web/adminhtml_web" name="web" />
</reference>
</web_adminhtml_web_index>
</layout>

Written by Arvind Bhardwaj

Arvind is a Magento and WordPress expert with more than 6 years of industry wide experience.

Website: http://www.webspeaks.in/

76 thoughts on “Create Admin (Backend) Module in Magento with Grids

  1. thanks for the great post……

    can you give the screenshot and source code of your module it is very helpful to me and beginners to understand the module…

    thanks in advance.

  2. Hello,
    I followed your code for creating a new module and also create according to your instruction and structure but still i am getting 404 not found error. I am fresher in magent. Can u help me !

    Thanks,
    kamal

  3. I have followed all your steps but only blank page is displayed when clicking on the Add New link.

    Please help me!!

  4. Thanks for the code.

    following anonymous’ bugfix (a file seems missing) in the other article, it works:

    “To solve the blank page problem, I add a file web.xml in appdesignADMINHTMLdefaultdefaultlayout with the content:”

    < ?xml version=”1.0″? >
    < layout version=”0.1.0″ >
    < default >
    < /default >
    < web_adminhtml_web_index >
    < reference name=”content” >
    < block type=”web/adminhtml_web” name=”web” / >
    < /reference >
    < /web_adminhtml_web_index >
    < /layout >

  5. I would like to add a couple of fields to the database, e.g. for an editable ‘status’ field and another text field. How can I do this and have them save into the db??

  6. Hi Mathew,
    For adding new fields to database table you need to create a new updater file in /app/code/local///sql/_setup/ as mysql4-upgrade-x.x.x-y.y.y.php
    where x.x.x is the old version of module and y.y.y is the new version number of your module. In this file you can write the update query for the table.
    Don’t forget to update your module version number in the appcodelocalCompanyWebetcconfig.xml.

    1. sorry.. i see the post is old, but i hace a question? why not save in new fields the data… i add the fields in the web/Grid.php and tab/Form.php.. and the not save in in the new field of the database..

    2. sorry.. i see the post is old, but i hace a question? why not save in new fields the data… i add the fields in the web/Grid.php and tab/Form.php.. and the not save in in the new field of the database..

  7. Hello,

    This is grid we can get creating module using module creator. Can you tell us how we can call the grid used in our own extension in custom tab or product catalog.

    Like if we make custom tab in product catalog page(edit section).Hope you will get my question.

    Thanks

  8. Considering Magento has very complicated, multiple and impossible to debug xml files, I don’t see how skipping XMLs makes “simplicity”.

    After some hours wasted on Magento XMLs (as usual), it works.

  9. I am using Magento 1.5. I have integrated this module but blank page is loaded when I click on “Manage Items”.

  10. When you get a blank page most of the time you will need to empty your cache + logout + close browser.

  11. I am using Magento 1.5. I have integrated this module but blank page is loaded when I click on “Manage Items”.

  12. Hi,

    I added this module in my magento code and refresh cache from admin. But I am not able to see link in admin menu. Please let me know what I am doing wrong.

    Thanks,
    Abhi

  13. how to create a new table in magento? please help me.i got stucked here.i have added new table but it is not showing in database.

  14. Hi,

    Am a fresher to magento.I have created new module and i want to create a new table for my module..i have done that part but still its not coming under my db.how to run the mysql4.upgrade file..how to make my script run and get my table? please help me in this.

  15. hi,
    i need to create e new tab in customer edit.
    This tab must contain two areas:
    1 Build a form to enter notes
    2 a grid with the notes already entered

    any suggestions would be very much appreciated especially on how to make xml files
    thank you

  16. Hi, first of all thank you very much for your tutorial which pointed me to the right direction. But unfortunately I have an error I cannot fix:

    The PHP error is:
    Fatal error: Call to a member function setSaveParametersInSession() on a non-object in app/code/local/MyCompany/MyModule/Block/Adminhtml/MyModule.php on line 21

    The Magento exception in the error.log is:
    ‘Mage_Core_Exception’ with message ‘Invalid block type: Mage_MyModule_Block_Adminhtml_Index_Grid’ in app/Mage.php:550

    Has anybody faced a similar problem?

    It looks like Magento is trying to load the Block class from the wrong namespace (Mage instead of MyModule). What do you think? Please help me out. I’m totally stuck here.

    Any help is appreciated. Thanks

  17. Great Article.. But CSV export not working..
    How to implement CSV Export with this..
    Any Suggesions….
    Thank u
    Venki

    1. Add this in ModulenameController.php

      public function exportCsvAction()
      {
      $fileName = ‘export.csv’;
      $content = $this->getLayout()->createBlock(‘modulename/adminhtml_modulename_grid’)->getCsv();
      $this->_sendUploadResponse($fileName, $content);
      }

      public function exportXmlAction()
      {

      $fileName = ‘export.xml’;
      $content = $this->getLayout()->createBlock(‘modulename/adminhtml_modulename_grid’)->getXml();
      $this->_sendUploadResponse($fileName, $content);

      }

      protected function _sendUploadResponse($fileName, $content, $contentType=’application/octet-stream’) {
      $response = $this->getResponse();
      $response->setHeader(‘HTTP/1.1 200 OK’, ”);
      $response->setHeader(‘Pragma’, ‘public’, true);
      $response->setHeader(‘Cache-Control’, ‘must-revalidate, post-check=0, pre-check=0’, true);
      $response->setHeader(‘Content-Disposition’, ‘attachment; filename=’ . $fileName);
      $response->setHeader(‘Last-Modified’, date(‘r’));
      $response->setHeader(‘Accept-Ranges’, ‘bytes’);
      $response->setHeader(‘Content-Length’, strlen($content));
      $response->setHeader(‘Content-type’, $contentType);
      $response->setBody($content);
      $response->sendResponse();
      die;
      }

  18. Hi Arvind!
    This is a great post. Good job!
    What should I do if I want to add more columns in grid?
    I added more columns in _prepareColumns function but did not work. Please advice.
    Thanks.

  19. Why eveybody want to use web/web ? ll not be easier for people to read web/web1 to be sure they don t get it wrong ?

  20. I got this site from my buddy who informed me on the topic of this site and at the moment this time I am browsing this site and reading very informative articles or
    reviews here.
    Here is my webpageFree Prestashop Modules

  21. Hi Arvind,
    Your code is working fine on magento 1.7.0.0, but i have a problem when i create a new role and in role resources i checked the role ‘web module’ and saved. but it is not saving. I want this role to assign other admin users.
    For this i created a file named adminhtml.xml in company/web/etc folder and i cut the code ( this code ) from config.xml and paste it into adminhtml.xml but still having the problem.
    can you help me out for this
    Thanks,
    Anirudh

  22. Hi Arvind,
    Your module is not working for multiple admin users, Do you have any suggestion…..replay please
    Thanks,
    Anirudh

  23. Hi Arvind

    Can you tell me the use of
    Step 10: Now write the helper class appcodelocalCompanyWebHelperData.php
    and
    Step 6: Now write the following file- appcodelocalCompanyWebBlockAdminhtmlWeb.php
    because i want to know about its necessity

    Thanks

  24. Hi Arvind

    when I click the “search ” button ,it redirect the indexController,I wonder why it doesn’t work the way magento default search funtionality does,I want it work in that way but I don’t know how to change the code,would anybody help me?

    Thanks

  25. Hi Arvind

    when I click the “search ” button ,it redirect the indexController,I wonder why it doesn’t work the way magento default search funtionality does,I want it work in that way but I don’t know how to change the code,would anybody help me?

    Thanks

  26. I am getting the following error :
    Fatal error: Call to a member function getOptionText() on a non-object in C:wampwwwMagentoappcodelocalCompanyWebBlockAdminhtmlWebGrid.php on lin

  27. Hi,
    Im getting the following error on clicking on ‘Manage Items’ :

    Fatal error: Call to a member function getOptionText() on a non-object in C:wampwwwMagentoappcodelocalCompanyWebBlockAdminhtmlWebGrid.php on line 91

  28. in file

    C:xampphtdocsmagento-1.7.0.2magentoappcodelocalCompanyWebBlockAdminhtmlWebGrid.php

    error :
    Fatal error: Call to a member function getOptionArray() on a non-object in C:xampphtdocsmagento-1.7.0.2magentoappcodelocalCompanyWebBlockAdminhtmlWebGrid.php on line 92

    Not able to google n find the use of getOptionArray();
    if i comment this line in Grid.php
    /* $statuses = Mage::getSingleton(‘web/status’)->getOptionArray();
    */
    I see a grid fetching data from web table but..

    on click of EDit i get following error.

    Fatal error: Call to a member function setData() on a non-object in C:xampphtdocsmagento-1.7.0.2magentoappcodecoreMageAdminhtmlBlockWidgetFormContainer.php on line 129

    Please help .. I m a programmer.. Learning magento varshag91@gmail.com

  29. Hi Arvind,

    I installed the module and Its working fine. But when I create a new user and wanted to give him limited permission, in that case this module is not coming in the list so that I could check it for the user to allow access of this module.
    Please let me know If Its possible or not?

    Thanks
    Vipin

  30. Hi,

    It works great except t shows two sets of buttons on Add/Edit screen, one on top of form and one below the form. I wish to ewmove one. How can I?

    regards
    VC

  31. Hi,
    Your module works great. I adding my own Order Item grid to your Web/Grid.php. This works fine. However when I try to sort based on the different columns in the grid, I get a 404 error. Any idea what might be wrong here?
    Thanks,
    Neet

  32. Hi,
    Your module works great. I added my own ORder Items grid to the Web/Grid and it works fine. However when I try to sort based on the different columns I get a 404 error. Any idea what might be wrong here?
    Thanks,
    Neet

  33. Please help to find out errors

    C:xampphtdocsmagento-1.7.0.2magentoappcodelocalCompanyWebBlockAdminhtmlWebGrid.php

    error :
    Fatal error: Call to a member function getOptionArray() on a non-object in C:xampphtdocsmagento-1.7.0.2magentoappcodelocalCompanyWebBlockAdminhtmlWebGrid.php on line 92

    Not able to google n find the use of getOptionArray();
    if i comment this line in Grid.php
    /* $statuses = Mage::getSingleton(‘web/status’)->getOptionArray();
    */
    I see a grid fetching data from web table but..

    on click of EDit i get following error.

    Fatal error: Call to a member function setData() on a non-object in C:xampphtdocsmagento-1.7.0.2magentoappcodecoreMageAdminhtmlBlockWidgetFormContainer.php on line 129

  34. Hi,
    Great tutorial for the beginners, its works perfectly. But, how can i show the admin data for front end .

  35. Nice tutorial….

    I am trying to add new field , I made changes in Edit/Tab/Form.php and added field directly to table from phpmyadmin. Unfortunately its not working. If I modify existing field like ‘filename’ to NAME then its working.

    Your help will be appreciated thank you 🙂

  36. Nice tutorial,

    I need your help to add new field in same module. I tried to add new field but its not working. I have added NAME field and modified changes in Edit/Tab/Form.php file and added same field to table from phpmyadmin. But its not working. Unable to SAVE data for that field.

    Please help me.

    Thank you

Comments are closed.