Use WooCommerce for digital products and as everyone knows, for this type of product or payment status it is always as processing. To resolve this, use the following code that resolves the issue, but the "payment received successfully" notification message is not synchronized. Does anyone know how to solve it?
add_action( 'woocommerce_order_status_changed', 'ts_auto_complete_by_payment_method' );
function ts_auto_complete_by_payment_method( $order_id ) {
if ( !$order_id ) {
return;
}
global $product;
$order = wc_get_order( $order_id );
if ( $order->data[ 'status' ] == 'processing' ) {
$payment_method = $order->get_payment_method();
if ( $payment_method != "cod" ) {
$order->update_status( 'completed' );
}
}
}
add_action( 'woocommerce_before_thankyou', 'update_order_status_and_show_info' );
function update_order_status_and_show_info( $order_id ) {
if ( !$order_id ) {
return;
}
$order = wc_get_order( $order_id );
if ( $order->get_status() == 'processing' ) {
$payment_method = $order->get_payment_method();
if ( $payment_method != "cod" ) {
$order->update_status( 'completed' );
echo "<span>Payment received successfully.</span>";
}
}
}
Try this code
Related
im trying to change order status to "completed" and skip payment page (go to thank you page) after order is processed.
so far i manage to change order status to completed but instead of redirecting me to thank you page, i will be redirected to payment page with the following error :
this is the code i use :
add_filter( 'woocommerce_checkout_order_processed' , 'skip_join_payment' );
function skip_join_payment( $order_id ) {
if ( ! $order_id ) {
return;
}
if( $_COOKIE['isjoinForFree'] == "yes" ){
$order = wc_get_order( $order_id );
$order->update_status( 'completed' );
** i tried to redirect here but getting error on checkout page **
// if ( $order->has_status( 'completed' ) ) {
// header("Location: /jtnx/");
// die();
// }
}
}
in addition i tried adding another hooks with redirect :
add_action( 'woocommerce_payment_complete', 'skiped_join_payment_redirect', 1 );
function skiped_join_payment_redirect ( $order_id ){
$order = wc_get_order( $order_id );
if( $_COOKIE['isjoinForFree'] == "yes" ){
$order = wc_get_order( $order_id );
if ( $order->has_status( 'completed' ) ) {
header("Location: /jtnx/");
die();
}
}
}
try steps below:
use absolute, full target page address in header like
header('Location: http://www.example.com/');. See header for the reason.
Ensure that if( $_COOKIE['isjoinForFree'] == "yes" ) { is true.
If you need, insert the else { part of if( $_COOKIE['isjoinForFree'] == "yes" ) { loop
if anyone step into this error that was my fix.
the reason for the redirect fail occur cause of the checkout ajax still running,
i added this code into my function.php, works well.
add_action( 'template_redirect', 'joined_for_free_redirect_to_thankyou' );
function joined_for_free_redirect_to_thankyou(){
if( !is_wc_endpoint_url( 'order-pay' )) {
return;
}
global $wp;
$order_id = intval( str_replace( 'join/order-pay/', '', $wp->request ) );
$order = wc_get_order( $order_id );
if ( $order->has_status( 'completed' ) && $_COOKIE['isjoinForFree'] == "yes" ) {
wp_redirect( site_url() . '/jtnx/' );
exit;
}
}
if anyone think he has a better way to fix it i will still be happy to hear :)
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...
How do I combine these so I can autocomplete orders with only virtual subscriptions articles?
add_action( 'woocommerce_payment_complete', 'woocommerce_subscriptions_auto_complete_order' );
function woocommerce_subscriptions_auto_complete_order( $order_id ) {
if ( ! $order_id ) {
return;
}
$order = wc_get_order( $order_id );
$order->update_status( 'completed' );
}
and this which autocompletes virtual products. Although my subscriptions are virtual this didn't work
/**
* Auto Complete all WooCommerce virtual orders.
*
* #param int $order_id The order ID to check
* #return void
*/
function custom_woocommerce_auto_complete_virtual_orders( $order_id ) {
// if there is no order id, exit
if ( ! $order_id ) {
return;
}
// get the order and its exit
$order = wc_get_order( $order_id );
$items = $order->get_items();
// if there are no items, exit
if ( 0 >= count( $items ) ) {
return;
}
// go through each item
foreach ( $items as $item ) {
// if it is a variation
if ( '0' != $item['variation_id'] ) {
// make a product based upon variation
$product = new WC_Product( $item['variation_id'] );
} else {
// else make a product off of the product id
$product = new WC_Product( $item['product_id'] );
}
// if the product isn't virtual, exit
if ( ! $product->is_virtual() ) {
return;
}
}
/*
* If we made it this far, then all of our items are virtual
* We set the order to completed.
*/
$order->update_status( 'completed' );
}
add_action( 'woocommerce_thankyou', 'custom_woocommerce_auto_complete_virtual_orders' );
I found an easier way at https://action-a-day.com/autocomplete-orders-in-woocommerce-3-0/
add_filter( 'woocommerce_order_item_needs_processing' , 'filter_woo_item_needs_processing', 10, 3 );
function filter_woo_item_needs_processing( $needs_processing, $product, $order_ID ) {
$product_type = $product->get_type();
if ( $product->is_virtual()
&& ( 'subscription' == $product_type || 'subscription_variation' == $product_type || 'variable-subscription' == $product_type ) ) {
return false;
}
return $needs_processing;
}
I'm coding a plugin which should check whether an order contains an product-ID.
How can I check all orders if any contains the product-ID and then mark this order as finished?
I know how to check an order on thankyou-page, but the order-ID there is already given:
Thank you all and #johnnyd23 for the code below.
foreach ( $order_summary as $order ) {
$order = wc_get_order( $order->order_id );
$order_id = $order->get_id();
$items = $order->get_items();
if ( $order->get_status() == 'processing' ) {
foreach ( $items as $item ) {
$product_id = $item['product_id'];
if ( $product_id == XYZ ) {
// do something
}
}
}
}
What you should do is check if this order id is what you need and update order status
if($order_id == 'Your_required_id'){
$order->update_status( 'completed' );
}
You could change your code something as the following
foreach ( $order_summary as $order ) {
$order = wc_get_order( $order->order_id );
$order_id = $order->get_id();
$items = $order->get_items();
if ( $order->get_status() == 'processing' ) {
foreach ( $items as $item ) {
$product_id = $item['product_id'];
if ( $product_id == XYZ ) {
// do something
$order->update_status( 'completed' );
}
}
}
}
I haven't tested it. Tailor the code according to your needs
I need to change the default order status that Woocommerce is applying to orders which are paid by Cash on delivery. The default is processing and I need to set it to on-hold. I have tried this
add_action( 'woocommerce_thankyou', 'my_order_status', 50 );
function my_order_status( $order_id ) {
if ( ! $order_id ) {
return;
}
$order = wc_get_order( $order_id );
if ( ( get_post_meta( $order->id, '_payment_method', true ) == 'cod' ) && ( $order->status == 'processing' ) ) {
$order->update_status('on-hold');
}
}
but it's not working. Any thoughts?
this solved my problem
add_action('woocommerce_thankyou_cod', 'action_woocommerce_thankyou_cod', 10, 1);
function action_woocommerce_thankyou_cod($order_id)
{
$order = wc_get_order($order_id);
$order->update_status('on-hold');
}
put this in your functions.php
To resolve the issue please use below code:
add_action( 'woocommerce_thankyou', 'wc_change_status' );
function wc_change_status( $order ) {
$order = new WC_Order($order);
$order->update_status('on-hold', 'This is the change status');
//print('<pre>');
// print_r($order);
}