This question already has answers here:
WooCommerce: Auto complete paid orders
(5 answers)
Closed 3 years ago.
I need to change automatically an order status for completed after receiving payment, but only if the order status is "processing". I found that snippet, what makes orders status completed in every case, but my payments plugins after successful payment changes returns data and changes the order status for "processing". I would like to change it into "completed" after success and don't change it if the status isn't "processing". The main problem I met is I don't know how to get the received status order.
Here is my code:
add_filter( 'woocommerce_thankyou', 'update_order_status', 10, 2 );
function update_order_status( $order_id ) {
$order = new WC_Order( $order_id );
$order_status = $order->get_status();
if ('processing' == $order_status) {
$order->update_status( 'completed' );
}
//return $order_status;
}
Edit:
I figured it out already. Here's the code that works for me:
add_filter( 'woocommerce_thankyou', 'update_order_status', 10, 1 );
function update_order_status( $order_id ) {
if ( !$order_id ){
return;
}
$order = new WC_Order( $order_id );
if ( 'processing' == $order->status) {
$order->update_status( 'completed' );
}
return;
}
Update 2 - 2019: Use WooCommerce: Auto complete paid orders (updated thread)
So the right hook to use is woocommerce_payment_complete_order_status filter returning complete
Update 1: Compatibility with WooCommerce version 3+
I have changed the answer
Based on: WooCommerce - Auto Complete paid virtual Orders (depending on Payment methods), you will be able to handle also all payment methods in conditionals:
// => not a filter (an action hook)
add_action( 'woocommerce_thankyou', 'custom_woocommerce_auto_complete_paid_order', 10, 1 );
function custom_woocommerce_auto_complete_paid_order( $order_id ) {
if ( ! $order_id )
return;
$order = new WC_Order( $order_id );
// No updated status for orders delivered with Bank wire, Cash on delivery and Cheque payment methods.
if ( get_post_meta($order_id, '_payment_method', true) == 'bacs' || get_post_meta($order_id, '_payment_method', true) == 'cod' || get_post_meta($order_id, '_payment_method', true) == 'cheque' ) {
return;
}
// "completed" updated status for paid "processing" Orders (with all others payment methods)
elseif ( $order->has_status( 'processing' ) ) {
$order->update_status( 'completed' );
}
else {
return;
}
}
The function woocommerce_thankyou is an action. You're required to use add_action function to hook into it. I would recommend changing the priority to 20 so that other plugins/code changes may be applied before update_order_status.
add_action( 'woocommerce_thankyou', 'update_order_status', 20);
Related
I would like to change the woocommerce order status auotmatically from "on-hold" to "processing" for every new order, except for payment method BACS (Direct Bank Transfer). I already found this code, but do not know how to adapt it to exclude payments made with BACS.
add_action( 'woocommerce_thankyou', 'woocommerce_auto_processing_orders');
function woocommerce_auto_processing_orders( $order_id ) {
if ( ! $order_id )
return;
$order = wc_get_order( $order_id );
// If order is "on-hold" update status to "processing"
if( $order->has_status( 'on-hold' ) ) {
$order->update_status( 'processing' );
}
}
Thank you for your help!
Update related to your comment based on WooCommerce: Auto complete paid orders answer thread.
Try the following:
add_action( 'woocommerce_payment_complete_order_status', 'wc_auto_complete_paid_order', 10, 3 );
function wc_auto_complete_paid_order( $status, $order_id, $order ) {
return 'processing';
}
It should work.
Original answer (based on the question code):
You can use WC_Order get_payment_method() method as follow:
add_action( 'woocommerce_thankyou', 'woocommerce_auto_processing_orders');
function woocommerce_auto_processing_orders( $order_id ) {
if ( ! $order_id )
return;
$order = wc_get_order( $order_id );
// If order is "on-hold" update status to "processing" except for "BACS" payments
if( $order->has_status( 'on-hold' ) && $order->get_payment_method() !== 'bacs' ) {
$order->update_status( 'processing' );
}
}
It should work.
Related: WooCommerce: Auto complete paid orders
This question already has answers here:
WooCommerce: Auto complete paid orders
(5 answers)
Automark ONLY Paid orders to "Completed" status in WooCommerce 3+
(1 answer)
Closed 4 years ago.
Have one small issue with my WooCommerce function , what was supposed to work in way i wanted, but seems that have bugs. I want to mark success paid orders as "Completed" instead of stuck on "Processing" after placed, and non success paid orders to mark as "Cancelled" orders instead stuck at "Payment Pending". This is my bugged function i have:
add_action( 'woocommerce_thankyou', 'wc_auto_complete_paid_order', 20, 1 );
function wc_auto_complete_paid_order( $order_id ) {
if ( ! $order_id )
return;
// Get an instance of the WC_Product object
$order = wc_get_order( $order_id );
// No updated status for orders delivered with Bank wire, Cash on delivery and Cheque payment methods.
if ( in_array( $order->get_payment_method(), array( 'bacs', 'cod', 'cheque', '' ) ) ) {
return;
// Updated status to "completed" for paid Orders with all others payment methods
} elseif ( $order->has_status('processing') ) {
$order->update_status( 'completed' );
}
}
You can try something like this:
add_action( 'woocommerce_thankyou', 'wc_auto_complete_paid_order' );
function wc_auto_complete_paid_order( $order_id ) {
if ( ! $order_id ) {
return;
}
$order = wc_get_order( $order_id );
if( $order->has_status('processing') ) {
$order->update_status( 'completed' );
} else {
$order->update_status( 'cancelled' );
}
}
The code is untested, I just wrote it down.
Let me know if it helps ;)
Cheers,
Francesco
I need to make WooCommerce push payments made by check into the "processing" status rather than the "on hold" status. I tried the snippet below however it doesn't seem to have an effect.
Here is my code:
add_filter( 'woocommerce_payment_complete_order_status', 'sf_wc_autocomplete_paid_orders' );
function sf_wc_autocomplete_paid_orders( $order_status, $order_id ) {
$order = wc_get_order( $order_id );
if ($order->status == 'on-hold') {
return 'processing';
}
return $order_status;
}
How can I achieve this?
Thanks.
Here is the function you are looking at hooked in woocommerce_thankyou hook:
add_action( 'woocommerce_thankyou', 'cheque_payment_method_order_status_to_processing', 10, 1 );
function cheque_payment_method_order_status_to_processing( $order_id ) {
if ( ! $order_id )
return;
$order = wc_get_order( $order_id );
// Updating order status to processing for orders delivered with Cheque payment methods.
if ( get_post_meta($order->id, '_payment_method', true) == 'cheque' )
$order->update_status( 'processing' );
}
This code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This is tested and works.
Related thread: WooCommerce: Auto complete paid Orders (depending on Payment methods)
I didn't want to use the Thank You filter in case the order still got set to On Hold at a previous step, before changing it to my desired status in the filter (a custom status in my case, or Processing in yours). So I used the filter in the Cheque gateway:
add_filter( 'woocommerce_cheque_process_payment_order_status', 'myplugin_change_order_to_agent_processing', 10, 1 );
function myplugin_change_order_to_agent_processing($status){
return 'agent-processing';
}
I hope this helps someone else out there to know that there is another option.
Previous answer from LoicTheAztec is outdated and gives error about accessing object fields directly on the order object.
Correct code should be
add_action( 'woocommerce_thankyou', 'cheque_payment_method_order_status_to_processing', 10, 1 );
function cheque_payment_method_order_status_to_processing( $order_id ) {
if ( ! $order_id )
return;
$order = wc_get_order( $order_id );
// Updating order status to processing for orders delivered with Cheque payment methods.
if ( get_post_meta($order->get_id(), '_payment_method', true) == 'cheque' )
$order->update_status( 'processing' );
}
I have integrated a payment gateway to accept online payments for my store running on woocommerce. Everything works fine but I noticed that woocommerce is changing the order status to wc-processing for all the online paid orders by default.
As per my store's functionality I want all the online paid orders to be in wc-on-hold status initially.
Is there any way to stop woocommerce changing the order status to wc-processing programatically?
Here it is a code snippet based on this thread. We use here woocommerce_thankyou (that is fired just after payment has been done) to hook our function, converting 'processing' orders status to 'on-hold':
add_action( 'woocommerce_thankyou', 'custom_woocommerce_paid_order_status', 10, 1 );
function custom_woocommerce_paid_order_status( $order_id ) {
if ( ! $order_id ) {
return;
}
global $woocommerce;
$order = new WC_Order( $order_id );
// 'processing' orders status are converted to 'on-hold'.
if ( is_object($order) && $order->has_status( 'processing' ) {
$order->update_status( 'on-hold' );
}
return;
}
You can also target in your conditions the payment gateways for example here we bypass 3 payment gateways and target a specific payment gateway using "your_payment_gateway" slug:
add_action( 'woocommerce_thankyou', 'custom_woocommerce_paid_order_status', 10, 1 );
function custom_woocommerce_paid_order_status( $order_id ) {
if ( ! $order_id ) {
return;
}
global $woocommerce;
$order = new WC_Order( $order_id );
// Bypass orders with Bank wire, Cash on delivery and Cheque payment methods.
if ( ( get_post_meta($order->id, '_payment_method', true) == 'bacs' ) || ( get_post_meta($order->id, '_payment_method', true) == 'cod' ) || ( get_post_meta($order->id, '_payment_method', true) == 'cheque' ) ) {
return;
}
// Target your "your_payment_gateway_slug" with this conditional
if ( is_object($order) && get_post_meta($order->id, '_payment_method', true) == 'your_payment_gateway_slug' && $order->has_status( 'processing' ) ) {
$order->update_status( 'on-hold' );
}
return;
}
This code snippets goes on function.php file of your active child theme or theme.
You can easily do anything you want, and the correct hook for paid orders is woocommerce_thankyou
References:
WooCommerce Class WC_Abstract_Order
WooCommerce: Auto complete paid Orders (depending on Payment methods)
Renaming WooCommerce Order Status
yes there is a way, but you need to modify the payment plugin or add your own code, you can read this to understand how payments work.
Now, woocommerce use $order->payment_complete() method to handle the completed order, so you need to hook your own function to modify the status, here is the description of that method
Use this filter: woocommerce_payment_complete_order_status
Normally wooCommerce should autocomplete orders for virtual products. But it doesn't and this is a real problem, even a BUG like.
So at this point you can find somme helpful things(but not really convenient):
1) A snippet code (that you can find in wooCommerce docs):
/**
* Auto Complete all WooCommerce orders.
*/
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 );
$order->update_status( 'completed' );
}
But this snippet does not work for BACS*, Pay on delivery and Cheque payment methods. It's ok for Paypal and Credit Card gateways payment methods.
*BACS is a Direct Bank transfer payment method
And …
2) A plugin: WooCommerce Autocomplete Orders
This plugin works for all payment methods, but not for other Credit Card gateways payment methods.
My question:
Using (as a base) the wooCommerce snippet in point 1:
How can I implement conditional code based on woocommerce payment methods?
I mean something like: if the payment methods aren't "BACS", "Pay on delivery" and "Cheque" then apply the snippet code (update status to "completed" for paid orders concerning virtual products).
Some help will be very nice.
The most accurate, effective and lightweight solution (For WooCommerce 3 and above) - 2019
This filter hook is located in:
WC_Order Class inside payment_complete() method which is used by all payment methods when a payment is required in checkout.
WC_Order_Data_Store_CPT Class inside update() method.
As you can see, by default the allowed paid order statuses are "processing" and "completed".
###Explanations:
Lightweight and effective:
As it is a filter hook, woocommerce_payment_complete_order_status is only triggered when an online payment is required (not for "cheque", "bacs" or "cod" payment methods). Here we just change the allowed paid order statuses.
So no need to add conditions for the payment gateways or anything else.
Accurate (avoid multiple notifications):
This is the only way to avoid sending 2 different customer notifications at the same time:
• One for "processing" orders status
• And one for "completed" orders status.
So customer is only notified once on "completed" order status.
Using the code below, will just change the paid order status (that is set by the payment gateway for paid orders) to "completed":
add_action( 'woocommerce_payment_complete_order_status', 'wc_auto_complete_paid_order', 10, 3 );
function wc_auto_complete_paid_order( $status, $order_id, $order ) {
return 'completed';
}
Code goes in function.php file of the active child theme (or active theme).
Related: WooCommerce: autocomplete paid orders based on shipping method
2018 - Improved version (For WooCommerce 3 and above)
Based on Woocommerce official hook, I found a solution to this problem *(Works with WC 3+).
In Woocommerce for all other payment gateways others than bacs (Bank Wire), cheque and cod (Cash on delivery), the paid order statuses are "processing" and "completed".
So I target "processing" order status for all payment gateways like Paypal or credit card payment, updating the order status to complete.
The code:
add_action( 'woocommerce_thankyou', 'wc_auto_complete_paid_order', 20, 1 );
function wc_auto_complete_paid_order( $order_id ) {
if ( ! $order_id )
return;
// Get an instance of the WC_Product object
$order = wc_get_order( $order_id );
// No updated status for orders delivered with Bank wire, Cash on delivery and Cheque payment methods.
if ( in_array( $order->get_payment_method(), array( 'bacs', 'cod', 'cheque', '' ) ) ) {
return;
}
// For paid Orders with all others payment methods (paid order status "processing")
elseif( $order->has_status('processing') ) {
$order->update_status( 'completed' );
}
}
Code goes in function.php file of the active child theme (or active theme).
Original answer (For all woocommerce versions):
The code:
/**
* AUTO COMPLETE PAID ORDERS IN WOOCOMMERCE
*/
add_action( 'woocommerce_thankyou', 'custom_woocommerce_auto_complete_paid_order', 10, 1 );
function custom_woocommerce_auto_complete_paid_order( $order_id ) {
if ( ! $order_id )
return;
$order = wc_get_order( $order_id );
// No updated status for orders delivered with Bank wire, Cash on delivery and Cheque payment methods.
if ( ( 'bacs' == get_post_meta($order_id, '_payment_method', true) ) || ( 'cod' == get_post_meta($order_id, '_payment_method', true) ) || ( 'cheque' == get_post_meta($order_id, '_payment_method', true) ) ) {
return;
}
// For paid Orders with all others payment methods (with paid status "processing")
elseif( $order->get_status() === 'processing' ) {
$order->update_status( 'completed' );
}
}
Code goes in function.php file of the active child theme (or active theme).
With the help of this post: How to check payment method on a WooCommerce order by id?
with this : get_post_meta( $order_id, '_payment_method', true ); from helgatheviking
"Bank wire" (bacs), "Cash on delivery" (cod) and "Cheque" (cheque) payment methods are ignored and keep their original order status.
Updated the code for compatibility with WC 3.0+ (2017-06-10)
For me this hook was called even if the payment did not go through or failed, and this resulted to completed failed payments. After some research I changed it to use 'woocommerce_payment_complete' because it's called only when payment is complete and it covers the issue that #LoicTheAztec mentions above –
add_action( 'woocommerce_payment_complete', 'wc_auto_complete_paid_order', 20, 1 );
function wc_auto_complete_paid_order( $order_id ) {
if ( ! $order_id )
return;
// Get an instance of the WC_Product object
$order = wc_get_order( $order_id );
// No updated status for orders delivered with Bank wire, Cash on delivery and Cheque payment methods.
if ( in_array( $order->get_payment_method(), array( 'bacs', 'cod', 'cheque', '' ) ) ) {
return;
// Updated status to "completed" for paid Orders with all others payment methods
} else {
$order->update_status( 'completed' );
}
}
For me, the simplest hook to modify order status when payment is completed is 'woocommerce_order_item_needs_processing' as this filter hook is meant to modify the target order status when payment completes.
This is what the final snippet will look alike:
add_filter('woocommerce_order_item_needs_processing', '__return_false',999);
It also compatible with the other plugins on sites.
For me, on a testing system with PayPal Sandbox (WooCommerce PayPal Payments plugin) the LoicTheAztec solution (2019 update) worked only when I added the $order->update_status( 'completed' ); code line. The return 'completed'; has not an effect in my case, I left it just because it's a filter.
add_filter( 'woocommerce_payment_complete_order_status', function( $status, $order_id, $order ) {
$order->update_status( 'completed' );
return 'completed';
}, 10, 3 );
If you are looking for autocompletion of virtual orders (like courses, ebooks, downloadables etc), this might be useful.
* 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;
}
// No updated status for orders delivered with Bank wire, Cash on delivery and Cheque payment methods.
if ( in_array( $order->get_payment_method(), array( 'bacs', 'cod', 'cheque', '' ) ) ) {
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 virual
* We set the order to completed.
*/
$order->update_status( 'completed' );
}
add_action( 'woocommerce_thankyou', 'custom_woocommerce_auto_complete_virtual_orders' );
Adapted from https://gist.github.com/jessepearson/33f383bb3ea33069822817cfb1da4258