
Automatically Mark Virtual (Non-Downloadable) Products as Completed After Payment in WooCommerce
By default, WooCommerce automatically marks orders for virtual downloadable products as “Completed” once the payment is successful.
However, if you’re selling virtual but non-downloadable products — such as coupons, online top-up codes, or similar — the order will not automatically move to the “Completed” status after payment.
This creates a poor user experience, especially when the product delivery doesn’t require any further manual processing.
Let’s fix that by adding a simple snippet to WooCommerce, allowing non-downloadable virtual products to also support automatic order completion.
Simply copy and paste the following code into your theme’s functions.php
file:
add_filter( 'woocommerce_payment_complete_order_status', 'virtual_order_payment_complete_order_status', 10, 2 );
function virtual_order_payment_complete_order_status( $order_status, $order_id ) {
$order = new WC_Order( $order_id );
if ( 'processing' == $order_status &&
( 'on-hold' == $order->status || 'pending' == $order->status || 'failed' == $order->status ) ) {
$virtual_order = null;
if ( count( $order->get_items() ) > 0 ) {
foreach ( $order->get_items() as $item ) {
if ( 'line_item' == $item['type'] ) {
$_product = $order->get_product_from_item( $item );
if ( ! $_product->is_virtual() ) {
// If any product is NOT virtual, stop and set flag
$virtual_order = false;
break;
} else {
$virtual_order = true;
}
}
}
}
// If all products are virtual, mark the order as completed
if ( $virtual_order ) {
return 'completed';
}
}
// Otherwise, return the original order status
return $order_status;
}
Why This Matters
This is actually a very common requirement for many WooCommerce stores — I’m honestly surprised WooCommerce doesn’t offer a built-in option for this.
Instead, we have to handle it ourselves by customizing the order completion behavior.
With this tweak, your customers will enjoy a much smoother purchasing experience for virtual goods that don’t involve a downloadable file.