Skip to content

Bulk actions

Bulk actions work on the selected records of the list.

use Anvil\Resource\BulkAction;
public function bulkActions(): array
{
return [
BulkAction::make('markWon')
->label('Mark as won')->icon('trophy')
->permission('deals.close') // default: "<slug>.update"
->allowed(static fn (array $deal): bool => $deal['stage'] !== 'lost') // checked per record
->confirm('Mark the selected deals as won?')
->handle(function (array $deals): string {
foreach ($deals as $deal) {
$this->model()->update($this->recordKey($deal), ['stage' => 'won']);
}
return count($deals) . ' deal(s) marked as won.';
}),
BulkAction::make('setStage')
->label('Set stage')->icon('signpost-split')
->form(static fn (Form $form): Form => $form->schema([
Radio::make('stage')->options(self::STAGES)->required(),
]))
->handle(function (array $deals, array $data): string {
service('deals')->setStage($deals, $data['stage']);
return count($deals) . ' deal(s) updated.';
}),
];
}
Option Effect Default
BulkAction::make('name') camelCase name, like record actions
label(), icon() button name, none
permission() required permission <slug>.update
allowed(fn ($record) => …) decides per record whether the action may change it all
confirm('…') confirmation question none
form(fn (Form $form) => …) dialog with fields; the closure gets no record none
maxRecords(500) largest selection 500
handle(fn (array $records, array $data) => …) receives all selected records; returns a message or null
  • The selection checkboxes are shown when the user may delete records or has the permission of at least one bulk action; the buttons appear when records are selected.
  • The selection covers the records of the current page.
  • Deleting a selection is built in and requires <slug>.delete.
  • Every selected record is loaded through the resource (tenant, scopeQuery()) and checked like a single action: allowed() and the permission including policies.
  • If one record is not found or not allowed, nothing is changed (404 / 403) – the user is not left with half a change.
  • The handler runs once for the whole selection, in one transaction, and is audited. The list is then reloaded and the message shown.

For changes of thousands of records use a queued job and notify the user when it is done, see Notifications.