2

I'm looking to create a custom admin page and add a grid similar to the sales_order_grid.

I've already created my admin route, menu item and page -- just can't seem to figure out how to duplicate the sales order grid so I can customize it a bit more.

In my admin layout, I can do the following to duplicate the Sales Order Grid:

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="content">
            <uiComponent name="sales_order_grid"/>
        </referenceContainer>
    </body>
</page>

But is there a way I can now extend or customize just this page without it updating the original Sale > Order Grid? I'm basically looking to keep the sorting / filtering of orders, I just need to customize the columns for this particular page.

2 Answers 2

3

A few months ago I created a module that I think can help you. In my case, I created a new page in the admin that showed a grid in which it took sales_order as the main table and joined with other tables to add columns from these tables.

I leave you an image of the file structure:

enter image description here

Now the code. I had too many columns and tables, so I only give you some as an example:

Vendor/Module/registration.php

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
   \Magento\Framework\Component\ComponentRegistrar::MODULE,
   'Vendor_Module',
   __DIR__
);

Vendor/Module/etc/module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
   <module name="Vendor_Module" setup_version="1.0.0">
      <sequence>
         <module name="Magento_Backend"/>
         <module name="Magento_Ui"/>
      </sequence>
   </module>
</config>

Vendor/Module/Controller/Adminhtml/MyCustomGrid/Index.php

<?php
namespace Vendor\Module\Controller\Adminhtml\MyCustomGrid;
class Index extends \Magento\Backend\App\Action
{
         protected $resultPageFactory = false;      
         public function __construct(
                 \Magento\Backend\App\Action\Context $context,
                 \Magento\Framework\View\Result\PageFactory $resultPageFactory
         ) {
                 parent::__construct($context);
                 $this->resultPageFactory = $resultPageFactory;
         } 
         public function execute()
         {
                 $resultPage = $this->resultPageFactory->create();
                 $resultPage->setActiveMenu('Vendor_Module::menu');
                 $resultPage->getConfig()->getTitle()->prepend(__('My Custom Grid'));
                 return $resultPage;
         }

}

Vendor/Module/etc/adminhtml/routes.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
    <router id="admin">
        <route id="module" frontName="module">
            <module name="Vendor_Module"/>
        </route>
    </router>
</config>

Vendor/Module/etc/adminhtml/menu.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Backend:etc/menu.xsd">
   <menu>
       <add id="Vendor_Module::menu"
           title="Your menu name" module="Vendor_Module"
           sortOrder="10"
           resource="Magento_Backend::content"
           />
           <!-- START: new node -->  
       <add id="Vendor_Module::mycustomgrid"
           title="Your item menu title" module="Vendor_Module"
           sortOrder="10" parent="Vendor_Module::menu"
           action="module/mycustomgrid/index"
           resource="Vendor_Module::mycustomgrid"
           />
       <!-- END:   new node -->
   </menu>
</config>

Vendor/Module/etc/di.xml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Vendor\Module\Model\ResourceModel\MyCustomGrid\Grid\Collection">
        <arguments>
            <argument name="mainTable" xsi:type="string">sales_order</argument>
            <argument name="eventPrefix" xsi:type="string">sales_order</argument>
            <argument name="eventObject" xsi:type="string">order</argument>
            <argument name="resourceModel" xsi:type="string">Vendor\Module\Model\ResourceModel\MyCustomGrid</argument>
        </arguments>
    </type>
    <type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory">
        <arguments>
            <argument name="collections" xsi:type="array">
                <!--data provider name which used in grid ui component file -->
                <item name="module_mycustomgrid_listing_data_source" xsi:type="string">Vendor\Module\Model\ResourceModel\MyCustomGrid\Grid\Collection</item>
            </argument>
        </arguments>
    </type>
</config>

Vendor/Module/view/adminhtml/layout/module_mycustomgrid_index.xml

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
   <!--<update handle="styles"/>-->
   <body>
       <referenceContainer name="content">
                 <uiComponent name="module_mycustomgrid_listing"/>
       </referenceContainer>
   </body>
</page>

Vendor/Module/view/adminhtml/ui_component/mycustomgrid_listing.xml

<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <listingToolbar name="listing_top">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="sticky" xsi:type="boolean">true</item>
            </item>
        </argument>   
        <bookmark name="bookmarks"/>
        <columnsControls name="columns_controls"/>
        <filters name="listing_filters"/>
        <paging name="listing_paging"/>
        <exportButton name="export_button"/>
    </listingToolbar>
    <argument name="data" xsi:type="array">
        <item name="js_config" xsi:type="array">
            <item name="provider" xsi:type="string">module_mycustomgrid_listing.module_mycustomgrid_listing_data_source</item>
            <item name="deps" xsi:type="string">module_mycustomgrid_listing.module_mycustomgrid_listing_data_source</item>
        </item>
        <item name="spinner" xsi:type="string">mycustomgrid_columns</item>
    </argument>
    <dataSource name="module_mycustomgrid_listing_data_source">
        <argument name="dataProvider" xsi:type="configurableObject">
            <argument name="class" xsi:type="string">Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider</argument>
            <argument name="name" xsi:type="string">module_mycustomgrid_listing_data_source</argument>
            <argument name="primaryFieldName" xsi:type="string">entity_id</argument>
            <argument name="requestFieldName" xsi:type="string">id</argument>
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/provider</item>
                    <item name="update_url" xsi:type="url" path="mui/index/render"/>
                    <item name="storageConfig" xsi:type="array">
                        <item name="indexField" xsi:type="string">entity_id</item>
                    </item>
                </item>
            </argument>
        </argument>
    </dataSource>
    <columns name="mycustomgrid_columns">
        <selectionsColumn name="ids">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="resizeEnabled" xsi:type="boolean">false</item>
                    <item name="resizeDefaultWidth" xsi:type="string">55</item>
                    <item name="indexField" xsi:type="string">entity_id</item>
                </item>
            </argument>
        </selectionsColumn>
        <column name="increment_id">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="sortOrder" xsi:type="number">1</item>
                    <item name="sorting" xsi:type="string">desc</item>
                    <item name="label" xsi:type="string" translate="true">nº de pedido</item>
                </item>
            </argument>
        </column>
        <column name="customer_firstname">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="sortOrder" xsi:type="number">4</item>
                    <item name="label" translate="true" xsi:type="string">Nombre cliente</item>
                </item>
            </argument>
        </column>
        <column name="country_id" sortOrder="16" component="Magento_Ui/js/grid/columns/select">
            <settings>
                <options class="Magento\Customer\Ui\Component\Listing\Address\Column\Countries"/>
                <dataType>select</dataType>
                <label translate="true">País</label>
            </settings>
        </column>
        <column name="created_at" class="Magento\Ui\Component\Listing\Columns\Date">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="sortOrder" xsi:type="number">17</item>
                    <item name="filter" xsi:type="string">dateRange</item>
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/columns/date</item>
                    <item name="dataType" xsi:type="string">date</item>
                    <item name="label" xsi:type="string" translate="true">Fecha de Compra</item>
                </item>
            </argument>
        </column>
        <column name="statuslabel">
            <argument name="data" xsi:type="array">
            <!--I have used my class to customize the status filter, you can use the Magento class-->
               <item name="options" xsi:type="object">Vendor\Module\Model\MyCustomGrid\Source\Status</item>
                <item name="config" xsi:type="array">
                    <item name="filter" xsi:type="string">select</item>
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/columns/select</item>
                    <item name="dataType" xsi:type="string">select</item>
                    <item name="sortOrder" xsi:type="number">20</item>
                    <item name="label" translate="true" xsi:type="string">Estado del Pedido</item>
                </item>
            </argument>
        </column>
    </columns>
</listing>

Vendor/Module/Model/MyCustomGrid/Source/Status.php

<?php
namespace Vendor\Module\Model\MyCustomGrid\Source;

class Status implements \Magento\Framework\Data\OptionSourceInterface
{
    protected $emp;

    public function __construct(\Vendor\Module\Model\MyCustomGrid $emp)
    {
        $this->emp = $emp;
    }

    /**
     * Get options
     *
     * @return array
     */
    public function toOptionArray()
    {
        $options[] = ['label' => '', 'value' => ''];
        $availableOptions = $this->getOptionArray();
        foreach ($availableOptions as $key => $value) {
            $options[] = [
                'label' => $value,
                'value' => $key,
            ];
        }
        return $options;
    }

    public static function getOptionArray()
    {
        return [
            'Procesando' => __('Procesando'),
            'Pendiente' => __('Pendiente'),
            'On Hold' => __('On Hold'),
            'Cerrado' => __('Cerrado'),
            'Cancelado' => __('Cancelado')
        ];
    }
}

Now you have your own grid with your own custom status filter, but you need to create your own collection to show all the columns you want.

Vendor/Module/Model/ResourceModel/MyCustomGrid/Grid/Collection.php

<?php
namespace Vendor\Module\Model\ResourceModel\MyCustomGrid\Grid;

use Magento\Framework\Api\Search\SearchResultInterface;
use Magento\Framework\Search\AggregationInterface;
// your main table collection
use Vendor\Module\Model\ResourceModel\MyCustomGrid\Collection as MyCustomGridCollection;
use Magento\Framework\Data\Collection\EntityFactoryInterface;
use Psr\Log\LoggerInterface;
use Magento\Framework\Data\Collection\Db\FetchStrategyInterface;
use Magento\Framework\Event\ManagerInterface;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Framework\Model\ResourceModel\Db\AbstractDb;

/**
 * Class Collection
 * Collection for displaying grid
 */
class Collection extends MyCustomGridCollection implements SearchResultInterface
{
    /**
     * Resource initialization
     * @param EntityFactoryInterface   $entityFactory,
     * @param LoggerInterface          $logger,
     * @param FetchStrategyInterface   $fetchStrategy,
     * @param ManagerInterface         $eventManager,
     * @param StoreManagerInterface    $storeManager,
     * @param String                   $mainTable,
     * @param String                   $eventPrefix,
     * @param String                   $eventObject,
     * @param String                   $resourceModel,
     * @param $model = 'Magento\Framework\View\Element\UiComponent\DataProvider\Document',
     * @param $connection = null,
     * @param AbstractDb              $resource = null
     * @return $this
     */
    public function __construct(
        EntityFactoryInterface $entityFactory,
        LoggerInterface $logger,
        FetchStrategyInterface $fetchStrategy,
        ManagerInterface $eventManager,
        StoreManagerInterface $storeManager,
        $mainTable,
        $eventPrefix,
        $eventObject,
        $resourceModel,
        $model = 'Magento\Framework\View\Element\UiComponent\DataProvider\Document',
        $connection = null,
        AbstractDb $resource = null
    ) {
        parent::__construct(
            $entityFactory,
            $logger,
            $fetchStrategy,
            $eventManager,
            $storeManager,
            $connection,
            $resource
        );
        $this->_eventPrefix = $eventPrefix;
        $this->_eventObject = $eventObject;
        $this->_init($model, $resourceModel);
        $this->setMainTable($mainTable);
    }

    /**
     * @return AggregationInterface
     */
    public function getAggregations()
    {
        return $this->aggregations;
    }

    /**
     * @param AggregationInterface $aggregations
     *
     * @return $this
     */
    public function setAggregations($aggregations)
    {
        $this->aggregations = $aggregations;
    }

    /**
     * Get search criteria.
     *
     * @return \Magento\Framework\Api\SearchCriteriaInterface|null
     */
    public function getSearchCriteria()
    {
        return null;
    }

    /**
     * Set search criteria.
     *
     * @param \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria
     *
     * @return $this
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function setSearchCriteria(
        \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria = null
    ) {
        return $this;
    }

    /**
     * Get total count.
     *
     * @return int
     */
    public function getTotalCount()
    {
        return $this->getSize();
    }

    /**
     * Set total count.
     *
     * @param int $totalCount
     *
     * @return $this
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function setTotalCount($totalCount)
    {
        return $this;
    }

    /**
     * Set items list.
     *
     * @param \Magento\Framework\Api\ExtensibleDataInterface[] $items
     *
     * @return $this
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function setItems(array $items = null)
    {
        return $this;
    }
}

Vendor/Module/Model/ResourceModel/MyCustomGrid/Collection.php

<?php
namespace Vendor\Module\Model\ResourceModel\MyCustomGrid;
 
/* use required classes */
use Magento\Framework\Data\Collection\EntityFactoryInterface;
use Psr\Log\LoggerInterface;
use Magento\Framework\Data\Collection\Db\FetchStrategyInterface;
use Magento\Framework\Event\ManagerInterface;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\Model\ResourceModel\Db\AbstractDb;
 
class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
{
    /**
     * @var string
     */
    protected $_idFieldName = 'id';

    protected $_logger;
 
    /**
     * @param EntityFactoryInterface $entityFactory,
     * @param LoggerInterface        $logger,
     * @param FetchStrategyInterface $fetchStrategy,
     * @param ManagerInterface       $eventManager,
     * @param StoreManagerInterface  $storeManager,
     * @param AdapterInterface       $connection,
     * @param AbstractDb             $resource
     */
    public function __construct(
        EntityFactoryInterface $entityFactory,
        LoggerInterface $logger,
        FetchStrategyInterface $fetchStrategy,
        ManagerInterface $eventManager,
        StoreManagerInterface $storeManager,
        AdapterInterface $connection = null,
        AbstractDb $resource = null
    ) {
        $this->_logger = $logger;
        $this->_init('Vendor\Module\Model\MyCustomGrid', 'Vendor\Module\Model\ResourceModel\MyCustomGrid');
        parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $connection, $resource);
        $this->storeManager = $storeManager;
    }
    
    protected function _initSelect()
    {
        //my filters
        $this->addFilterToMap('statuslabel', 'statustable.label');
        $this->addFilterToMap('created_at', 'main_table.created_at');
        parent::_initSelect();

                $query = $this->getSelect()->reset(\Zend_Db_Select::COLUMNS)
                //my main table fields
                ->columns('main_table.entity_id')
                ->columns('main_table.increment_id')
                ->columns("CONCAT (main_table.customer_firstname, ' ' , main_table.customer_lastname) AS customer_firstname")
                ->columns('main_table.customer_lastname')
                ->columns('main_table.status')    
                ->columns('main_table.created_at')  
                //join main table with other tables
                ->join(
                    ['statustable'=>$this->getTable('sales_order_status')],
                    'main_table.status = statustable.status',
                    [
                        'statuslabel'=>'statustable.label'
                    ]
                )->distinct(true)
                ;

                $this->_logger->error("Query: " . $query->__toString());
                return $this;

    }
    
}

Vendor/Module/Model/ResourceModel/MyCustomGrid.php

<?php
namespace Vendor\Module\Model\ResourceModel;


class MyCustomGrid extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
{

    /**
     * Construct.
     *
     * @param \Magento\Framework\Model\ResourceModel\Db\Context $context
     * @param string|null                                       $resourcePrefix
     */
    public function __construct(
        \Magento\Framework\Model\ResourceModel\Db\Context $context,
        $resourcePrefix = null
    )
    {
        parent::__construct($context,$resourcePrefix);
    }
    
    protected function _construct()
    {
        $this->_init('sales_order', 'entity_id');
    }
    
}

Vendor/Module/Model/MyCustomGrid.php

<?php
namespace Vendor\Module\Model;
class MyCustomGrid extends \Magento\Framework\Model\AbstractModel {

    protected function _construct()
    {
        $this->_init('Vendor\Module\Model\ResourceModel\MyCustomGrid');
    }
}

I leave you several tutorials in case they help you to understand all this:

How to create a simple grid (using only one table)

Create grid joining tables

A little explanation of how to use mysql with join

I hope this can help you!

4
  • Thank you for all of the info, I'll give this a shot!
    – AJK
    May 14, 2021 at 13:22
  • I want to save new columns into the new table, can you please help how to acheive that
    – Rana Zain
    Jan 27 at 9:38
  • I want to save new columns into the new table, can you please help how to acheive that in your modue where you create the table and stored data in the table
    – Rana Zain
    Jan 27 at 9:43
  • can you please provide full code
    – Rana Zain
    Jan 27 at 10:19
0

You have to create custom UI component grid, please refer below link: Create UI Component Grid

Or you can create grid without UI component like in magento 1.

But in collection pass Magento's core collection of Orders like in di.xml(UI component). You can refer di.xml of Magento Order's module.

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.