Bulk changes
Available since 1.26.0. Permission: management. It is the same engine used by the app's bulk changes.
Routes
| Method | Route | Use |
|---|---|---|
| POST | /bulk/preview | Calculates the effect without applying anything. |
| POST | /bulk | Runs the change. |
| GET | /bulk?limit=30 | History (1 to 100 jobs). |
| GET | /bulk/{id} | Status and problems of a job. |
| POST | /bulk/{id}/revert | Undoes a job. |
Request body
| Field | Required | Notes |
|---|---|---|
entity | Yes | products, extras, extra_categories or product_terms. |
operation | Yes | See the operations table. |
params | No | Operation parameters. |
target | Yes | { "ids": [..] } or, for products only, { "filter": {..} }. |
request_id | Yes, when running and undoing | Idempotency key of 8 to 64 characters. If you repeat it, you get the existing job. |
actor | No | Who makes the change, for example "notifier:15". |
The product filter accepts the wc/v3/products parameters: search, category, tag, brand, status, stock_status, min_price, max_price, type, on_sale, sku, modified_after, plus notiwoo_image, notiwoo_extras and notiwoo_extra_category.
Operations
| Entity and operation | Parameters |
|---|---|
products price.regular, extras price | mode: set, increase_amount, decrease_amount, increase_percent or decrease_percent. value ≥ 0. round: none, 50, 100, 1000 or 900. |
products price.sale | mode: set, percent_off or clear. value, and optionally from and to (YYYY-MM-DD). round. |
products status.set | status: publish, draft, private or pending. |
products stock.set | stock_status: instock, outofstock or onbackorder. quantity if the product manages stock. |
products terms.categories, terms.tags, terms.brands | action: add, remove or replace. ids: up to 100. |
products extras.assign | action: add, remove, replace or clear. ids: extra categories. include_global with clear. |
products extras.global | disabled: yes or no ("No extras"). |
extras categories, extra_categories global_categories | action and ids. |
extras enabled.set, extra_categories enabled.set | enabled. |
extras prechecked.set | prechecked. |
extra_categories rules.set | required, minimum_options, maximum_options. |
extra_categories unassign_products | scope: all, or product_category together with product_category_id. |
products, extras, extra_categories delete | — |
product_terms delete | taxonomy: product_cat, product_tag or product_brand. |
product_terms merge | taxonomy and target_id. |
delete, merge and unassign_products are destructive. Always show the preview and ask for confirmation before running them. On variable products, price changes apply to their variations.
Preview
curl -X POST https://tienda.example.test/wp-json/notiwoo/v1/bulk/preview \
-H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
-d '{
"entity": "products",
"operation": "price.regular",
"params": { "mode": "increase_percent", "value": 5, "round": "100" },
"target": { "filter": { "status": "publish" } }
}'
{
"success": true,
"data": {
"targets": 12, "total": 12, "changed": 12, "skipped": 0, "skip_reasons": {},
"samples": [
{ "type": "product", "id": 21, "label": "Combo para dos",
"before": { "regular_price": "34000" }, "after": { "regular_price": "35700" } }
],
"variations": 0,
"destructive": false
}
}
samples shows up to 10 examples. Possible skip reasons are no_price, sale_not_lower, unchanged, invalid_rules, unsupported, error and modified_since.
Run
Send the same body to POST /bulk, adding request_id. It responds 201 with the job:
{
"id": 31, "entity": "products", "operation": "price.regular", "status": "done",
"total": 12, "processed": 12, "succeeded": 12, "skipped": 0, "failed": 0,
"actor": "notifier:15", "revert_of": null, "reverted_by": null,
"created_at": "2026-09-30T17:30:00+00:00", "finished_at": "2026-09-30T17:30:02+00:00",
"can_revert": true
}
Limits:
- Up to 5000 items per job.
- Up to 200 items are processed in the same request. Above that, they are processed in the background in batches of 50 and
statusisrunninguntil it finishes. CallGET /bulk/{id}to follow progress. - Only one job can run at a time per store (
409 notiwoo_bulk_busy).
Undo
POST /bulk/{id}/revert with a new request_id. You can only undo within 7 days and if can_revert is true. Items modified after the change are skipped with the reason modified_since.
Errors
| Code | HTTP |
|---|---|
notiwoo_bulk_unknown_operation, notiwoo_bulk_invalid_params, notiwoo_bulk_invalid_price, notiwoo_bulk_invalid_target, notiwoo_bulk_empty_target, notiwoo_bulk_request_id | 400 |
notiwoo_bulk_too_many | 400 |
notiwoo_bulk_busy, notiwoo_bulk_cannot_revert | 409 |
notiwoo_bulk_not_found | 404 |
notiwoo_bulk_job_failed | 500 |