WooCommerce PHP Beginner

Auto-Complete Virtual and Downloadable Orders

Last updated: May 6, 2026

WooCommerce’s default order flow requires manual intervention to mark an order as Completed, even when it contains only digital products that don’t require picking, packing, or shipping. A customer buys a plugin, a PDF, or a software licence, the payment clears, the download link is emailed automatically, and then the order sits in Processing indefinitely until someone logs into the admin and updates its status. This is unnecessary friction for both the store owner and the customer, and it clutters the orders list with processing orders that are effectively already fulfilled.

This snippet hooks into the payment completion event and automatically transitions orders to Completed when every item in the order is either virtual or downloadable.

The Code

Add this to your functions.php or a site-specific plugin. It hooks into woocommerce_payment_complete, which fires after a payment gateway confirms a successful transaction.

The Logic

The snippet loops through every line item in the order and checks whether the associated product is virtual or downloadable. If any single item is neither, meaning it’s a physical product that needs to be shipped, the $auto_complete flag is set to false and the loop breaks early. Only when every item passes the check does the order status update to Completed.

This conservative approach ensures mixed orders, those containing both physical and digital items, are left in Processing for manual fulfilment, while pure digital orders are handled automatically.

The Status Note

update_status() accepts an optional second argument for an order note. The snippet includes a note explaining why the status changed, which is visible in the order timeline in the admin. This is helpful when reviewing orders later, the note makes it immediately clear the auto-completion was intentional and rule-based rather than a manual action.

Why woocommerce_payment_complete

This hook fires after payment is confirmed, which is the right moment to trigger auto-completion, not before. Using an earlier hook like woocommerce_checkout_order_created would mark orders complete before payment is confirmed, which is incorrect. The woocommerce_payment_complete hook guarantees the payment gateway has already acknowledged the transaction.

Payment Gateway Compatibility

Most standard payment gateways, Stripe, PayPal, Square, trigger woocommerce_payment_complete on successful payment. Bank transfer and cheque payment gateways don’t trigger it until payment is manually confirmed in the admin, which is correct behaviour, those orders should remain in Processing until the store owner confirms receipt of funds. The snippet works correctly with both flows.

Customer Experience

From the customer’s perspective, an order marked Completed immediately after payment provides a cleaner experience, their account shows the order as fully resolved, and any completion-triggered emails (like a “your order is complete” email if you’ve configured one) fire promptly rather than being delayed until manual processing.

functions.php
add_action( 'woocommerce_payment_complete', function( $order_id ) {
    $order = wc_get_order( $order_id );
    if ( ! $order ) return;

    $auto_complete = true;

    foreach ( $order->get_items() as $item ) {
        $product = $item->get_product();
        if ( ! $product ) continue;

        if ( ! $product->is_virtual() && ! $product->is_downloadable() ) {
            $auto_complete = false;
            break;
        }
    }

    if ( $auto_complete ) {
        $order->update_status( 'completed', __( 'Order auto-completed: all items are virtual or downloadable.', 'nahnu-snippets' ) );
    }
} );

Built by Nahnu Plugins

Need something more powerful than a snippet?

Our commercial plugins go further, built for serious WordPress sites with full support, updates, and documentation included.

Browse All Plugins →

This website uses cookies to enhance your browsing experience and ensure the site functions properly. By continuing to use this site, you acknowledge and accept our use of cookies.

Accept All Accept Required Only