31

I've added a new column to the table sales_order called export_status, now I want to add new order grid column with the data from the new sales_order column.

I've managed to add column to the sales_order_grid table.

$installer->getConnection()->addColumn($installer->getTable("sales_order_grid"), "xml_exported", [
     'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
     'comment' => 'XML Exported'
]);

How can I now make it actually show in the orders grid with the value from the sales_order export_status column?

5
  • You may find the answer magento.stackexchange.com/questions/87012/… Commented Sep 5, 2016 at 10:46
  • I think there is a better way of doing this without having to implement an observer and using events. Commented Sep 5, 2016 at 11:07
  • Try the solution here This method uses plugin to add columns.
    – Asrar
    Commented Feb 14, 2017 at 1:50
  • @AbidMalik Does this need another table to store? I've follow some course and they only use "quote" and "sales_order" table in database. They didn't use the 3rd table, in this case is "affiliate" table.
    – fudu
    Commented Sep 30, 2018 at 1:50
  • @fudu you have to add columns to grid_table; for actual values in database it depends whether you need to add columns to existing tables or create new tables altogether. this tutorial shows adding new table - it all depends on what is your scenario.
    – Abid Malik
    Commented Oct 8, 2018 at 8:29

6 Answers 6

65

After lots of digging into Magento's core code, I found a solution to my question. Instead of adding a column to the grid via the database, I created a UI component sales_order_grid.xml under [COMPANY]/[MODULE]/view/adminhtml/ui_component/sales_order_grid.xml

<?xml version="1.0" encoding="UTF-8"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <columns name="sales_order_columns">
        <column name="export_status" class="[COMPANY]\[MODULE]\Ui\Component\Listing\Column\Status">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="visible" xsi:type="boolean">true</item>
                    <item name="label" xsi:type="string" translate="true">XML Exported</item>
                </item>
            </argument>
        </column>
    </columns>
</listing>

Then created the UI class under [COMPANY]/[MODULE]/Ui/Component/Listing/Column/Status.php

<?php
namespace [COMPANY]\[MODULE]\Ui\Component\Listing\Column;

use \Magento\Sales\Api\OrderRepositoryInterface;
use \Magento\Framework\View\Element\UiComponent\ContextInterface;
use \Magento\Framework\View\Element\UiComponentFactory;
use \Magento\Ui\Component\Listing\Columns\Column;
use \Magento\Framework\Api\SearchCriteriaBuilder;

class Status extends Column
{
    protected $_orderRepository;
    protected $_searchCriteria;

    public function __construct(
        ContextInterface $context,
        UiComponentFactory $uiComponentFactory,
        OrderRepositoryInterface $orderRepository,
        SearchCriteriaBuilder $criteria,
        array $components = [],
        array $data = []
    ) {
        $this->_orderRepository = $orderRepository;
        $this->_searchCriteria  = $criteria;
        parent::__construct($context, $uiComponentFactory, $components, $data);
    }

    public function prepareDataSource(array $dataSource)
    {
        if (isset($dataSource['data']['items'])) {
            foreach ($dataSource['data']['items'] as & $item) {

                $order  = $this->_orderRepository->get($item["entity_id"]);
                $status = $order->getData("export_status");

                switch ($status) {
                    case "0":
                        $export_status = "No";
                        break;
                    case "1";
                        $export_status = "Yes";
                        break;
                    default:
                        $export_status = "Failed";
                        break;

                }

                // $this->getData('name') returns the name of the column so in this case it would return export_status
                $item[$this->getData('name')] = $export_status;
            }
        }

        return $dataSource;
    }
}
23
  • This worked great. I'm facing an issue where this customization causes the toolbar of the order grid to be rendered after the grid. Did you experience this issue?
    – Ian
    Commented Sep 27, 2016 at 1:14
  • @Ian I did not have that issue. Which version of magento 2 are you using? Commented Sep 27, 2016 at 10:07
  • 2
    CE 2.1.1. I determined the issue. My module came before Magento_Sales alphabetically. I added <sequence> with a dependency to Magento_Sales, disabled my module and then re-enabled it. This corrected the issue.
    – Ian
    Commented Sep 28, 2016 at 0:20
  • 1
    Does this work for export options also? In my case exported data had empty values.
    – MagePsycho
    Commented Feb 19, 2017 at 12:42
  • 1
    Likewise Magento 1's filter_condition_callback where you can add your own custom filter as per field. Please don't say "What do you mean?" this time ;)
    – MagePsycho
    Commented Mar 7, 2017 at 7:55
44

My solution may be a bit more efficient since it follows the native way of adding a column to the grid, and you won't have to load every order displayed on the page to obtain the column data (utilizing the sales_order_grid table instead). The above is a great example of how to create a customized renderer though.

vendor/[vendor]/[package]/view/adminhtml/ui_component/sales_order_grid.xml

<!-- Add the column "my_column" (My Column) to the sales order grid. -->
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
<columns name="sales_order_columns">
    <column name="my_column">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="filter" xsi:type="string">text</item>
                <item name="label" xsi:type="string" translate="true">My Column</item>
            </item>
        </argument>
    </column>
</columns>

Please note that you must enable the column using the drop-down widget above the order grid before it appears.

vendor/[vendor]/[package]/etc/di.xml

<!-- Sync the column "my_column" between the sales_order and sales_order_grid tables -->
<virtualType name="Magento\Sales\Model\ResourceModel\Order\Grid" type="Magento\Sales\Model\ResourceModel\Grid">
    <arguments>
        <argument name="columns" xsi:type="array">
            <item name="my_column" xsi:type="string">sales_order.my_column</item>
        </argument>
    </arguments>
</virtualType>

Sample setup code to add a column to sales_order_grid table (use this in your install/upgrade script). The same code works for the sales_order table by the way.

$setup->getConnection()->addColumn(
        $setup->getTable('sales_order_grid'),
        'my_column',
        [
            'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
            'length' => 255,
            'nullable' => true,
            'comment' => 'My Column'
        ]
    );

Hope it helps! :-)

4
  • This answer requires that the column is sales_order_grid table, correct? Commented Jan 25, 2018 at 15:18
  • @MageParts, when this script will work ? Commented Jun 20, 2018 at 10:20
  • 1
    worked for me, thanks :3 btw, in that sales_order_grid.xml you should close your <listing></listing> tag or it will return an error of xml
    – fudu
    Commented Sep 30, 2018 at 2:11
  • <argument name="columns"> should be replaced with <argument name="columns" xsi:type="array"> in the di:xml file. Otherwise it will return the following error. Invalid Document Element 'argument': The type definition is abstract. Commented Nov 19, 2018 at 2:24
7

The answers here were very helpful, thank you! Here's an answer with some updated material (usage of db_schema.xml vs setup scripts, how to populate column data & clear UI bookmarks).


1. Create Database Columns

I didn't see any answers here using db_schema.xml. I'm not sure this feature was implemented when the question was first asked, but it is a much easier method for creating the necessary database columns in the grid tables.

Here's an example db_schema.xml for adding the coupon_code column to both of the order grid tables:

Vendor/Module/etc/db_schema.xml

<?xml version="1.0"?>
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
    <!-- Add column to "sales_order_grid" -->
    <table name="sales_order_grid">
        <column xsi:type="varchar" name="coupon_code" nullable="true" length="255" comment="Coupon Code"/>
    </table>
    <!-- Enterprise Edition: Add column to "magento_sales_order_grid_archive" -->
    <table name="magento_sales_order_grid_archive">
        <column xsi:type="varchar" name="coupon_code" nullable="true" length="255" comment="Coupon Code"/>
    </table>
</schema>

2. Configure Grid Columns in Virtual Classes

The grid columns are defined in a virtual Magento\Sales\Model\ResourceModel\Order\Grid class in the Magento_Sales dependency injection (di.xml) file. You can study the file to see how to select columns and join data from other tables.

Vendor/Module/etc/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <virtualType name="Magento\Sales\Model\ResourceModel\Order\Grid">
        <arguments>
            <argument name="columns" xsi:type="array">
                <item name="coupon_code" xsi:type="string">sales_order.coupon_code</item>
            </argument>
        </arguments>
    </virtualType>
    <virtualType name="Magento\SalesArchive\Model\ResourceModel\Order\Grid">
        <arguments>
            <argument name="columns" xsi:type="array">
                <item name="coupon_code" xsi:type="string">sales_order.coupon_code</item>
            </argument>
        </arguments>
    </virtualType>
</config>

Enterprise edition users will also have the Magento_SalesArchive module. The module's di.xml file defines a similar Magento\SalesArchive\Model\ResourceModel\Order\Grid virtual class.


3. Add Columns to UI Components

Now we need to add the column to the UI component definition file.

Vender/Module/view/adminhtml/ui_component/sales_order_grid.xml

<?xml version="1.0" encoding="UTF-8"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <columns name="sales_order_columns">
        <column name="coupon_code">
            <settings>
                <filter>text</filter>
                <label translate="true">Coupon Code</label>
                <visible>false</visible>
            </settings>
        </column>
    </columns>
</listing>

Enterprise users: update the archive grid component as well.

Vender/Module/view/adminhtml/ui_component/sales_archive_order_grid.xml

<?xml version="1.0" encoding="UTF-8"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <columns name="sales_order_columns">
        <column name="coupon_code">
            <settings>
                <filter>text</filter>
                <label translate="true">Coupon Code</label>
                <visible>false</visible>
            </settings>
        </column>
    </columns>
</listing>

4. Populate Data

The columns should be created in the database, configured to show on the order grids, and new orders should populate the data as expected. Existing orders will need another solution to populate missing data.

The best solution I found was from this article. The solution simply runs a SQL UPDATE / SET query (example in patch file below).


5. Optional: Delete UI Bookmarks

If you find that the column settings are not reflecting on the grid, you may want to delete the sales_order_grid entries in the ui_bookmark database table (Refer to example in patch file below).

Enterprise users: refresh the magento_sales_order_grid_archive entries as well.




I addressed steps 4 and 5 together with a patch file.

Vendor/Module/Setup/Patch/Data/PopulateGridData.php

<?php

namespace Vendor\Module\Setup\Patch\Data;

use Magento\Framework\Setup\Patch\DataPatchInterface;
use Magento\Ui\Model\ResourceModel\Bookmark\Collection as BookmarkCollection;

class PopulateGridData implements DataPatchInterface
{
    /**
     * @var BookmarkCollection
     */
    private $bookmarkCollection;

    /**
     * @param BookmarkCollection $bookmarkCollection
     */
    public function __construct(
        BookmarkCollection $bookmarkCollection
    ) {
        $this->bookmarkCollection = $bookmarkCollection;
    }

    /**
     * Populate sales order grid tables
     */
    private function populateSalesOrderGridColumns()
    {
        // Get connection
        $connection = $this->bookmarkCollection->getConnection();

        // Get grid table names
        $gridTables = [
            $connection->getTableName('sales_order_grid'),
            $connection->getTableName('magento_sales_order_grid_archive'),
        ];

        // Loop through grid tables
        foreach ($gridTables as $table) {
            // Build update select
            $select = $connection->select()->join(
                $connection->getTableName('sales_order'),
                sprintf("sales_order.entity_id = %s.entity_id", $table),
                ['netsuite_internal_id', 'coupon_code']
            );

            // Execute SQL query
            $connection->query(
                $connection->updateFromSelect(
                    $select,
                    $table
                )
            );
        }
    }

    /**
     * Refresh UI bookmarks table
     */
    private function deleteOrderGridBookmarks()
    {
        // Get collection and connection
        $connection = $this->bookmarkCollection->getConnection();

        // Get ID's to delete
        $ids = $this->bookmarkCollection->addFieldToFilter('namespace', [
            'in' => ['sales_order_grid', 'sales_archive_order_grid']
        ])->getColumnValues('bookmark_id');

        // Delete
        $connection->delete(
            $this->bookmarkCollection->getMainTable(),
            $connection->quoteInto('bookmark_id IN(?)', $ids)
        );
    }

    /**
     * Delete order grid UI bookmarks
     */
    public function apply()
    {
        $this->populateSalesOrderGridColumns();
        $this->deleteOrderGridBookmarks();
    }

    /**
     * Get aliases (previous names) for the patch.
     *
     * @return string[]
     */
    public function getAliases()
    {
        return [];
    }

    /**
     * Get array of patches that have to be executed prior to this.
     *
     * @return string[]
     */
    public static function getDependencies()
    {
        return [];
    }
}
2

For creating a new column in order grid , I have referred Magento Default Module vendor/magento/module-customer-balance

In my case,'custom_column' column already exists in the sales_order table.

I have to show 'custom_column' column in order grid

Step 1: Add a new Column in sales_order_grid table

        $connection = $installer->getConnection();
        if ($connection->isTableExists('sales_order_grid')) {
            $connection->addColumn(
                $connection->getTableName('sales_order_grid'),
                'custom_column',
                [
                    "type"      =>  Table::TYPE_TEXT,
                    'default'   =>  null,
                    "comment"   =>  'Custom Column'
                ]
            );
    }

Step 2 : di.xml file in app\code[Vendor][NameSpace]\etc\di.xml

 <!-- Adding Columns in sales_order_grid-->
    <virtualType name="Magento\Sales\Model\ResourceModel\Order\Grid">
        <arguments>
            <argument name="columns" xsi:type="array">
                <item name="custom_column" xsi:type="string">sales_order.custom_column</item>
            </argument>
        </arguments>
    </virtualType>
    <virtualType name="Magento\SalesArchive\Model\ResourceModel\Order\Grid">
        <arguments>
            <argument name="columns" xsi:type="array">
                <item name="custom_column" xsi:type="string">sales_order.custom_column</item>
            </argument>
        </arguments>
    </virtualType>

Step 3 : Create sales_order_grid.xml layout file under app\code[Vendor][NameSpace]\view\adminhtml\ui_component

<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <columns name="sales_order_columns">
        <column name="custom_column">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="filter" xsi:type="string">text</item>
                    <item name="label" xsi:type="string" translate="true">Custom Column</item>
                </item>
            </argument>
        </column>
    </columns>
</listing>

Note: This has been tested in Magento version 2.2.6

0

Demo/ExtendedGrid/view/adminhtml/ui_component/sales_order_grid.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <columns name="sales_order_columns">
        <column name="new_column_name" class="Demo\ExtendedGrid\Ui\Component\Listing\Column\NewColumnStatus">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="sortable" xsi:type="boolean">false</item>
                    <item name="has_preview" xsi:type="string">1</item>
                    <item name="label" xsi:type="string" translate="true">New Column Name</item>
              </item>
            </argument>
        </column>
    </columns>
</listing>

Then Created the UI Class to render it.

Demo/ExtendedGrid/Ui/Component/Listing/Column/NewColumnStatus.php

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Demo\ExtendedGrid\Ui\Component\Listing\Column;

/**
 * Class  NewColumnStatus
 */
class NewColumnStatus extends \Magento\Ui\Component\Listing\Columns\Column
{

    /**
     * @var string[]
     */
    protected $statuses;

   /**
     * Constructor
     *
     * @param ContextInterface $context
     * @param UiComponentFactory $uiComponentFactory
     * @param CollectionFactory $collectionFactory
     * @param array $components
     * @param array $data
     */
       public function __construct(
        \Magento\Framework\View\Element\UiComponent\ContextInterface $context,
        \Magento\Framework\View\Element\UiComponentFactory $uiComponentFactory,
        \Magento\Framework\UrlInterface $urlBuilder,
        array $components = [],
        array $data = []
    ) {
        $this->urlBuilder = $urlBuilder;
         parent::__construct($context, $uiComponentFactory, $components, $data);
    }


    /**
     * Prepare Data Source
     *
     * @param array $dataSource
     * @return void
     */
    public function prepareDataSource(array $dataSource)
    {
        if (isset($dataSource['data']['items'])) {
            foreach ($dataSource['data']['items'] as &$item) {

           //put  the logic here


            }
        }

        return $dataSource;
   }
}

Dont forget to clear cache.

-1

I have created custom module which will add custom attribute in Sales Order entity and then show in admin Sales Order grid.

module.xml file to define the module. app\code\COMPANY\MODULE\etc\module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Module/etc/module.xsd">
    <module name="COMPANY_MODULE" setup_version="1.0.0">
        <sequence>
            <module name="Magento_Sales"/>
            <module name="Magento_Quote"/>
            <module name="Magento_Checkout"/>
        </sequence>
    </module>
</config>

di.xml file in app\code\COMPANY\MODULE\etc\di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <virtualType name="Magento\Sales\Model\ResourceModel\Order\Grid" type="Magento\Sales\Model\ResourceModel\Grid">
        <arguments>
            <argument name="columns" xsi:type="array">
                <item name="export_status" xsi:type="string">sales_order.export_status</item>
            </argument>
        </arguments>
    </virtualType>
</config>

InstallData.php to add custom attribute export_status in database table

app\code\COMPANY\MODULE\Setup\InstallData.php

<?php

namespace COMPANY\MODULE\Setup;

use Magento\Eav\Setup\EavSetup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;

/**
 * @codeCoverageIgnore
 */
class InstallData implements InstallDataInterface
{
    /**
     * EAV setup factory
     *
     * @var EavSetupFactory
     */
    private $eavSetupFactory;

    /**
     * Init
     *
     * @param EavSetupFactory $eavSetupFactory
     */
    public function __construct(EavSetupFactory $eavSetupFactory)
    {
        $this->eavSetupFactory = $eavSetupFactory;
    }

    /**
     * {@inheritdoc}
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
     */
    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        /** @var EavSetup $eavSetup */
        $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
        if (version_compare($context->getVersion(), '1.0.0') < 0){      
            $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
            $salesSetup = $objectManager->create('Magento\Sales\Setup\SalesSetup');
            $salesSetup->addAttribute('order', 'export_status', ['type' =>'varchar']);
            $quoteSetup = $objectManager->create('Magento\Quote\Setup\QuoteSetup'); 
        }
    }
}

sales_order_grid.xml to add custom column in Sales Order admin grid.

<?xml version="1.0" encoding="UTF-8"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <columns name="sales_order_columns">
        <column name="export_status">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="filter" xsi:type="string">text</item>
                    <item name="label" xsi:type="string" translate="true">XML Exported</item>
                </item>
            </argument>
        </column>
    </columns>
</listing>

You can download the full module by clicking on below link http://vdcstaging.co.in/download/add-custom-culumn-to-admin-grid.zip

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.