manuxi / sulu-bulk-actions-bundle
Bulk actions (publish, unpublish, copy locale, delete) for lists in the Sulu admin.
Package info
github.com/manuxi/SuluBulkActionsBundle
Type:symfony-bundle
pkg:composer/manuxi/sulu-bulk-actions-bundle
Requires
- php: ^8.2
- sulu/sulu: ^3.0
- symfony/config: ^6.4 | ^7.0
- symfony/dependency-injection: ^6.4 | ^7.0
- symfony/framework-bundle: ^6.4 | ^7.0
- symfony/http-foundation: ^6.4 | ^7.0
- symfony/http-kernel: ^6.4 | ^7.0
- symfony/messenger: ^6.4 | ^7.0
- symfony/translation: ^6.4 | ^7.0
- symfony/yaml: ^6.4 | ^7.0
Requires (Dev)
- ext-pdo_sqlite: *
- phpunit/phpunit: ^10.5 | ^11.0
- symfony/var-exporter: ^6.4 | ^7.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-15 18:58:55 UTC
README
Bulk actions for lists in the Sulu admin: mark rows, then publish, unpublish, copy a locale or delete them in one go. Articles (all groups), snippets, testimonials and events work out of the box with all four actions; other bundles bring their own handler.
This is the 3.x branch for Sulu 3.0. The 2.x branch is the version for Sulu 2.6.
Installation
composer require manuxi/sulu-bulk-actions-bundle:3.x-dev
- Register the bundle in
config/bundles.php:Manuxi\SuluBulkActionsBundle\SuluBulkActionsBundle::class => ['all' => true] - Import the routes in
config/routes_admin.yaml:SuluBulkActionsBundle: resource: '@SuluBulkActionsBundle/Resources/config/routes_admin.yaml'
- Add the JS to
assets/admin/package.json("sulu-bulk-actions-bundle": "file:../../vendor/manuxi/sulu-bulk-actions-bundle/src/Resources/js") andassets/admin/app.js(import 'sulu-bulk-actions-bundle';), thennpm install --force && npm run build. - Give the "Bulk actions" context to a role (see Permissions).
Permissions
Two levels, so nobody can do in bulk what they may not do one by one:
- Switch: the security context
sulu.bulk_actions.actions("BulkActions" in the role form) decides whether a role may use bulk actions at all. "Live" allows publish and unpublish, "Edit" allows copy locale, "Delete" allows delete (unlessdelete_enabledis switched off, see below). Nobody has it by default; give it to a role in the role form. - Entries: every entry is checked against the security context of the entry itself, with the same permission
("Live", "Edit" or "Delete"). For articles that is the context of the article group (
sulu.article.articles_blog, ...), for snippetssulu.snippet.snippets, for testimonials and events their own contexts. Copy locale checks "Edit" in the target language. Entries without permission are skipped and reported. The dropdown only shows the actions the user may use in that list (for example only in the Blog tab if they have the right for Blog).
New article groups need nothing: their contexts already exist in the role form.
Result
If not all selected entries could be processed, a dialog explains why, in the language of the admin: entries without a version in the chosen language (detected up front and skipped), entries without permission, and other errors with the title of the entry. Details: Result of a bulk action
Copy locale
"Copy locale" copies the content of one language into another for all selected articles, snippets, testimonials or events, like "Copy locale"
in the form. A dialog asks for the source and the target language. The result is always a draft; nothing is published.
Entries without the source language and entries that already have the target language are skipped and listed by title;
a switch "Overwrite existing versions" (default: off) replaces existing drafts. Pages have a handler, but no list in
the admin yet (the page tree cannot select). The list of the forms of the SuluFormBundle
gets only this action (forms have neither a draft nor a publication), and only with a version of that bundle whose
FormManager has copyLocale(). Details: Copy locale
Delete
"Delete" removes all selected entries after a confirmation. It is offered only to roles that have the "Delete" permission in the "Bulk actions" context and in the context of the list, and every entry is checked again on the server. Articles and snippets are removed with the message of Sulu; testimonials and events are put into the trash and leave the search index and the activity log like they do when deleted in the form. Details: Delete
Configuration
sulu_bulk_actions: delete_enabled: true # false removes bulk delete for everybody, whatever the roles say resources: # optional; articles, snippets, testimonials and events are added by default articles: view_prefixes: ['sulu_article.article.list_'] actions: [publish, unpublish, copy_locale, delete]
A list configured under resources replaces the defaults of that resource: add delete and copy_locale there too.
Handlers for other resources
Implement Manuxi\SuluBulkActionsBundle\Handler\BulkActionHandlerInterface (it is tagged automatically) and add the
resource to sulu_bulk_actions.resources with the names of its list views:
public function supports(string $resourceKey, string $action): bool { return 'testimonials' === $resourceKey && \in_array($action, ['publish', 'unpublish'], true); } public function handle(string $action, array $ids, string $locale): array { // ... return ['done' => [...ids], 'failed' => [id => message]] }
Also implement EntryInfoProviderInterface so that entries without the language are skipped with a clear message and
errors show the title instead of the ID (see Result of a bulk action).
LocaleCopyHandlerInterface adds the action copy_locale (see Copy locale).
Endpoint
POST /admin/api/bulk-actions/{resourceKey}/{action}?locale=de with {"ids": ["..."]}. The prefix is deliberately not
/admin/api/{resourceKey}/..., which would collide with the routes of the resources themselves. The response counts
done, missing, denied and failed entries (see Result of a bulk action).
copy_locale also takes sourceLocale, targetLocale and overwrite (see Copy locale).
Tests
composer install vendor/bin/phpunit

