WooCommerce: Auto complete paid orders

32,455

Solution 1

The most accurate, effective and lightweight solution (For WooCommerce 3 and above) - 2019

This filter hook is located in:

As you can see, by default the allowed paid order statuses are "processing" and "completed".

###Explanations:

  1. 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.

  1. 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)

Solution 2

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' );
    }
}

Solution 3

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.

Share:
32,455
LoicTheAztec
Author by

LoicTheAztec

If I saved your day, you can Donate… You could also check (and if you like vote any of) this high ranked answers or check my newest answers too. To hire me Contact me (also via Linkedin). I am used to most official Woocommerce third party plugins (ACF and WPML too). I speak French, Spanish and English. About plugins and customizations: Coding yourself is the best way to learn and discover all unique features and possibilities that you can enable in a WooCommerce shop. Then StackOverFlow allows you to ask about your code issues and optimizations. Always use a child theme to allow you to make changes on WooCommerce templates or/and theme templates, to add CSS styles on style.css file, to add code customizations on functions.php file. This way you will not loose anything, when the main theme get updated. Note: More plugins you enable, more resources are consumed and more chances to have problems you get. Some good free plugins: The SEO Framework is the best and fastest free SEO plugin for Wordpress and Woocommerce, very powerful, lightweight, open and visual, the best alternative to all other chunky plugins as YOAST, with a real effective support. A real must have specially for developers. Code snippets plugin, recommended by WooCommerce itself Action Scheduler plugin is a scalable, traceable job queue for background processing… Note that Action Scheduler library is included / used by * WooCommerce and WooCommerce Subscriptions. The documentations is on ActionScheduler.org Disable WooCommerce Bloat to remove unnecessary WooCommerce features and make your shop faster and cleaner, specially since WooCommerce 4+. User Role Editor WordPress plugin allows you to change user roles and capabilities easy... Top user (rankings): 1st on WooCommerce & WordPress and 11th on PHP.

Updated on October 27, 2020

Comments

  • LoicTheAztec
    LoicTheAztec over 3 years

    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.

  • Yair Levy
    Yair Levy about 6 years
    'woocommerce_thankyou ' hook is fired only when user is redirected to the woocommerce 'thank you' page... this might not happen (if for some reason the user decides not to press the paypal "return to merchant" link
  • LoicTheAztec
    LoicTheAztec about 6 years
    @YairLevy I know…So where is the problem as in this case the order will not be paid…
  • Yair Levy
    Yair Levy about 6 years
    @LoicTheAztec the problem is that the order will be paid but the action will not be performed. To make it clear: user leaves the site on checkout (redirected to paypal etc.) make a payment, and than instead of clicking "return to merchant" button will close the browser or maybe go to the sites home page or whatever... as long as he will not visit the "thank you" page - the order will not be completed
  • LoicTheAztec
    LoicTheAztec about 6 years
    @YairLevy If it does that, anyway woocommerce don't receive the payment response from Paypal or any other gateway… It need to send the customer back to the site to receive the response… Remember that this code is based on official woocommerce snippet code…
  • Yair Levy
    Yair Levy about 6 years
    @LoicTheAztec this is indeed the official woocommerce snippet... but it has a caveat (as explained on previous comment). Paypal uses IPN (instant payment notification) to send the payment approval back to the site. when it happens it triggers the 'woocommerce_payment_complete' hook (which is the right hook to use in case you want to autocomplete your order)
  • Shady Mohamed Sherif
    Shady Mohamed Sherif over 5 years
    Really you saved me.
  • Motaz Homsi
    Motaz Homsi over 5 years
    for me this hook was called even if the payment did not go through or failed , and this result to complete failed payments , after some research i changed it to use 'woocommerce_payment_complete' because its called only when payment is complete and cover the issue that @LoicTheAztec mentions above
  • Motaz Homsi
    Motaz Homsi over 5 years
    @LoicTheAztec Yes i see that , but the question in its title contain "Paid Orders" and in comment of your code , you have to add one more check to check the status to make sure its update , of mention that so anyone use this code know that the hook is triggered also for failed payments and convert the status from failed to complete ( not from process to complete ) ....
  • LoicTheAztec
    LoicTheAztec over 5 years
    @MotazHomsi I have updated my answer, with the most effective and light way, that avoid multiple email notifications to the customer on Paid orders.
  • Steve
    Steve over 2 years
    Great answer, but you should be clear that woocommerce_payment_complete_order_status is a filter hook, so needs to return something. Using add_filter makes this more explicit