I have a virtual product and I want it to change status after payment is completed. The following code changes all purchases to "completed", but I want to change only one of my products, not all of them. My product is a variable product and has 4 items,
add_action( 'woocommerce_thankyou', 'custom_woocommerce_auto_complete_order' );
function custom_woocommerce_auto_complete_order( $order_id ) {
if ( ! $order_id ) {
return;
}
$order = wc_get_order( $order_id );
if( $order->has_status( 'processing' ) ) {
$order->update_status( 'completed' );
}
}
I searched a lot but did not find an answer. please help me. Thank You
You can target specific product(s) Id(s) from order items, to make your code work only for them as follows:
add_action( 'woocommerce_thankyou', 'custom_woocommerce_auto_complete_order' );
function custom_woocommerce_auto_complete_order( $order_id ) {
if ( ! $order_id ) {
return;
}
$order = wc_get_order( $order_id );
$product_ids = array('23'); // Here set your targeted product(s) Id(s)
$product_found = false;
// Loop through order items
foreach ( $order->get_items() as $item ) {
if( array_intersect( $product_ids, array($item->get_product_id(), $item->get_variation_id()) ) ) {
$product_found = true;
break;
}
}
if( $order->has_status( 'processing' ) && $product_found ) {
$order->update_status( 'completed' );
}
}
If you want to target those products exclusively, then you will use the following instead:
add_action( 'woocommerce_thankyou', 'custom_woocommerce_auto_complete_order' );
function custom_woocommerce_auto_complete_order( $order_id ) {
if ( ! $order_id ) {
return;
}
$order = wc_get_order( $order_id );
$product_ids = array('23'); // Here set your targeted product(s) Id(s)
$product_found = true;
// Loop through order items
foreach ( $order->get_items() as $item ) {
if( ! array_intersect( $product_ids, array($item->get_product_id(), $item->get_variation_id()) ) ) {
$product_found = false;
break;
}
}
if( $order->has_status( 'processing' ) && $product_found ) {
$order->update_status( 'completed' );
}
}
Code goes in functions.php file of the active child theme (or active theme). It should works.
Addition: Avoid multiple notifications
You should better use
woocommerce_payment_complete_order_status
hook instead like in WooCommerce: Auto complete paid orders answer, to avoid multiple notifications.So the code is going to be:
add_action( 'woocommerce_payment_complete_order_status', 'wc_auto_complete_paid_order', 10, 3 ); function wc_auto_complete_paid_order( $status, $order_id, $order ) { $product_ids = array('23'); // Here set your targeted product(s) Id(s) $product_found = false; // Loop through order items foreach ( $order->get_items() as $item ) { if( array_intersect( $product_ids, array($item->get_product_id(), $item->get_variation_id()) ) ) { $product_found = true; break; } } return $product_found ? 'completed' : $status; }
Or targeting products exclusively:
add_action( 'woocommerce_payment_complete_order_status', 'wc_auto_complete_paid_order', 10, 3 ); function wc_auto_complete_paid_order( $status, $order_id, $order ) { $product_ids = array('23'); // Here set your targeted product(s) Id(s) $product_found = true; // Loop through order items foreach ( $order->get_items() as $item ) { if( ! array_intersect( $product_ids, array($item->get_product_id(), $item->get_variation_id()) ) ) { $product_found = false; break; } } return $product_found ? 'completed' : $status; }
It should work...