WooCommerce 11.1 records the persisted order item IDs present when removal is requested, then deletes only those IDs during save. The change protects replacement items created before the save, but custom order data stores that override deletion behavior can retain synchronous semantics or collide with newly introduced method names.
Use this for custom HPOS data stores, ERP bridges, subscription logic, order cloning, line-item replacement, refunds, bundles, fulfillment sync, or extensions overriding order item deletion methods.
Quick answer
Inventory every custom class that extends or replaces a WooCommerce order data store and search for remove_order_items, delete_items, get_item_ids, delete_items_by_ids, save, and the removed-items hook. On staging, create a recorded order with product, fee, shipping, tax, coupon, and metadata fixtures. Remove one item type, add a replacement before save, call save once, and compare in-memory items, persisted rows, HPOS tables, order totals, stock, refunds, hooks, webhooks, emails, analytics, and ERP records. Repeat with a failed save and retry. The old item should be deleted exactly once, the replacement must survive, and hooks must fire at the documented lifecycle point.
Test scenarios to run
Run the same controlled fixture across these branches. Write down the expected result before testing so a surprising response is easy to identify.
| Scenario | Fixture | Expected result |
| Core store | Remove then replace before save | Only original ID deleted |
| Custom store | Overrides delete_items | Documented lifecycle retained |
| Failure | Save throws once | Retry does not double-delete |
| Integration | ERP consumes removal hook | One correct downstream change |
Diagnostic table
Use this table to connect the observed behavior to evidence and a verification step.
| Action | Evidence | Verification |
| Inventory custom stores and hooks | Record WooCommerce version, HPOS state, authoritative order store, custom data-store classes, method signatures, hooks, save wrappers, transaction behavior, and integration consumers. | Original persisted item IDs are removed exactly once. |
| Create typed order fixtures | Search PHP code and runtime class maps for delete_items, delete_items_by_ids, get_item_ids, remove_order_items, woocommerce_removed_order_items, and assumptions about immediate deletion. | Replacement items and metadata survive the save. |
| Trace deletion through save | Create orders with each item type and stable fixture metadata, then remove and replace items before save, during a transaction, after an exception, and on retry. | HPOS, totals, stock, hooks, and integrations agree. |
| Repair method and retry assumptions | Compare the in-memory collection, order item tables, HPOS order rows, totals, stock, refund links, hook count and time, webhook payloads, emails, analytics, and ERP state. | A failed save and retry do not duplicate deletion or notifications. |
What to check first
- Record WooCommerce version, HPOS state, authoritative order store, custom data-store classes, method signatures, hooks, save wrappers, transaction behavior, and integration consumers.
- Search PHP code and runtime class maps for delete_items, delete_items_by_ids, get_item_ids, remove_order_items, woocommerce_removed_order_items, and assumptions about immediate deletion.
- Create orders with each item type and stable fixture metadata, then remove and replace items before save, during a transaction, after an exception, and on retry.
- Compare the in-memory collection, order item tables, HPOS order rows, totals, stock, refund links, hook count and time, webhook payloads, emails, analytics, and ERP state.
- Update method signatures or opt-in behavior only after the custom store passes both deferred and failure fixtures, then monitor real canary orders by ID.
Field notes
- Write the expected result before changing anything and keep one repeatable synthetic fixture for the full test window.
- Record exact versions and UTC timestamps because caches, retries, scheduled actions, and deployments can change the evidence between checks.
- Test the public path and the stored server-side result, not only an admin preview, isolated command, or API response.
- Review the result again after the relevant cache, queue, cron, webhook, and observation window has completed.
Useful command or data shape
Adapt paths, IDs, and privacy handling to the site before running commands or storing data on production.
rg -n 'remove_order_items|delete_items_by_ids|delete_items|get_item_ids|woocommerce_removed_order_items' wp-content/plugins wp-content/mu-plugins
# Run the replacement-item fixture on staging with exact order IDs.
Why this usually happens
- A custom store assumes order item deletion is immediate.
- A replacement item is added before save and an older broad delete removes it too.
- An extension already declares a method with the new name but incompatible arguments.
- A retry fires the removal hook or downstream webhook more than once.
Decision rule
Approve WooCommerce 11.1 only when each original item ID is deleted once, replacement items survive, hook timing is documented, and HPOS plus downstream systems reconcile after failure and retry.
Production verification checklist
- Original persisted item IDs are removed exactly once.
- Replacement items and metadata survive the save.
- HPOS, totals, stock, hooks, and integrations agree.
- A failed save and retry do not duplicate deletion or notifications.
Safe fix order
Use a sequence that makes each result easy to prove. Stop when new evidence changes the scope or owner of the problem.
- Inventory custom stores and hooks
- Create typed order fixtures
- Trace deletion through save
- Repair method and retry assumptions
- Canary downstream reconciliation
Mistakes to avoid
- Changing production before recording exact versions, UTC timestamps, a stable fixture, the expected result, and a tested rollback point.
- Treating one successful screen as proof while logs, stored records, background jobs, caches, emails, APIs, and downstream systems remain unchecked.
- Testing only as an administrator instead of using the role, device, locale, cache state, request path, and failure branch that users actually reach.
- Leaving debug output, temporary exclusions, helper accounts, duplicate hooks, broad permissions, or relaxed firewall rules active after verification.
Questions teams ask during testing
Can I test this directly in production?
Start with read-only evidence. Use staging for package, code, checkout, form, permission, or cache changes. If a production canary is necessary, make it identifiable, reversible, monitored, and unable to expose personal data or charge a customer.
How do I avoid a false positive?
Repeat the same fixture with the same versions, URL, role, locale, cache state, and downstream integration. Compare the browser result, stored result, and logs instead of relying on one successful screen.
What evidence should I retain?
Keep UTC time, exact versions, request or record ID, expected result, actual result, relevant log lines, change made, rollback point, owner, and final verification. Redact credentials, tokens, and personal data.
When is the work complete?
Close it when the primary path passes, failure branches are understood, stored and downstream records reconcile, temporary changes are removed, monitoring is active, and the owner has the evidence packet.
What to tell the client or owner
Give the owner a concise packet with the affected workflow, exact versions, UTC test time, synthetic fixture ID, expected result, actual result, key logs, change made, rollback point, final result, unresolved risks, owner, and next review date. Remove credentials and personal data before sharing it.
When HandL WP should help
Bring in help when this affects leads, checkout, search visibility, security, paid media reporting, or a client production site. HandL WP can trace the issue through WordPress, hosting, cache, tracking, and Search Console, then verify the workflow after the technical fix.
If this is active on a production site, have HandL WP test a custom WooCommerce order store.
Related HandL WP guides
Use these related guides when the same issue touches tracking, security, checkout, or crawler visibility.
Extend the test through downstream consumers
After the custom data store preserves replacement items, run the custom data-store method signature scan across classes and traits. Then use the order-item deletion hook idempotency test to prove webhooks, ERP updates, stock, analytics, and audit records do not duplicate after failure and retry.
Helpful references