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