Admin Grid for Rewards
Admin Grid for Rewards
~6 Min. Lesezeit Zuletzt aktualisiert am August 9, 2026
With the model, resource model, and a filterable collection in place, only one thing is missing: a visible admin management interface where rewards can be created, edited, and deleted. This chapter shows the minimal wiring - the full explanation of UI components, listing, and form XML is covered by this catalog's own, dedicated "Admin Grids & Forms in Magento 2" tutorial series (series tutorial-admin-grids-forms-*, identifier admin-grids-formulare) - anyone not yet familiar with UI components will find the complete groundwork there.
ACL and menu entry
Reward management gets its own ACL resource, as a child of the top-level Mironsoft_Loyalty::loyalty resource from chapter 7.
<acl>
<resources>
<resource id="Magento_Backend::admin">
<resource id="Mironsoft_Loyalty::loyalty" title="Mironsoft Loyalty">
<resource id="Mironsoft_Loyalty::rewards" title="Rewards"/>
<!-- Mironsoft_Loyalty::config_section from chapter 7 stays unchanged -->
</resource>
</resource>
</resources>
</acl><?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="Mironsoft_Loyalty::rewards" title="Rewards"
module="Mironsoft_Loyalty" sortOrder="10"
parent="Mironsoft_Loyalty::loyalty"
action="mironsoft_loyalty/reward/index"
resource="Mironsoft_Loyalty::rewards"/>
</menu>
</config>Controller and UI component
The index controller only renders the layout handle; the actual grid logic lives entirely in the UI component XML - the same pattern as every other Magento admin grid.
<?php
declare(strict_types=1);
namespace Mironsoft\Loyalty\Controller\Adminhtml\Reward;
use Magento\Backend\App\Action;
use Magento\Framework\View\Result\Page;
use Magento\Framework\View\Result\PageFactory;
/**
* Renders the reward admin grid.
*/
class Index extends Action
{
/**
* @var string
*/
public const ADMIN_RESOURCE = 'Mironsoft_Loyalty::rewards';
/**
* @param Action\Context $context Backend action context.
* @param PageFactory $resultPageFactory Creates the admin page result.
*/
public function __construct(
Action\Context $context,
private readonly PageFactory $resultPageFactory
) {
parent::__construct($context);
}
/**
* Builds the admin page holding the reward_listing UI component.
*
* @return Page
*/
public function execute(): Page
{
$resultPage = $this->resultPageFactory->create();
$resultPage->setActiveMenu(self::ADMIN_RESOURCE);
$resultPage->getConfig()->getTitle()->prepend(__('Rewards'));
return $resultPage;
}
}<!-- app/code/Mironsoft/Loyalty/view/adminhtml/ui_component/reward_listing.xml (excerpt) -->
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
<dataSource name="reward_listing_data_source">
<argument name="dataProvider" xsi:type="configurableObject">
<argument name="class" xsi:type="string">Magento\Ui\DataProvider\AbstractDataProvider</argument>
<argument name="name" xsi:type="string">reward_listing_data_source</argument>
<argument name="primaryFieldName" xsi:type="string">entity_id</argument>
<argument name="requestFieldName" xsi:type="string">id</argument>
</argument>
</dataSource>
<!-- columns: entity_id, title, points_cost, reward_type, is_active, actions ->
see the dedicated admin grids series for the full explanation -->
</listing>The dataProvider needs a di.xml wiring that points the collection constructor parameter at Mironsoft\Loyalty\Model\ResourceModel\Reward\CollectionFactory from chapter 15 - the same collection the storefront reward catalog (block 6) uses too, here without addActiveFilter(), so inactive rewards stay visible in the admin.
EAV collection directly in the grid: a deliberate trade-off
Magento\Eav\Model\Entity\Collection\AbstractCollection provides addFieldToFilter() as an alias for addAttributeToFilter() (chapter 15) and can therefore technically be used directly as the data source for AbstractDataProvider - without an additional detour.
Achtung: Magento's own admin grids for customers and products still don't access the raw EAV collection directly - they use their own, indexer-populated flat grid tables (customer_grid_flat, the product indexes) - exactly for the performance reasons chapter 18 covers in detail. For this series' reward catalog, with an expected row count in the double to low triple digits, using the EAV collection directly is a pragmatic, defensible trade-off. If the catalog grows significantly, the same guideline as for Magento's own grids applies: consider a flat index.
A working admin grid is now in place - chapter 17 handles the counterpart on the form side: required fields and validation.