Updates to removed order items actions in WooCommerce 11.0

Starting with WooCommerce 11.0.0, the woocommerce_removed_order_items action fires during the next call to save(), after the database deletion completes, rather than synchronously inside WC_Abstract_Order::remove_order_items(). Extensions that depend on the previous timing may need to update their callbacks.

To fix a bug where order line items could be lost when a checkout order-resume fails mid-flow, WC_Abstract_Order::remove_order_items() no longer deletes the items from the database immediately. The database deletion is now deferred until the next call to save(). As a side effect, the woocommerce_removed_order_items action now fires from save_items() after the delete has committed, rather than synchronously from inside remove_order_items().

Deferring the delete until save() keeps the resume flow atomic. Previously, remove_order_items() deleted the persisted items right away and then rebuilt them; if anything between that delete and the save threw (a silent exception, an unexpected cart state, or a gateway-triggered double checkout), the order was left with a correct total but zero line items. By holding the delete until save(), the previously persisted items stay intact if the flow is interrupted before the save completes.

The companion pre-hook, woocommerce_remove_order_items, is unchanged and still fires synchronously at the start of remove_order_items().

Before (WooCommerce 10.9 and earlier) — everything on one call stack inside remove_order_items():

  1. woocommerce_remove_order_items (pre) fires
  2. items are deleted from the database
  3. woocommerce_removed_order_items (post) fires

After (WooCommerce 11.0.0) — the post-hook moves to save time:

  • remove_order_items() fires woocommerce_remove_order_items (pre) and clears the in-memory items
  • later, save() deletes the items from the database and fires woocommerce_removed_order_items (post)

Listeners that only observe the final persisted order state see no difference, because the post-hook still fires after the database delete completes. No screenshots (backend behavior change).

How can developers tell if they are affected?

This applies to extensions running on WooCommerce 11.0.0 or later that add a callback to the woocommerce_removed_order_items action and assume it fires on the same call stack as remove_order_items() — for example, code that brackets a single operation across the woocommerce_remove_order_items / woocommerce_removed_order_items pair, or that expects the item rows to already be gone from the database the moment remove_order_items() returns.

You are not affected if your callback only needs to observe the final persisted order state: the post-hook still fires after the delete commits, so the observed end state is unchanged. There are no consumers of this hook in WooCommerce core itself.

What action do developers need to take if affected?

  • If you rely on the items being deleted from the database right after remove_order_items() returns, call save() on the order before acting on the persisted state.
  • If you pair woocommerce_remove_order_items and woocommerce_removed_order_items expecting both to run on one call stack, move the post-hook logic to run after the order is saved.
  • No action is needed for callbacks that only observe the final persisted order state.

Leave a Reply

Your email address will not be published. Required fields are marked *