Auto-Remove Out-of-Stock Items from the WooCommerce Cart at Checkout
When a WooCommerce customer reaches checkout and their cart has an out-of-stock item, they hit a wall. The page refreshes, shows a generic “Sorry, we do not have enough [product] in stock” error, and refuses to proceed. The customer has to figure out which item is the problem, go back to the cart, remove it manually, and try checkout again. Most of them just leave.
This is especially painful when stock counts change between the moment a product is added to cart and the moment checkout begins. The customer did nothing wrong; the inventory just shifted. The snippet below intercepts the stock check at checkout, silently removes any item that’s now out of stock or oversold, recalculates the totals, and shows a friendly notice listing what was removed and a link to the product. Checkout proceeds without the wall.
/**
* Auto-remove out-of-stock or oversold items from the cart at checkout.
*
* Replaces WooCommerce's hard-stop "cart has errors" page with a soft
* removal: bad items disappear, totals recalculate, and the customer gets
* a notice listing what was removed and a link to each product.
*/
class Carticy_Auto_Remove_OOS_At_Checkout
{
private $removed_items = array();
public function __construct()
{
add_action('woocommerce_check_cart_items', array($this, 'handle_out_of_stock_items'), 0);
add_filter('woocommerce_add_error', array($this, 'intercept_stock_errors'), 10, 1);
add_filter('woocommerce_checkout_redirect_empty_cart', array($this, 'maybe_prevent_redirect'), 10, 1);
}
public function handle_out_of_stock_items()
{
if (!is_checkout() || WC()->cart->is_empty()) {
return;
}
$cart = WC()->cart;
$items_removed = false;
foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
$product = $cart_item['data'];
if (!$product) {
continue;
}
$check = $this->check_item_stock($product, $cart_item['quantity']);
if (is_wp_error($check)) {
$this->removed_items[] = array(
'name' => $product->get_name(),
'url' => $product->get_permalink(),
'reason' => $check->get_error_message(),
);
$cart->remove_cart_item($cart_item_key);
$items_removed = true;
}
}
if ($items_removed) {
$cart->calculate_totals();
$this->add_removal_notices();
// If the cart is now empty, send the customer back to the cart page
if (is_checkout() && $cart->is_empty()) {
wp_safe_redirect(wc_get_cart_url());
exit;
}
}
}
private function check_item_stock($product, $quantity)
{
if (!$product->is_in_stock()) {
return new WP_Error('out-of-stock', sprintf(__('%s is no longer in stock.', 'woocommerce'), $product->get_name()));
}
if ($product->managing_stock()) {
$available = $product->get_stock_quantity();
$limit = apply_filters('woocommerce_cart_item_max_quantity', $available, $quantity, $product);
if ($quantity > $limit) {
if ($available > 0) {
return new WP_Error('insufficient-stock', sprintf(
__('%s has only %d in stock.', 'woocommerce'),
$product->get_name(),
$available
));
}
return new WP_Error('out-of-stock', sprintf(__('%s is no longer in stock.', 'woocommerce'), $product->get_name()));
}
}
return true;
}
private function add_removal_notices()
{
foreach ($this->removed_items as $item) {
$notice = sprintf(
'Removed from cart: %s. %s',
esc_html($item['reason']),
sprintf('<a href="%s">View product</a>', esc_url($item['url']))
);
wc_add_notice($notice, 'notice');
}
}
public function intercept_stock_errors($error)
{
if (!is_checkout()) {
return $error;
}
// Swallow the default stock errors since we've handled them ourselves
if (strpos($error, 'insufficient stock') !== false || strpos($error, 'out of stock') !== false) {
return false;
}
return $error;
}
public function maybe_prevent_redirect($redirect)
{
if (!empty($this->removed_items)) {
return false;
}
return $redirect;
}
}
new Carticy_Auto_Remove_OOS_At_Checkout();
How It Works
The class hooks into woocommerce_check_cart_items at priority 0, which is earlier than WooCommerce’s built-in stock validation. For each cart item it asks two questions: is the product in stock at all, and (for stock-managed products) is the requested quantity available. Anything that fails gets removed from the cart with remove_cart_item(), and the failure reason is stored so it can be shown to the customer afterward.
Two extra filters keep the experience clean. woocommerce_add_error swallows the default “out of stock” error messages that WooCommerce would otherwise add, since the snippet already shows its own friendlier notice. And woocommerce_checkout_redirect_empty_cart is intercepted in case all items were removed: instead of WooCommerce blocking checkout, the customer is redirected back to the cart where the notices are visible.
What This Snippet Does Not Do
It doesn’t change anything about backorders. If a product is marked “allow backorders”, it counts as in-stock and won’t be removed. It also won’t email or notify the customer outside the standard WooCommerce notice that shows on the page. If you need an inventory-restock email follow-up, that’s a separate flow.
It also doesn’t run on the cart page itself, only at checkout. Customers can still browse to the cart with a now-out-of-stock item and see it sitting there. The cleanup only happens at the checkout boundary, which is intentional: it’s better to surprise them at the cart than at the moment they’re entering their credit card.
Verification
- Add the snippet to your child theme’s
functions.phpor a custom plugin - Add a stock-managed product to your cart
- In another tab as admin, change the product’s stock quantity to 0 or its status to Out of Stock
- Return to the storefront and proceed to checkout
- Confirm the item is silently removed, a notice appears at the top with the product name and a link, and checkout continues with the remaining items
Need Help?
Learn how to add custom code to WordPress or reach out for custom development help.
About the Author
More Code Snippets
-
Reorder the Columns on the WooCommerce Orders List
Put your WooCommerce orders list columns in whatever order works…
-
Set the Default Country on WooCommerce Checkout
Pre-fill the WooCommerce checkout country (and optionally state) dropdown with…
-
Bulk Delete Expired Unused WooCommerce Coupons (Batched, Safe)
One-time bulk cleanup utility for stores with thousands of expired,…