Autocomplete virtual orders in WooCommerce

Autocomplete virtual orders in WooCommerce

A client of mine runs a WooCommerce store selling day tickets for regular venue admissions (they’re a science and educational centre). No physical products, nothing to pick or pack, nothing to post. Every order that comes in sits in Processing until someone logs in and clicks Complete. It’s a manual chore that serves no purpose.

WooCommerce will actually auto-complete orders in one specific case: when every item is both virtual and downloadable. So that only covers digital downloads – not services, bookings, donations, event tickets, etc. Those “processing” orders just pile up over time.

I looked at the existing plugins that solve this. Most of them are bloated order-automation suites with settings pages, upsells, and sneaky telemetry baked in. I swear if I see one more plugin use the admin notification area as an advertising space, I shall scream!

I needed a small plugin to do this one task, maybe with some filters/hooks so I could extend it in the future. So I built it.

What it does

Autocomplete Virtual Orders hooks into woocommerce_order_status_processing. When an order changes status to “Processing”, it checks every line item. If every item is virtual, the order is moved straight to Completed. If there’s a single physical item in the order, it’s left alone.

It also adds a note to the order when it auto-completes:

Autocomplete Virtual Orders: order completed automatically (all items are virtual — nothing to ship).

The actual core logic is only a few lines of PHP:

public function order_is_all_virtual( WC_Order $order ): bool {
    $items  = $order->get_items();
    $result = ! empty( $items );

    foreach ( $items as $item ) {
        $product = $item->get_product();

        if ( ! $product || ! $product->is_virtual() ) {
            $result = false;
            break;
        }
    }

    return (bool) apply_filters( 'acvo_order_is_all_virtual', $result, $order );
}

An empty order returns false. So if there’s nothing to fulfil, it shouldn’t be auto-completed.

HPOS compatible

The plugin declares compatibility with WooCommerce’s High-Performance Order Storage (HPOS). If you’ve migrated to custom order tables, it works without any changes.

Customisable in code

There’s no settings page, but we expose three filters and an action for developers who want to adjust the behaviour:

  • acvo_should_autocomplete_order : the master switch. Return false to prevent completion, or true to force it for an order that wouldn’t otherwise qualify.
  • acvo_order_is_all_virtual : redefine what “nothing to ship” means. Useful if you have a custom product type that WooCommerce doesn’t flag as virtual but you don’t want to ship.
  • acvo_target_status : change the status qualifying orders are moved to. Defaults to completed, but you can send them to a custom status instead.
  • acvo_order_autocompleted : fires after an order is completed. Use it to trigger your own side effects: external fulfilment pings, bespoke emails, audit logging.

For example, to never auto-complete orders over £500 even if all items are virtual:

/**
 * Prevent auto-completion for high-value orders.
 *
 * @param bool     $should_complete Whether the order should be auto-completed.
 * @param WC_Order $order           The order being evaluated.
 * @return bool
 */
function my_theme_acvo_skip_high_value_orders( bool $should_complete, WC_Order $order ): bool {
	if ( $order->get_total() > 500 ) {
		$should_complete = false;
	}

	return $should_complete;
}
add_filter( 'acvo_should_autocomplete_order', 'my_theme_acvo_skip_high_value_orders', 10, 2 );

Self-updating from GitHub

The plugin includes a lightweight GitHub-based updater. When a new release is published, it shows up on your Plugins screen and in Dashboard → Updates, just like a wordpress.org plugin. No account or external service needed.

Leave a comment