Skip to content

Unpaid bank transfer orders

WooCommerce’s own Hold stock (minutes) setting only cancels orders left in Pending payment. A bank transfer (BACS) puts the order in On hold, so that timer never touches it and an unpaid transfer can hold the last unit of stock indefinitely. This module closes that gap.

Requested by 5trid3rr in wppoland/polski#74.

Go to Polski > Modules and enable Unpaid bank transfer orders (module key unpaid_orders), in the “Checkout and Orders” group.

Setting Description Default
Payment methods this applies to Comma separated gateway ids bacs
Send a payment reminder Whether the reminder stage runs at all Yes
Remind after, hours from the order date First clock 24
Cancel the order if it stays unpaid Whether the cancel stage runs at all Yes
Cancel after, hours from the order date Second clock 48

Both clocks are measured from the order date, not from the moment the order entered On hold. An order can enter that status more than once, and the customer’s deadline should not restart when it does.

  1. The customer places an order and chooses bank transfer. WooCommerce sets it to On hold and reduces the stock.
  2. After the reminder window, if the order is still unpaid, the customer gets a payment reminder and an order note records that it was sent. It is sent once.
  3. After the cancel window, if the order is still unpaid, the customer is told the order was cancelled and the status changes to Cancelled, which releases the stock.
  4. If payment arrives first, neither step fires.

An order that is already past the cancel window when the module is first switched on is cancelled directly. It is not told to pay and then, in the same run, told it has been cancelled.

Every order is loaded again and re-checked immediately before the module acts on it, because between the query and the action the shop may have taken payment. The module leaves an order alone when any of these is true:

  • the status is no longer On hold
  • the payment method is no longer one of the configured ones
  • WooCommerce considers it paid, or it has a payment date
  • an invoice has been issued against it
  • a withdrawal declaration has been filed for it
  • a return request exists for it

The last three exist because cancelling underneath a document or a consumer claim leaves paperwork pointing at an order that no longer exists.

Both emails are standard WooCommerce emails. Edit the subject, heading, extra content and the on/off switch at WooCommerce > Settings > Emails:

  • Unpaid order reminder
  • Unpaid order cancelled

Templates can be overridden in a theme like any WooCommerce email, from polski-pro/templates/emails/.

The module runs hourly on WP-Cron (polski_unpaid_orders_cron) and processes up to 50 orders per run, so a large backlog is worked through over several runs rather than timing out. Switching the module off unschedules the event.

Hook Type Description
polski/unpaid_order/reminder action Fires with the order id when a reminder is sent
polski/unpaid_order/cancelled action Fires with the order id just before the status changes
polski/unpaid_order/actionable filter Return false to protect an individual order
// Never auto-cancel orders over 1000 PLN; chase those by hand.
add_filter('polski/unpaid_order/actionable', function (bool $ok, WC_Order $order): bool {
return $order->get_total() > 1000 ? false : $ok;
}, 10, 2);