Create Admin (Backend) Module in Magento with Grids

74 comments
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>

74 comments

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.

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

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

Please help me!!

Hi, I will upload the zip file of the module by this evening. Please be patient.

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 app\design\ADMINHTML\default\default\layout\ 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 >

Good post.. Really useful.. But CSV export not working..
How implement CSV Export with this..

Hi Vigneshprabhu,
Export fetaure has not been added in this article. Probably I will include it in some future post.

Thnaks.

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??

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 app\code\local\Company\Web\etc\config.xml.

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

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.

Very Good post help me lot thanks...Keep it up

Nice post!!
Can you please tell me how we can have multiple grid in a single module ?

the zip file is 404 .. any chance in getting it added back?

cheers :)

How can i add another grid view to show using another top menu link within the same module?

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

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

@Anonymous, Thanks for bug fixing. your idea was great to create web.xml on pp\design\ADMINHTML\default\default\layout\

awesome!!!!

Does anyone know why export is not working.. Or I have to add some other stuffs.

Please suggest...

Beside this, it is awesome!!!

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

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

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.

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.

Anyone please help me on this problem

http://stackoverflow.com/questions/8849262/add-a-row-for-displaying-total-balance-at-the-end-of-the-grid-magento-admin-gift

thanks bosssssss

Great article. Thanks a lot

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

again and again blank page in back-end in 1.6.1.0

Hello Everyone,
The bug in the article has been fixed. Now the page appears in the backend.

Thanks.

Still a white page on 1.7.0, tnx

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

@Cool &amp; Deadly, This error has not been reported before. Which version of Magento are you testing on?

Hi,
There was a bug in the app\design\adminhtml\default\default\layout\web.xml
It has been fixed now. Please download the new version and try now.

Hi,
There was a bug in the app\design\adminhtml\default\default\layout\web.xml
It has been fixed now. Please download the new version and try now.

Hi,
There was a bug in the app\design\adminhtml\default\default\layout\web.xml
It has been fixed now. Please download the new version and try now.

Thanks,
It has been fixed now. Please download the new version and try now.

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

Hi, I may include CSV export functionality in some future post.
Thanks.

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.

The new version of web.xml is doesn't help in version 1.6.1, the blank page is still happen when I visit configuration menu. Any suggestion?

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 ?

Hi,
Its not web/web, its company/web. So its bit more clear BTW :)

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 webpage - Free Prestashop Modules

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

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

This is a great post. Good job!
Thanx u

Testing replies. Thanks for sharing this!
Cheers ;)

Hi Arvind

Can you tell me the use of
Step 10: Now write the helper class app\code\local\Company\Web\Helper\Data.php
and
Step 6: Now write the following file- app\code\local\Company\Web\Block\Adminhtml\Web.php
because i want to know about its necessity

Thanks

It would work on day . . . .

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

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

I am getting the following error :
Fatal error: Call to a member function getOptionText() on a non-object in C:\wamp\www\Magento\app\code\local\Company\Web\Block\Adminhtml\Web\Grid.php on lin

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:\wamp\www\Magento\app\code\local\Company\Web\Block\Adminhtml\Web\Grid.php on line 91

great tutorial... thanks a lot... but please tell me how to display this items in the frontend.
thanks.


in file

C:\xampp\htdocs\magento-1.7.0.2\magento\app\code\local\Company\Web\Block\Adminhtml\Web\Grid.php

error :
Fatal error: Call to a member function getOptionArray() on a non-object in C:\xampp\htdocs\magento-1.7.0.2\magento\app\code\local\Company\Web\Block\Adminhtml\Web\Grid.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:\xampp\htdocs\magento-1.7.0.2\magento\app\code\core\Mage\Adminhtml\Block\Widget\Form\Container.php on line 129

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

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..

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..

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

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

The source file put to download are not updated with this file.
Thank you for the tutorial.

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

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

Please help to find out errors

C:\xampp\htdocs\magento-1.7.0.2\magento\app\code\local\Company\Web\Block\Adminhtml\Web\Grid.php

error :
Fatal error: Call to a member function getOptionArray() on a non-object in C:\xampp\htdocs\magento-1.7.0.2\magento\app\code\local\Company\Web\Block\Adminhtml\Web\Grid.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:\xampp\htdocs\magento-1.7.0.2\magento\app\code\core\Mage\Adminhtml\Block\Widget\Form\Container.php on line 129

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;
}

great tutorial...

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

i am getting this error

Fatal error: Class 'Company_Web_Helper_Data' not found in C:\xampp\htdocs\magento_test\app\Mage.php on line 546

gr8 tutorial thanks ...

I have successfully working module in admin but nothing display on frontend this url
http://localhost/abc/web

Please help me.

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 :)

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

Yes I have same issue. Please help.

Can u post a code to export selected rows from grid?

My own module not saving properly

We would love to hear from you...

back to top