Install any skill in seconds. Free to start, no credit card required.
Get Started Free →webiny/webiny-cms-bulk-actions
Authoring a custom Headless CMS bulk action (EntriesBulkAction) that Webiny runs as a background task, plus the Admin-side button that triggers it.
Passed 20 of 22 test cases with the skill, and 5 of 22 without it.
and 22 more in the full report
15 fixed5 passed either way2 still failing0 broke
Tokens, turns and time describe resource use, not a dollar price.
One of 15 test cases the skill fixed. Same model, same prompt, with and without the skill.
If I define a Webiny bulk action class with readonly name = "applyDiscount", what exact PascalCased background task IDs and GraphQL mutation name are automatically created by Webiny?
| Checked | Without skill | With skill |
|---|---|---|
| Prefixes task IDs with hcmsBulkList and hcmsBulkProcess using PascalCased action name. | Missed | Passed |
| Generates GraphQL mutation named bulkAction<SingularApiName>. | Missed | Passed |
The instructions your model reads when the skill loads.
A bulk action is a class implementing EntriesBulkAction.Interface with two methods —
loadData (which entries) and processData (what to do to each). Register it with
export default EntriesBulkAction.createImplementation({...}) via <Api.Extension src>.
For every registered bulk action, Webiny automatically generates a list background
task, a process background task, and a GraphQL mutation. On the Admin side, add a
ContentEntryListConfig.Browser.BulkAction button that calls BulkActionFeature's
useCase.execute({ model, action, where, data }).
Available from Webiny 6.5.0 (webiny/api/cms/entry).
// extensions/myBulkAction/api/MyBulkAction.ts
import {
EntriesBulkAction,
ListLatestEntriesUseCase,
UpdateEntryUseCase
} from "webiny/api/cms/entry";
class MyBulkActionImpl implements EntriesBulkAction.Interface {
// PascalCased into the task ids + GraphQL enum value, so "applyDiscount" →
// tasks hcmsBulk(List|Process)ApplyDiscountEntries and frontend action "ApplyDiscount".
readonly name = "applyDiscount";
// Optional: restrict which models get the mutation/button.
readonly modelIds = ["product"];
// Optional: entries processed per batch (defaults to the configured batchSize).
// readonly batchSize = 50;
constructor(
private listEntries: ListLatestEntriesUseCase.Interface,
private updateEntry: UpdateEntryUseCase.Interface
) {}
// Runs in the "list" task, with pagination (params.where/search/after/limit).
async loadData(model, params) {
test cases passed, vs 5 / 22 without
More skills from the same source and nearby in the registry, with their headline benchmark lift.