Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Massenaktionen (Mass Actions): Aktivieren/Deaktivieren, Löschen

Massenaktionen (Mass Actions): Aktivieren/Deaktivieren, Löschen

~8 Min. Lesezeit Zuletzt aktualisiert am 9. August 2026

Massenaktionen erlauben es, mehrere ausgewählte Zeilen auf einmal zu bearbeiten - typischerweise Löschen oder einen Statuswechsel. Auf der JavaScript-Seite ist dafür nichts weiter zu tun als eine Deklaration in listing.xml; auf der PHP-Seite braucht jede Aktion einen eigenen Controller.

massaction in listing.xml deklarieren

app/code/Mironsoft/Announcement/view/adminhtml/ui_component/mironsoft_announcement_listing.xml (Ausschnitt)
<massaction name="listing_massaction">
    <action name="delete">
        <settings>
            <confirm>
                <title translate="true">Delete</title>
                <message translate="true">Are you sure you want to delete selected announcements?</message>
            </confirm>
            <url path="mironsoft_announcement/announcement/massDelete"/>
            <type>delete</type>
            <label translate="true">Delete</label>
        </settings>
    </action>
    <action name="activate">
        <settings>
            <url path="mironsoft_announcement/announcement/massStatus">
                <param name="status" xsi:type="number">1</param>
            </url>
            <type>activate</type>
            <label translate="true">Activate</label>
        </settings>
    </action>
    <action name="deactivate">
        <settings>
            <url path="mironsoft_announcement/announcement/massStatus">
                <param name="status" xsi:type="number">0</param>
            </url>
            <type>deactivate</type>
            <label translate="true">Deactivate</label>
        </settings>
    </action>
</massaction>

Jede <action> braucht nur eine url, ein optionales confirm für einen Bestätigungsdialog, und optionale statische param-Werte, die bei jedem Aufruf mitgeschickt werden (hier: der Ziel-Status).

Magento\Ui\Component\MassAction\Filter

Der Controller muss die vom Frontend gesendeten IDs nicht selbst aus dem Request auslesen und filtern - dafür gibt es Filter, das direkt eine bereits gefilterte Collection zurückliefert:

app/code/Mironsoft/Announcement/Controller/Adminhtml/Announcement/MassDelete.php
<?php

declare(strict_types=1);

namespace Mironsoft\Announcement\Controller\Adminhtml\Announcement;

use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\Controller\ResultFactory;
use Magento\Framework\Controller\ResultInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Ui\Component\MassAction\Filter;
use Mironsoft\Announcement\Model\ResourceModel\Announcement\CollectionFactory;

/**
 * Deletes all announcements selected via a grid mass action.
 */
class MassDelete extends Action
{
    public const ADMIN_RESOURCE = 'Mironsoft_Announcement::announcement';

    /**
     * @param Context $context Backend action context.
     * @param Filter $filter Applies the grid selection onto a collection.
     * @param CollectionFactory $collectionFactory Factory for the announcement collection.
     */
    public function __construct(
        Context $context,
        private readonly Filter $filter,
        private readonly CollectionFactory $collectionFactory,
    ) {
        parent::__construct($context);
    }

    /**
     * Deletes the selected announcements and redirects back to the grid.
     *
     * @return ResultInterface
     * @throws LocalizedException
     */
    public function execute(): ResultInterface
    {
        $collection = $this->filter->getCollection($this->collectionFactory->create());
        $deleted = 0;

        foreach ($collection as $announcement) {
            $announcement->delete();
            $deleted++;
        }

        $this->messageManager->addSuccessMessage(
            __('A total of %1 record(s) have been deleted.', $deleted)
        );

        /** @var ResultInterface $resultRedirect */
        $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);

        return $resultRedirect->setPath('mironsoft_announcement/announcement/index');
    }
}

$this->filter->getCollection() übernimmt automatisch beide Fälle: entweder eine explizite Liste ausgewählter IDs, oder "alle Zeilen, die dem aktuellen Filter entsprechen" (wenn der Benutzer "Alle auswählen" nutzt) - beide Fälle sind ohne zusätzlichen Code korrekt abgedeckt.

MassStatus für Aktivieren/Deaktivieren

app/code/Mironsoft/Announcement/Controller/Adminhtml/Announcement/MassStatus.php
<?php

declare(strict_types=1);

namespace Mironsoft\Announcement\Controller\Adminhtml\Announcement;

use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\Controller\ResultFactory;
use Magento\Framework\Controller\ResultInterface;
use Magento\Ui\Component\MassAction\Filter;
use Mironsoft\Announcement\Model\ResourceModel\Announcement\CollectionFactory;

/**
 * Toggles the active status of the announcements selected via a mass action.
 */
class MassStatus extends Action
{
    public const ADMIN_RESOURCE = 'Mironsoft_Announcement::announcement';

    /**
     * @param Context $context Backend action context.
     * @param Filter $filter Applies the grid selection onto a collection.
     * @param CollectionFactory $collectionFactory Factory for the announcement collection.
     */
    public function __construct(
        Context $context,
        private readonly Filter $filter,
        private readonly CollectionFactory $collectionFactory,
    ) {
        parent::__construct($context);
    }

    /**
     * Applies the requested status to the selected announcements.
     *
     * @return ResultInterface
     */
    public function execute(): ResultInterface
    {
        $status = (int) $this->getRequest()->getParam('status');
        $collection = $this->filter->getCollection($this->collectionFactory->create());

        foreach ($collection as $announcement) {
            $announcement->setIsActive($status)->save();
        }

        $this->messageManager->addSuccessMessage(__('Status updated.'));

        /** @var ResultInterface $resultRedirect */
        $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);

        return $resultRedirect->setPath('mironsoft_announcement/announcement/index');
    }
}

Achtung: Massenaktionen laufen ohne separate Bestätigung durch die Datenbank durch, wenn kein <confirm> in der XML gesetzt ist - für destruktive Aktionen wie Löschen gehört ein Bestätigungsdialog daher zwingend dazu, nicht nur als Komfortfeature.