Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save willgorham/874c4ac943fc27443cd862a93764d659 to your computer and use it in GitHub Desktop.
Save willgorham/874c4ac943fc27443cd862a93764d659 to your computer and use it in GitHub Desktop.
WooCommerce: Automatically complete virtual orders
<?php
add_filter( 'woocommerce_payment_complete_order_status', 'wmg_auto_complete_virtual_orders', 10, 3 );
/**
* Automatically complete orders with only virtual products
*
* @param string $payment_complete_status Order status used after an order payment is received
* @param int $order_id ID of the order being processed
* @param WC_Order $order Order object being processed
* @return string $payment_complete_status Updated order status
*/
function wmg_auto_complete_virtual_orders( $payment_complete_status, $order_id, $order ) {
$current_status = $order->get_status();
// We only want to update the status to 'completed' if it's coming from one of the following statuses:
$allowed_current_statuses = array( 'on-hold', 'pending', 'failed' );
if ( 'processing' === $payment_complete_status && in_array( $current_status, $allowed_current_statuses ) ) {
$order_items = $order->get_items();
// Create an array of products in the order
$order_products = array_filter( array_map( function( $item ) {
// Get associated product for each line item
return $item->get_product();
}, $order_items ), function( $product ) {
// Remove non-products
return !! $product;
} );
if ( count( $order_products ) > 0 ) {
// Check if each product is 'virtual'
$is_virtual_order = array_reduce( $order_products, function( $virtual_order_so_far, $product ) {
return $virtual_order_so_far && $product->is_virtual();
}, true );
if ( $is_virtual_order ) {
$payment_complete_status = 'completed';
}
}
}
return $payment_complete_status;
}
@warend2
Copy link

warend2 commented Apr 15, 2020

This is cool for virtual products. It would be great if you have also for physical products with autocomplete status if the shipment date matched or beyond.

Sorry for my English :)

@gbozzetti
Copy link

With PHP 7.4 it throws a warning on line 31: Warning: count(): Parameter must be an array or an object that implements Countable.

@Croolw
Copy link

Croolw commented Nov 17, 2021

Does anyone find the solution for the php 7.4 warning:
Warning: count(): Parameter must be an array or an object that implements Countable.
If so can you tell me?

@colinskuse
Copy link

im a bit of a newbe to code, Wordpress & WooCommerce. where do i need to place this code ?

@jsbls
Copy link

jsbls commented Jun 5, 2022

@colinskuse Your theme's functions.php file. Ideally, you should be using a Child Theme. You can find the functions.php file at wp-content/themes/your-theme.

If there's code there already, just paste the code at the very bottom or the very top. Make sure you remove the starting <?php tag in this script if there's already one in your file, though.

@nmbgeek
Copy link

nmbgeek commented Jun 26, 2023

Any suggestions for the error thrown below. This was working until some recent updates.

2023-06-16T01:25:05+00:00 CRITICAL Uncaught TypeError: count(): Argument #1 ($value) must be of type Countable|array, bool given in /home/runcloud/webapps/bastore/wp-content/themes/oceanwp-child-theme-master/functions.php:192
Stack trace:
#0 /home/runcloud/webapps/bastore/wp-includes/class-wp-hook.php(308): auto_complete_virtual_orders()
#1 /home/runcloud/webapps/bastore/wp-includes/plugin.php(205): WP_Hook->apply_filters()
#2 /home/runcloud/webapps/bastore/wp-content/plugins/woocommerce/includes/class-wc-order.php(142): apply_filters()
#3 /home/runcloud/webapps/bastore/wp-content/plugins/woocommerce-square/includes/Framework/PaymentGateway/Payment_Gateway_Direct.php(329): WC_Order->payment_complete()
#4 /home/runcloud/webapps/bastore/wp-content/plugins/woocommerce/includes/class-wc-checkout.php(1050): WooCommerce\Square\Framework\PaymentGateway\Payment_Gateway_Direct->process_payment()
#5 /home/runcloud/webapps/bastore/wp-content/plugins/woocommerce/includes/class-wc-checkout.php(1279): WC_Checkout->process_order_payment()
#6 /home/runcloud/webapps/bastore/wp-content/plugins/woocommerce/includes/class-wc-ajax.php(485): WC_Checkout->process_checkout()
#7 /home/runcloud/webapps/bastore/wp-includes/class-wp-hook.php(308): WC_AJAX::checkout()
#8 /home/runcloud/webapps/bastore/wp-includes/class-wp-hook.php(332): WP_Hook->apply_filters()
#9 /home/runcloud/webapps/bastore/wp-includes/plugin.php(517): WP_Hook->do_action()
#10 /home/runcloud/webapps/bastore/wp-content/plugins/woocommerce/includes/class-wc-ajax.php(96): do_action()
#11 /home/runcloud/webapps/bastore/wp-includes/class-wp-hook.php(308): WC_AJAX::do_wc_ajax()
#12 /home/runcloud/webapps/bastore/wp-includes/class-wp-hook.php(332): WP_Hook->apply_filters()
#13 /home/runcloud/webapps/bastore/wp-includes/plugin.php(517): WP_Hook->do_action()
#14 /home/runcloud/webapps/bastore/wp-includes/template-loader.php(13): do_action()
#15 /home/runcloud/webapps/bastore/wp-blog-header.php(19): require_once('...')
#16 /home/runcloud/webapps/bastore/index.php(17): require('...')
#17 {main}
  thrown in /home/runcloud/webapps/bastore/wp-content/themes/oceanwp-child-theme-master/functions.php on line 192

@daza110
Copy link

daza110 commented Aug 25, 2023

@Croolw @gbozzetti @nmbgeek

The line:
if ( count( $order_products > 0 ) ) {

Needs to be changed to:

if ( count( $order_products ) > 0 ) {

Note the correct placement of the close bracket on the count() function - this fixes the error you are all encountering

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment