-
-
Save willgorham/874c4ac943fc27443cd862a93764d659 to your computer and use it in GitHub Desktop.
<?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; | |
} |
Note: issue mentioned by @willgorham was fixed in WooCommerce Subscriptions v2.2.17.
Hi there @willgorham,
Thanks for sharing this great snippet!
Just to let you know – I've just had a subscription order that didn't change status as expected. It just went from 'Pending payment' to 'On-Hold' and so it seems that the snippet didn't kick in 😞
Are anyone else experiencing this problem?
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 :)
With PHP 7.4 it throws a warning on line 31: Warning: count(): Parameter must be an array or an object that implements Countable.
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?
im a bit of a newbe to code, Wordpress & WooCommerce. where do i need to place this code ?
@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.
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
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
Note: there's a current bug in WooCommerce subscriptions that doesn't accept the use of 3 parameters for this function. If you're using WCS, change your code like so: