29

I am facing an issue of adding a column on customer grid and showing values in that column.

Here is the observer code that I have been trying to show the column:-

if ($block->getType() == 'adminhtml/customer_grid') {
          $customer = $observer->getCustomer();
          $collection = Mage::getResourceModel('customer/customer_collection');
        $block->addColumnAfter('mobile', array(
                'header'    => 'Mobile No.',
                'type'      => 'text',
                'index'     => 'mobile',
            ), 'email');
        }   

This adds the column but no values are shown under that.

3
  • On what event are you doing this? Probably the grid collection does not have mobile column and you have to also add this column to collection. It should be accessible in $block->getCollection()
    – Zefiryn
    Jul 23, 2013 at 8:18
  • @Zefiryn how can I do that?? How can I add the mobile column in the collection using observer?
    – Kuldeep
    Jul 23, 2013 at 8:41
  • 1
    @Kuldeep The second answer is better as it avoid code duplication. You might want to accept that one.
    – Alex
    Apr 3, 2014 at 13:19

6 Answers 6

26

To add a column to the customer grid, you need to override 2 things in the block Mage_Adminhtml_Block_Customer_Grid.

  • _prepareCollection - to add your attribute in the collection
  • _prepareColumns - to add the column in your grid.

For this you should create a new extension. Let's call it Easylife_Customer. For this you will need the following files:
app/etc/module/Easylife_Customer.xml - the declaration file

<?xml version="1.0"?>
<config>
    <modules>
        <Easylife_Customer>
            <active>true</active>
            <codePool>local</codePool>
            <depends>
                <Mage_Customer /><!-- your module should depend on Mage_Customer -->
                <Mage_Adminhtml /><!-- your module should depend on Mage_Adminhtml also -->
            </depends>
        </Easylife_Customer>
    </modules>
</config>

app/code/local/Easylife/Customer/etc/config.xml - the configuration file

<?xml version="1.0"?>
<config>
    <modules>
        <Easylife_Customer>
            <version>0.0.1</version>
        </Easylife_Customer>
    </modules>
    <global>
        <blocks>
            <adminhtml>
                <rewrite>
                    <customer_grid>Easylife_Customer_Block_Adminhtml_Customer_Grid</customer_grid><!-- rewrite the customer grid -->
                </rewrite>
            </adminhtml>
        </blocks>
    </global>
</config>

app/code/local/Easylife/Customer/Block/Adminhtml/Customer/Grid.php - your own version of the customer grid. Read my comments in the code:

<?php
class Easylife_Customer_Block_Adminhtml_Customer_Grid extends Mage_Adminhtml_Block_Customer_Grid{
    /**
     * override the _prepareCollection to add an other attribute to the grid
     * @return $this
     */
    protected function _prepareCollection(){
        $collection = Mage::getResourceModel('customer/customer_collection')
            ->addNameToSelect()
            ->addAttributeToSelect('email')
            ->addAttributeToSelect('created_at')
            ->addAttributeToSelect('group_id')
            //if the attribute belongs to the customer, use the line below
            ->addAttributeToSelect('mobile')
            //if the attribute belongs to the customer address, comment the line above and use the one below
            //->joinAttribute('mobile', 'customer_address/mobile', 'default_billing', null, 'left')
            ->joinAttribute('billing_postcode', 'customer_address/postcode', 'default_billing', null, 'left')
            ->joinAttribute('billing_city', 'customer_address/city', 'default_billing', null, 'left')
            ->joinAttribute('billing_telephone', 'customer_address/telephone', 'default_billing', null, 'left')
            ->joinAttribute('billing_region', 'customer_address/region', 'default_billing', null, 'left')
            ->joinAttribute('billing_country_id', 'customer_address/country_id', 'default_billing', null, 'left');

        $this->setCollection($collection);
        //code from Mage_Adminhtml_Block_Widget_Grid::_prepareCollection()
        //since calling parent::_prepareCollection will render the code above useless
        //and you cannot call in php parent::parent::_prepareCollection()
        if ($this->getCollection()) {

            $this->_preparePage();

            $columnId = $this->getParam($this->getVarNameSort(), $this->_defaultSort);
            $dir      = $this->getParam($this->getVarNameDir(), $this->_defaultDir);
            $filter   = $this->getParam($this->getVarNameFilter(), null);

            if (is_null($filter)) {
                $filter = $this->_defaultFilter;
            }

            if (is_string($filter)) {
                $data = $this->helper('adminhtml')->prepareFilterString($filter);
                $this->_setFilterValues($data);
            }
            else if ($filter && is_array($filter)) {
                $this->_setFilterValues($filter);
            }
            else if(0 !== sizeof($this->_defaultFilter)) {
                $this->_setFilterValues($this->_defaultFilter);
            }

            if (isset($this->_columns[$columnId]) && $this->_columns[$columnId]->getIndex()) {
                $dir = (strtolower($dir)=='desc') ? 'desc' : 'asc';
                $this->_columns[$columnId]->setDir($dir);
                $this->_setCollectionOrder($this->_columns[$columnId]);
            }

            if (!$this->_isExport) {
                $this->getCollection()->load();
                $this->_afterLoadCollection();
            }
        }

        return $this;
    }

    /**
     * override the _prepareColumns method to add a new column after the 'email' column
     * if you want the new column on a different position just change the 3rd parameter
     * of the addColumnAfter method to the id of your desired column
     */
    protected function _prepareColumns(){
        $this->addColumnAfter('mobile', array(
            'header'    => Mage::helper('customer')->__('Mobile'),
            'index'     => 'mobile'
        ),'email');
        return parent::_prepareColumns();
    }
}

Clear the cache and you should be ready.

3
  • Thanks man you rock..it worked like charm :D .. Thanks a lot.
    – Kuldeep
    Jul 23, 2013 at 9:06
  • As I found in this answer, you can call a grandparent's method by its class name, in this case, like this: Mage_Adminhtml_Block_Widget_Grid::_prepareCollection();
    – kiatng
    Apr 4, 2018 at 23:54
  • That s not calling the grandparent' s methot. You are calling a non static method as atatic. That' s not ok.
    – Marius
    Apr 5, 2018 at 5:04
42

The Observers way:

Declare 2 observers in your config.xml file: one to add your column to the grid block and the other one to load data from the corresponding attribute:

<adminhtml>
    <events>
        <core_block_abstract_to_html_before>
            <observers>
                <{observer_name}>
                    <type>singleton</type>
                    <class>{namespace}_{module}/observer</class>
                    <method>beforeBlockToHtml</method>
                </{observer_name}>
            </observers>
        </core_block_abstract_to_html_before>
        <eav_collection_abstract_load_before>
            <observers>
                <{observer_name}>
                    <class>{namespace}_{module}/observer</class>
                    <method>beforeCollectionLoad</method>
                </{observer_name}>
            </observers>
        </eav_collection_abstract_load_before>
    </events>
</adminhtml>

Create an Observer class with appropriate methods:

class {Namespace}_{Module}_Model_Observer
{
    public function beforeBlockToHtml(Varien_Event_Observer $observer)
    {
        $grid = $observer->getBlock();

        /**
         * Mage_Adminhtml_Block_Customer_Grid
         */
        if ($grid instanceof Mage_Adminhtml_Block_Customer_Grid) {
            $grid->addColumnAfter(
                '{column_code}',
                array(
                    'header' => Mage::helper('{Module}_customer')->__('{{column_name}}'),
                    'index'  => '{column_code}'
                ),
                'entity_id'
            );
        }
    }

    public function beforeCollectionLoad(Varien_Event_Observer $observer)
    {
        $collection = $observer->getCollection();
        if (!isset($collection)) {
            return;
        }

        /**
         * Mage_Customer_Model_Resource_Customer_Collection
         */
        if ($collection instanceof Mage_Customer_Model_Resource_Customer_Collection) {
            /* @var $collection Mage_Customer_Model_Resource_Customer_Collection */
            $collection->addAttributeToSelect('{attribute_code}');
        }
    }
}
7
  • 1
    Definitely the best option. No rewrite Feb 2, 2014 at 19:06
  • Unfortunately it does not work for the CSV export - the column is missing there.
    – Alex
    Apr 3, 2014 at 13:28
  • What would it be like for the Product Grid page?
    – frostshoxx
    Jun 2, 2017 at 22:42
  • Rewrite is much better than observer
    – hkguile
    Jul 14, 2017 at 2:04
  • I would just recommand to use the event at Mage_Adminhtml_Block_Widget_Grid::Mage_Adminhtml_Block_Widget_Grid() that is more specialized. Sep 18, 2018 at 9:22
10

I reply to Alex comment :

To export in CSV too use

core_block_abstract_prepare_layout_before

instead of

core_block_abstract_to_html_before
5

Assuming that $block is an instance of Mage_Adminhtml_Block_Customer_Grid then

$block->getCollection() should return a customer collection used in the grid which is an instance of Mage_Customer_Model_Resource_Customer_Collection. When you look at the code in Mage_Adminhtml_Block_Customer_Grid::_prepareCollection() you will see how can you add an attribute to that collection.

It should be (although not tested)

assuming there is an attribute mobile added to the customer entity

$block->getCollection()
      ->addAttributeToSelect('mobile');

or if the mobile is and attribute added to billing address entity

$block->getCollection()
      ->joinAttriubte('mobile','customer_address/mobile','defaul_billing',null,'left');
4
  • Hello @Zefiryn , I tried both of the codes that you sent but none of them are working
    – Kuldeep
    Jul 23, 2013 at 8:53
  • Tell me on what event are you running this observer
    – Zefiryn
    Jul 23, 2013 at 8:54
  • This is a good approach but only works when exporting a grid. This happens because at the end of Mage_Adminhtml_Block_Widget_Grid::_prepareCollection this is called: $this->getCollection()->load(). This means that any other modification to the collection is ignored. But, like I said, this is a very good approach for exporting a grid. When doing an export the load method is not called until much later.
    – Marius
    Jul 23, 2013 at 10:11
3

Another way:

Rewrite customer grid block with your custom module and use setCollection() function to fetch your custom attribute.

app/code/[local or community]/YourCompany/YourModule/etc/config.xml

<?xml version="1.0"?>
<config>
    <modules>
        <yourcompany_yourmodule>
            <version>0.1.0</version>
        </yourcompany_yourmodule>
    </modules>
    <global>
        <blocks>
            <adminhtml>
                <rewrite>
                    <customer_grid>YourCompany_YourModule_Block_Customer_Grid</customer_grid>
                </rewrite>
            </adminhtml>
        </blocks>
    </global>
</config>

app/code/[local or community]/YourCompany/YourModule/Block/Customer/Grid.php

<?php

class YourCompany_YourModule_Block_Customer_Grid extends Mage_Adminhtml_Block_Customer_Grid
{
    public function setCollection($collection)
    {
        // your field/attribute to fetch, assuming it to be 'mobile'
        $collection->addAttributeToSelect('mobile'); 
        parent::setCollection($collection);
    }

    protected function _prepareColumns()
    {
        parent::_prepareColumns();

        $this->addColumn('mobile', array(
                'header'=> Mage::helper('customer')->__('Mobile'),
                'index' => 'mobile',
                'type'  => 'text',
                'width' => '100px',
        ));

        // show your new column named 'mobile' after ZIP column
        $this->addColumnsOrder('mobile', 'billing_postcode');

        return parent::_prepareColumns();
    }
}
4
  • 1
    Thanks for you code. Now how we give order to display this attribute in customer grid? Mar 6, 2017 at 8:40
  • You can give order to column by using addColumnsOrder function. Please check the updated answer. Mar 6, 2017 at 9:05
  • I used $this->addColumnAfter() but $this->addColumnsOrder() also working thanks for your reply. Mar 6, 2017 at 9:44
  • IMHO Use setCollection() is actually the best solution ( I don't like to add observer to all loadcollection event, sounds not very performance-wise ... )
    – Fra
    Jul 26, 2017 at 6:39
1

I needed to remove some default columns and add additional columns in the customer grid. I decided to make the columns configurable. First I added 2 multiselect boxes in system.xml:

<config>
    <sections>
        <extendedcustomer translate="label" module="extendedcustomer">
            <label>Extended Customer</label>
            <tab>customer</tab>
            <sort_order>100</sort_order>
            <show_in_default>1</show_in_default>
            <show_in_website>1</show_in_website>
            <show_in_store>1</show_in_store>
            <groups>
                <manage_grid translate="label">
                    <label>Manage Customer Grid in Backend</label>
                    <frontend_type>text</frontend_type>
                    <sort_order>10</sort_order>
                    <show_in_default>1</show_in_default>
                    <show_in_website>1</show_in_website>
                    <show_in_store>1</show_in_store>
                    <fields>
                        <remove translate="label">
                            <label>Remove Columns</label>
                            <frontend_type>multiselect</frontend_type>
                            <source_model>extendedcustomer/source_gridColumn</source_model>
                            <sort_order>10</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>1</show_in_store>
                        </remove>
                        <add translate="label">
                            <label>Add Columns</label>
                            <frontend_type>multiselect</frontend_type>
                            <source_model>extendedcustomer/source_attributeCode</source_model>
                            <sort_order>20</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>1</show_in_store>
                        </add>                       
                    </fields>
                </manage_grid>
            </groups>
        </extendedcustomer>
    </sections>
</config>

The source models are straight forward:

class SomeCo_ExtendedCustomer_Model_Source_GridColumn
{
    public function toOptionArray()
    {     
        return [
            ['value' => 'name', 'label' => 'Name'],
            ['value' => 'email', 'label' => 'Email'],
            ['value' => 'group', 'label' => 'Group'],
            ['value' => 'billing_telephone', 'label' => 'Telephone'],
            ['value' => 'billing_postcode', 'label' => 'ZIP'],
            ['value' => 'billing_country_id', 'label' => 'Country'],
            ['value' => 'billing_region', 'label' => 'State/Province'],
            ['value' => 'customer_since', 'label' => 'Customer Since'],
            ['value' => 'website_id', 'label' => 'Website'],
            ['value' => 'action', 'label' => 'Action']
        ];
    }
}

The second source model

class SomeCo_ExtendedCustomer_Model_Source_AttributeCode
{
    public function toOptionArray()
    {     
        $collection = Mage::getResourceModel('customer/attribute_collection')
            ->addFieldToSelect(['attribute_code', 'frontend_label'])
            ->addFieldToFilter('frontend_label', ['notnull'=>'notnull'])
            ->addFieldToFilter('is_user_defined', 1);
        $options = [];
        foreach ($collection as $item) {
            $options[] = [
                'value'     => $item->getData('attribute_code'),
                'label'     => $item->getData('frontend_label')
            ];
        }
        return $options;
    }
}

Then override the grid class:

class SomeCo_ExtendedCustomer_Block_Adminhtml_Customer_Grid extends Mage_Adminhtml_Block_Customer_Grid
{
    public function __construct()
    {
        parent::__construct();
        if ($remove = Mage::getStoreConfig('extendedcustomer/manage_grid/remove')) {
            $remove = explode(',', $remove);
        } else {
            $remove = false;
        }
        $this->setRemoveList($remove);

        if ($add = Mage::getStoreConfig('extendedcustomer/manage_grid/add')) {
            $add = explode(',', $add);
        } else {
            $add = false;
        }
        $this->setAddList($add);
    }

    protected function _prepareCollection()
    {
        if ($remove = $this->getRemoveList()) {
            $collection = Mage::getResourceModel('customer/customer_collection');
            if (!in_array('name', $remove)) {
                $collection->addNameToSelect();
            }
            foreach (['postcode', 'city', 'telephone', 'region', 'country_id'] as $suffix) {
                if (!in_array('billing_'.$suffix, $remove)) {
                    $collection->joinAttribute('billing_'.$suffix, 'customer_address/'.$suffix, 'default_billing', null, 'left');
                }
            }
        } else {
            $collection = Mage::getResourceModel('customer/customer_collection')
                ->addNameToSelect()
                //->addAttributeToSelect('email') // static attributes are added by default
                //->addAttributeToSelect('created_at')
                //->addAttributeToSelect('group_id')
                ->joinAttribute('billing_postcode', 'customer_address/postcode', 'default_billing', null, 'left')
                ->joinAttribute('billing_city', 'customer_address/city', 'default_billing', null, 'left')
                ->joinAttribute('billing_telephone', 'customer_address/telephone', 'default_billing', null, 'left')
                ->joinAttribute('billing_region', 'customer_address/region', 'default_billing', null, 'left')
                ->joinAttribute('billing_country_id', 'customer_address/country_id', 'default_billing', null, 'left');
        }

        if ($add = $this->getAddList()) {
            $collection->addAttributeToSelect($add);
        }

        $this->setCollection($collection);

        return Mage_Adminhtml_Block_Widget_Grid::_prepareCollection(); // call grandParent
    }

    protected function _prepareColumns()
    {
        $this->addColumn('entity_id', array(
            'header'    => Mage::helper('customer')->__('ID'),
            'width'     => '50px',
            'index'     => 'entity_id',
            'type'  => 'number',
        ));

        $remove = $this->getRemoveList();

        if (!$remove || !in_array('name', $remove)) {           
            $this->addColumn('name', array(
                'header'    => Mage::helper('customer')->__('Name'),
                'index'     => 'name'
            ));
        }

        if ($add = $this->getAddList()) {
            $collection = Mage::getResourceModel('customer/attribute_collection')
                ->addFieldToSelect(['attribute_code', 'frontend_label', 'source_model'])
                ->addFieldToFilter('attribute_code', ['in' => $add]);
            foreach ($collection as $item) {
                if ($source = $item->getSourceModel()) {
                    $this->addColumn($item->getAttributeCode(), array(
                        'header'    =>  $item->getFrontendLabel(),
                        'width'     =>  '100',
                        'index'     =>  $item->getAttributeCode(),
                        'type'      =>  'options',
                        'options'   =>  Mage::getSingleton($source)->toOptionHash(false)
                    ));
                } else {
                    $this->addColumn($item->getAttributeCode(), array(
                        'header'    => $item->getFrontendLabel(),
                        'width'     => '150',
                        'index'     => $item->getAttributeCode()
                    ));
                }
            }
        }

        if (!$remove || !in_array('email', $remove)) {            
            $this->addColumn('email', array(
                'header'    => Mage::helper('customer')->__('Email'),
                'width'     => '150',
                'index'     => 'email'
            ));
        }

        if (!$remove || !in_array('group', $remove)) {
            $groups = Mage::getResourceModel('customer/group_collection')
                ->addFieldToFilter('customer_group_id', array('gt'=> 0))
                ->load()
                ->toOptionHash();

            $this->addColumn('group', array(
                'header'    =>  Mage::helper('customer')->__('Group'),
                'width'     =>  '100',
                'index'     =>  'group_id',
                'type'      =>  'options',
                'options'   =>  $groups,
            ));
        }

        if (!$remove || !in_array('billing_telephone', $remove)) {
            $this->addColumn('Telephone', array(
                'header'    => Mage::helper('customer')->__('Telephone'),
                'width'     => '100',
                'index'     => 'billing_telephone'
            ));
        }

        if (!$remove || !in_array('billing_postcode', $remove)) {
            $this->addColumn('billing_postcode', array(
                'header'    => Mage::helper('customer')->__('ZIP'),
                'width'     => '90',
                'index'     => 'billing_postcode',
            ));
        }

        if (!$remove || !in_array('billing_country_id', $remove)) {
            $this->addColumn('billing_country_id', array(
                'header'    => Mage::helper('customer')->__('Country'),
                'width'     => '100',
                'type'      => 'country',
                'index'     => 'billing_country_id',
            ));
        }

        if (!$remove || !in_array('billing_region', $remove)) {
            $this->addColumn('billing_region', array(
                'header'    => Mage::helper('customer')->__('State/Province'),
                'width'     => '100',
                'index'     => 'billing_region',
            ));
        }

        if (!$remove || !in_array('customer_since', $remove)) {
            $this->addColumn('customer_since', array(
                'header'    => Mage::helper('customer')->__('Customer Since'),
                'type'      => 'datetime',
                'align'     => 'center',
                'index'     => 'created_at',
                'gmtoffset' => true
            ));
        }

        if (!$remove || !in_array('website_id', $remove)) {
            if (!Mage::app()->isSingleStoreMode()) {
                $this->addColumn('website_id', array(
                    'header'    => Mage::helper('customer')->__('Website'),
                    'align'     => 'center',
                    'width'     => '80px',
                    'type'      => 'options',
                    'options'   => Mage::getSingleton('adminhtml/system_store')->getWebsiteOptionHash(true),
                    'index'     => 'website_id',
                ));
            }
        }

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

        $this->addExportType('*/*/exportCsv', Mage::helper('customer')->__('CSV'));
        $this->addExportType('*/*/exportXml', Mage::helper('customer')->__('Excel XML'));
        return Mage_Adminhtml_Block_Widget_Grid::_prepareColumns();
    }
}

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.