Blog

How to Set WooCommerce Virtual Order Status to Complete After Payment

Please note that this snippet will work for WooCommerce 2.0 and 2.1, but not 2.2+ – the order status structure has changed in version 2.2 to support refunds. If we post an updated version, we’ll link to it here when published.

WooCommerce virtual orders can be automatically marked as ‘completed’ after payment with a little bit of code added to a custom plugin, or your themes functions.php file. By default WooCommerce will mark virtual-downloadable orders as ‘completed’ after successful payment, which makes sense, but some store owners will want to be able to automatically mark even a virtual order as complete upon payment, for instance in the case of a site which takes donations where no further action is required. To do so, use the following code, which is based on the core virtual-downloadable completed order status:

add_filter( 'woocommerce_payment_complete_order_status', 'virtual_order_payment_complete_order_status', 10, 2 );

function virtual_order_payment_complete_order_status( $order_status, $order_id ) {
  $order = new WC_Order( $order_id );

  if ( 'processing' == $order_status &&
       ( 'on-hold' == $order->status || 'pending' == $order->status || 'failed' == $order->status ) ) {

    $virtual_order = null;

    if ( count( $order->get_items() ) > 0 ) {

      foreach( $order->get_items() as $item ) {

        if ( 'line_item' == $item['type'] ) {

          $_product = $order->get_product_from_item( $item );

          if ( ! $_product->is_virtual() ) {
            // once we've found one non-virtual product we know we're done, break out of the loop
            $virtual_order = false;
            break;
          } else {
            $virtual_order = true;
          }
        }
      }
    }

    // virtual order, mark as completed
    if ( $virtual_order ) {
      return 'completed';
    }
  }

  // non-virtual order, return original status
  return $order_status;
}

Note: This article has been updated to work with WooCommerce 2.0+ and the sample code above will no longer work with WC 1.6.6 and previous

We also have a convenient plugin available that can do this for you, which will continue to be updated even if this tip becomes irrelevant: WooCommerce Order Status Control.

114 Comments

  • Louis 4 months ago Reply

    I am bookmarking this one — thanks again Justin.

  • Hendrik 4 months ago Reply

    Thanks a lot for sharing, it’s exactly what I needed!

  • Hendrik 4 months ago Reply

    Could it be that the code doesn’t work with the latest update? If so, do you have an idea what to change? Thanks in advance, Hendrik

    • justin 4 months ago Reply

      Hey Hendrik, sorry to hear it’s not working for you. I just gave this solution a try in the most recent WooCommerce and it worked just fine for me, so not sure why it wouldn’t be working for you. One thing to note is that this will complete an order only if the entire order consists of virtual products.

  • Martin 4 months ago Reply

    Thanks Justin,

    If I understand. I have to put the code in my “fonctions.php” of my “inspire-commerce theme” and that’s it?

    I sell a membership for the website so it’s not a physical product and not a downloadable product too. The orders status stay on “Processing” until I put the orders on “Complete”. So the customers can’t reach the membership content until I put the order on “Complete”.

    I hope this will fix my problem.

    Thanks.

    • justin 4 months ago Reply

      Yep, you got it, just make sure you’re setting these products as “virtual”

      • Martin 4 months ago Reply

        Thanks Justin!

        It’s working now! Thanks for sharing with us this solution. It’s very appreciate!

  • Tristan 4 months ago Reply

    Hi,

    I’ve pasted that code into my theme’s functions.php at the end, but before the ?>. I’ve set the product to Virtual and it’s still not auto-confirming the order?

    Great site, thanks in advance!

    • justin 4 months ago Reply

      hmm, I just took another look at the relevant WooCommerce core code, and I can’t see anything that would cause this not to work. I’ve been unable to reproduce whatever the issue is, so I’m not able to determine why it would not work for you, it should just work assuming that the entire order consists of virtual products. I’m afraid you’d have to do a little debugging to track down the problem, if this is something you’re able to tackle, I do have an introduction to debugging WordPress which you can read through. You’d want to add some error_log() statements: first to make sure the virtual_order_payment_complete_order_status() is being called, and then to figure out whether it’s returning the correct status “completed” when you desired. Hope this helps

  • Drew 4 months ago Reply

    Do you think I could use this for a regular product as well? I have a customer who never bothers going into their admin panel so the orders always sit as ‘processing’ and I would like them to automatically be marked as completed. I fairly new to WC so I am having some trouble figuring out how to do this.

    • justin 4 months ago Reply

      Sure, that’s a simpler, more general case than what I did here. Get rid of the check for whether the order is virtual, and just return ‘completed’

      • Drew 4 months ago Reply

        So would that look like this?

        add_action( ‘woocommerce_payment_complete_order_status’, ‘virtual_order_payment_complete_order_status’, 10, 2 );

        function virtual_order_payment_complete_order_status( $order_status, $order_id ) {

        $order = new WC_Order( $order_id );

        if ( $order_status == ‘processing’ &&

        ( $order->status == ‘on-hold’ || $order->status == ‘pending’ || $order->status == ‘failed’ ) ) {

        $order = true;

        if ( count( $order->get_items() ) > 0 ) {

        foreach( $order->get_items() as $item ) {

        if ( $item[‘id’] > 0 ) {

        $_product = $order->get_product_from_item( $item );

        }

        }

        }

        // virtual order, mark as completed

        if ( $order ) {

        return ‘completed';

        }

        }

        }

        • justin 4 months ago Reply

          Well, no, the function should be even simpler, maybe something just like:

          function virtual_order_payment_complete_order_status( $order_status, $order_id ) {

          $order = new WC_Order( $order_id );

          if ( $order_status == 'processing' &&

          ( $order->status == 'on-hold' || $order->status == ‘pending’ || $order->status == ‘failed’ ) ) return 'completed';

          return $order_status;

          }

          • Rostam 2 months ago

            Hi!
            For some reason, this code does not work for me. I can’t figure out why, as the original code (for virtual products only) did work just fine.
            Any ideas?

            Thank you!

          • Justin Stern 2 months ago

            Unfortunately I’m not sure why the code might cease to work for you. And, it still does work for “virtual products only”, so I don’t think that’s the issue

  • kathy 4 months ago Reply

    Hi Justin,

    I had a question about your choice of conditionals….

    if ( $order_status == 'processing' &&

    ( $order->status == 'on-hold' || $order->status == 'pending' || $order->status == 'failed' ) )

    What is the point of checking that original $order->status ? Also, nitpicking, but shouldn’t it be add_filter()? Anyway, I appreciate your sharing this! Cheers!

    • justin 4 months ago Reply

      Hey Kathy, thanks for pointing out my action/filter misstype, wordpress is so loose with that sort of thing that I think it still works anyways, but I do prefer using the correct one.

      As for checking the original order status, I based this function off of WC_Order::payment_complete(), and they make the same check there and so I maintained it.

      Thanks!

      • kathy 4 months ago Reply

        Hi Justin,

        One more thing: I presume you are adding this to your theme’s functions.php?? I ask, because I’ve tried putting this in my plugin’s class and my function that is attached to ‘woocommerce_payment_complete_order_status’ never seems to fire.

        thanks,

        -kathy

        • kathy 4 months ago Reply

          it was a facepalm!!! of the highest order. hangs head in shame. thanks again for this post.

          • justin 4 months ago

            Ha ha, no problem, glad if it was of help to you!

  • Jamie 4 months ago Reply

    Hi Justin,

    Looks like you have another useful piece of code I want to use! I am trying to adapt this code so that any orders I get with the status ” On Hold” or “Pending” are updated to “Processing”.

    Simple I thought, but unfortunately I can’t get it to work. I have taken your code and changed it to this:

    function virtual_order_payment_complete_order_status( $order_status, $order_id ) {

    $order = new WC_Order( $order_id );

    if ( $order_status == 'on-hold' &&

    ( $order->status == 'pending' || $order->status == ‘failed’ ) ) return 'processing';

    return $order_status;

    }

    Nothing changes on the backend with the above code. What am I doing wrong?

    Many thanks in advance for your help.

    Jamie

    • justin 4 months ago Reply

      Hey Jaime, in this filter $order_status will be the status that the order is being set to, while $order->status will be the current (soon to be previous) order status. So to automatically set on-hold/pending orders to processing, you could simply try replacing your if statement with:

      if ( $order_status == 'on-hold' || $order_status == 'pending' ) return 'processing';

      Where here we don’t even care what the previous order status was, we’re just making all on-hold/pending status’ change to ‘processing’.

      • Jamie 4 months ago Reply

        Hi Justin,

        Many thanks for the explanation. I understand where I went wrong now! I will give the new code a try and post back with my results.

        Little by little I am beginning to understand, it’s a slow process for me though!

        Jamie

        • Jamie 4 months ago Reply

          OK, I tried the new code, but nothing seems to happen. I have placed a couple of orders and they are still at the “On Hold” status.

          Here’s my code below that I’m adding to the theme’s function.php file:

          function virtual_order_payment_complete_order_status( $order_status,

          $order_id ) {

          $order = new WC_Order( $order_id );

          if ( $order_status == 'on-hold' || $order_status == 'pending' )

          return 'processing';

          return $order_status;

          }

          I also tried the same code without the return $order_status at the end:

          function virtual_order_payment_complete_order_status( $order_status,

          $order_id ) {

          $order = new WC_Order( $order_id );

          if ( $order_status == 'on-hold' || $order_status == 'pending' )

          return 'processing';

          }

          Any ideas where I’m going wrong?

          Many thanks,

          Jamie

    • Binh 9 weeks ago Reply

      @Jamie, you may have forgotten the “add_filter” line:
      add_filter( ‘woocommerce_payment_complete_order_status’, ‘virtual_order_payment_complete_order_status’, 10, 2 );

  • greg 4 months ago Reply

    am using a theme called Bounce by ghostpool.com, am wanting to add this code to the theme functions… just trying to understand why the redirect is to

    themes.php?page=theme-options.php

    Redirect to Theme Options after Activation

    Does this mean the user upon successful sale is redirected to the theme options page?

    • justin 4 months ago Reply

      No, you’re probably talking about the WP Admin theme options page that can be displayed by certain themes when you activate them. This will have nothing to do with the thank-you page a customer sees after checking out

  • Andrew 3 months ago Reply

    Think I might be doing something wrong? Every time I put the code in my ‘functions.php’ it just makes the code appear at the top of my website for everyone to see.

  • Fidel de la Hoya 3 months ago Reply

    Great! worked perfectly for me :) really nice work!!

    • justin 3 months ago Reply

      Awesome!

  • John Hawkins 3 months ago Reply

    This process seems to have broken after an update to WooCommerce 2.0. It doesn’t seem to be passing $order_id. I’m digging under the hood now, but wanted to see if you have run in to this as well and if you had a solution.

    Thanks.

    • justin 3 months ago Reply

      Hey John, I just took a look at the WooCommerce code and it’s definitely still passing the order id; must be something else going on in your environment? Did you get this working?

    • Bassscape 3 months ago Reply

      Yes, I’m in the same boat as John. Marking orders as complete is no longer working for me. I’m still looking for a solution as this functionality was great to have. Doh!

      • justin 3 months ago Reply

        Yeah, sorry about this, this was long overdue, I’ve updated the sample code to be WooCommerce 2.0+ compatible (and no longer compatible with WC 1.6.6 and earlier)

  • marc beneteau 3 months ago Reply

    Also not working for me on WooCommerce 2.0. In my case I use payment method “COD” as its a free download, I just want them to go through the checkout process and get download immediately. It’s Virtual and Downloadable order. The order remains in status “On Hold”. Should I perhaps try another payment method like Bank Transfer?

    • justin 3 months ago Reply

      Hey Marc, my code will only work for a payment gateway that processes payment. You’d need a different implementation to make this work with one of the “fake” gateways like COD or bank transfer

  • Mark Petersen 3 months ago Reply

    Hello there,

    Im trying to get your code to work for me. im using variables products though, so i cant seem to get this to work?

    Thanks in advanges

    • justin 3 months ago Reply

      Hey Mark, I have updated the code to be WC 2.0 compatible, and tested with a variable virtual product and it is now working. Cheers!

  • Jay 3 months ago Reply

    Hi Justin,

    I have applied this a while ago and it worked great until today. I haven’t updated the woocommerce plugin but i have updated the Follow Up Emails for woocommerce plugin because welcome emails were not going out, could this have effected it?

    If not, how would I go about diagnosing why it is not working.

    Thanks again!

    • justin 3 months ago Reply

      Hey, it definitely was broken for WC 2.0, I know you said you didn’t upgrade, but I guess I’d recommend upgrading now if you haven’t already and then trying out the updated code that I just posted

  • Joe 3 months ago Reply

    Hi Justin,

    I recently upgraded to WC 2.0 and have found that this function has stopped working as before. All my orders (virtual or not) are being marked as completed now. I have looked at the code and can’t see any obvious reasons why this has stopped working. (FYI, this seems to be impacting variable products.)

    Any help would be really appreciated.

    Cheers.

    Joe

    Joe

    • justin 3 months ago Reply

      Hey Joe, I have updated the code and this should now be working with WC 2.0

  • Andy 3 months ago Reply

    THANK YOU kind sir. I was able to easily modify this code to work for my specific needs.

    I used the same hook to submit data to a CRM to manage my customers better.

    Thanks again!

  • jason 3 months ago Reply

    Hope you can give me an idea on where to start troubleshooting this — the code works – virtual orders are being marked as complete.

    However, I’m testing a Simple product which is *not* marked as virtual, and it too is being marked complete upon successful purchase. Hrm.

    If I remove the code, then virtual products and simple products return to default functionality, and show up as pending.

    Any idea on where to start looking?

    Somehow the code is returning that all purchase are virtual no matter what.

    I can’t see where I can put in another conditional to bail out of the script if the product is not virtual… as that test is already right there.

    Stumped. I’ve checked and double checked that the product is just a regular old physical product, no downloads no nothing — shipping rates show up, tax shows up… ????

  • Jason 3 months ago Reply

    Face –> Palm.

    Just read the last comment before the one I posted and see that I had old version of the code from somewhere else.

    New version = working.

    Thank you !!!

    • Justin Stern 3 months ago Reply

      ha ha ok cool, I just tested the code in my dev environment and it worked fine so I was about to ask whether you had the latest. You beat me to it!

  • Jeramiah 3 months ago Reply

    Will this help fix my issue?, I can seem to go through the whole process of adding a virtual product…in my case a mp3 file, but it wont show the download links on the order page or even in the email woocommerce sends out. I managed to get it working for a pretend user I created but I had to manually go in as admin to the order page and grant access to that file (product) so it shows up under the “My Account” page when I log back in as a user. I am very confused. I have been searching google and ended up here. any help would be great!

    I think it’s basically not auto approving it somehow. I am just paying myself between 2 of my pay pal accounts and the transactions are working. Just the available download links are not working.

    Many thanks.

    Jeramiah

    • Max Rice 3 months ago Reply

      Hey Jeramiah, sounds like the orders aren’t being completed properly. You’ll want to make sure PayPal is sending the payment notifications correctly by looking at the order notes for the order. If you don’t see “PayPal IPN Completed”, then you’ll need to look into that.

  • Matt 3 months ago Reply

    Hi There,

    This looks to be the code i’m after but nothing happens… I have setup my WooCommerce product to be virtual and downloadable and when the i complete the order with the default “Direct Bank Transfer” as admin the order stays on-hold and not completed.

    WooCommerce looks great for a membership site offering digital files, but really a must have is being able to auto approve customers rather them having to wait to get manually approved to have access to the files.

    I’m updated to WooCommerce 2.0.10.

    Would love to get this working ;)

    • Max Rice 3 months ago Reply

      Hey Matt, “Direct Bank Transfer” changes the order status to ‘on-hold’, which doesn’t indicate to WooCommerce that payment is complete for the order. You can add a bit of code to automatically complete orders paid for with “direct bank transfer”, but you then run into the issue of people submitting fake orders in order to get immediate access.

  • Philly 3 months ago Reply

    Hey is there anyway to do it without a hook?

    simply by order id?….because the action im taking is outside of woocommerce

    i simply want to place inside of my existing function this order id update to completed

    i thought of doing it just through update_post_meta but i was scared the completed email wouldnt fire off

    • Max Rice 3 months ago Reply

      Sure, if you have an order ID you can complete the order like this:


      $order = new WC_Order( $order_id );

      $order->payment_complete();

  • Paul 3 months ago Reply

    Hi Justin,

    Brilliant! … works perfectly …. I’m using it with The Events Calendar & WooTickets … It would be great if I could get “Virtual” to be the default setting on every product… Any thoughts??

    Thanks again!

  • Goyo 2 months ago Reply

    Hi Justin,

    I’ve placed the conde on the functions.php, right after the opening php line, the product is marked as virtual and downloable but the orders holds on pending and no automatic status chage are made >,< (WC 2.0.10)

    • Max Rice 2 months ago Reply

      This code only works for orders that payment has been received for, so if it’s pending it won’t change the order status. If you’re using PayPal, make sure that IPN is working and orders being correctly moved into the “processing” status first :)

  • Israel 2 months ago Reply

    Note for those (like me) who tried this code solution and saw no results: if you’re not calling the add_filter() soon enough, it won’t kick in. I’m using a child theme, and so had to make sure I placed

    add_filter( ‘woocommerce_payment_complete_order_status’, ‘virtual_order_payment_complete_order_status’, 10, 2 );

    in the action hook “after_setup_theme”. Then it worked perfectly! Even paypal standard worked quickly, and my virtual orders are auto-completing (without having to be “downloads” too)

  • Joseph 2 months ago Reply

    Hello

    I’m trying a simple thing but no success. I just want to skip whole “pending” and “on-hold” status. I want that all orders after they are payed go automatically to “processing” status so user receives email notification.

    Could you please put whole code for this, since many of us are just beginning to learn php, so this simple task is not so simple for us :)

    This is what I came up with help of this thread, but it’s doesn’t work.

    /*Order status*/
    function global_pending( $order_status, $order_id ) {

    $order = new WC_Order( $order_id );

    if ( $order_status == ‘on-hold’ || $order_status == ‘pending’ ) return ‘processing';

    return $order_status;

    }
    add_filter( ‘woocommerce_payment_pending_order_status’, ‘global_pending’);

    • Max Rice 2 months ago Reply

      That filter you’re using doesn’t exist :) The code above only works for orders that have received payment, so if you’re using something like PayPal, make sure that IPN’s are working correctly and orders are being moved into the “processing” status first.

      • Joseph 2 months ago Reply

        Hello

        OK. Is there a way to skip whole pending and on-hold process, and just tell woocommerce that all orders go to processing mode?

        Cheers

        • Max Rice 2 months ago Reply

          The initial order status is hardcoded to ‘pending’, but you could change it to whatever status you want by using this filter: https://github.com/woothemes/woocommerce/blob/v2.0.12/classes/class-wc-checkout.php#L674

          • Doris 2 months ago

            Very new to all this. What would the filter be for “processing” and where would I put it?

          • Justin Stern 2 months ago

            Hmm, not entirely sure what you’re asking. This code will take an order that would have gone to the processing state, and move it to the completed state if it’s an order containing only virtual products, and the snippet can go in your theme’s functions.php

  • Flavia Russo 2 months ago Reply

    Thank you for sharing your solution. It perfectly works on my site!

  • Mohammad 2 months ago Reply

    Thanks ! this code worked for me .

  • Olivier 2 months ago Reply

    Hello,

    Thanks for sharing that code, it’s very useful!
    Is there a compatibility issue between this code and the Follow Up Emails for Woocommerce plugin? Looks like none of the auto emails are triggered when using this code (triggers based on status=complete)? Would the plug-in you sell work better?

    Thanks. Olivier

    • Max Rice 2 months ago Reply

      Hey Olivier, unfortunately there is a bug with the Follow Up Emails plugin that prevents it from working correctly when order statuses are changed directly from pending to completed — you’ll want to submit a support ticket on http://support.woothemes.com so they can let the Follow Up Emails dev know :)

      • Olivier 2 months ago Reply

        Thanks Max. That’s unfortunate :( I’ll let them know…

        • Max Rice 2 months ago Reply

          I think this is fixed in the 2.5 release which should be coming out today or tomorrow :)

  • Schalkk 2 months ago Reply

    Hey there
    Is there a way to auto select/default the virtual checkbox as I am using wp user frontend to load products and need both virtual and downloadable checkboxes to be automatically selected?

    Please help!

    • Justin Stern 2 months ago Reply

      Well anything’s possible, but I’m actually not familiar with WP User Frontend. Perhaps someone else out there has an idea?

  • karan 2 months ago Reply

    Hello Justin,

    I am using downloadable products for my site with woocommerce, and i want order becomes auto complete after users payment and redirect orders received with downloadable link. i am doing this thing manually in orders with change the status “Completed”. after that user got the mail of order received with downloadable link. i want to do this automatically. Thanks

    • Max Rice 2 months ago Reply

      If your orders are already being marked as “processing” you can set the option under WooCommerce > Settings > General > “Grand Access to downloadable products after payment” which should work for you.

  • Marlies 2 months ago Reply

    Hmm unfortunately, it is not working on my site… I have the WooCommerce combined with Wootickets (for The Events Calendar), and as a payment gateway I am using Sisow IDEAL (in test mode). Any idea what could be the problem?

    Would be great if there would be a way to autocomplete the order. Right now my wordpress is not even sending out a notification of a new order, because of the status ‘pending’. Would be perfect if it could at least move from pending to processing without my help. Could this be because of the test environment maybe? or the maintenance mode my site is in?

    • Max Rice 2 months ago Reply

      This code will only work if your payment gateway is marking the order as payment completed first. The Mollie gateway relies on a payment notification that your site must process first, so I’d check to make sure orders are being marked as “processing” — if they always show as “pending”, then that’s your issue :) It could be because of a test environment, especially if it’s local to your computer or is otherwise prevented from receiving the notification from Mollie’s servers.

  • Shaina 2 months ago Reply

    I’m using WooCommerce to process orders of non-virtual products that will later be invoiced, so no PayPal, and therefore no way to automatically mark the orders as payment completed. I’m using the “cash on delivery” option to receive payment. Is there a way I can get the payment to mark as completed automatically so I can use the bit of code Justin posted on 12 October 2012 to mark orders as complete? (The people handling invoices will have nothing to do with the website aside from getting emails indicating that the order has been placed, but I want the “order again” feature on previous orders to work.)

    PS – I’m good and copying and pasting, but know pretty much no PHP. :)

    • Max Rice 2 months ago Reply

      This should get you started :) https://gist.github.com/maxrice/6772280

    • James Ulrich 4 weeks ago Reply

      Hello,

      I have the same problem than Marlies. I have the WooCommerce combined with Wootickets (for The Events Calendar) and I would like to process just those tickets, so I use your code changing the type of the item from ‘line’ to ‘tribe_wooticket’. Anyway, it’s not working and it has the same effect if I comment the line with the “add_filter” code.

      add_filter( ‘woocommerce_payment_complete_order_status’, ‘virtual_order_payment_complete_order_status’, 10, 2 );
      function virtual_order_payment_complete_order_status( $order_status, $order_id ) {
      $order = new WC_Order( $order_id );

      if ( ‘processing’ == $order_status && ( ‘on-hold’ == $order->status || ‘pending’ == $order->status || ‘failed’ == $order->status ) )
      {
      $virtual_order = null;

      if ( count( $order->get_items() ) > 0 )
      {
      foreach( $order->get_items() as $item )
      {
      if ( ‘tribe_wooticket’ == $item[‘type’] )
      {
      $_product = $order->get_product_from_item( $item );

      if ( ! $_product->is_virtual() )
      {
      // once we’ve found one non-virtual product we know we’re done, break out of the loop
      $virtual_order = false;
      break;
      }
      else
      {
      $virtual_order = true;
      }
      }
      }
      }

      // virtual order, mark as completed
      if ( $virtual_order ) {
      return ‘completed';
      }
      }

      // non-virtual order, return original status
      return $order_status;
      }

      I’m using a free product, so there’s no payment. Can that be the source of the problem?

      Cheers.

  • Lars 2 months ago Reply

    Hi,
    I would like to do it the opposite way. Currently and order are mark as “Processing” when a payment is done. I wan’t it to be marked as “Pending”. Is it possible?

    • Justin Stern 2 months ago Reply

      Hey Lars, it can be done but would require some custom coding, something like the following in your theme’s functions.php, which should always set the order status to ‘pending’ after payment is complete:


      add_filter( 'woocommerce_payment_complete_order_status', 'woocommerce_payment_complete_order_status_pending', 10, 2 );
      function woocommerce_payment_complete_order_status_pending( $new_order_status, $order_id ) {
      return 'pending';
      }

      Just note that WooCommerce defines the “pending” status as “order received (unpaid)”, so just be certain this makes sense for your business processes.

  • Craig Grella 2 months ago Reply

    You guys rock, this is the exact code I needed on a member association site for a client.
    Thx.

  • Nicholas Chen 2 months ago Reply

    i add the code to my themes function.php file and it brings down the whole site. the message i get is:

    Internal Server Error
    The server encountered an internal error or misconfiguration and was unable to complete your request.
    Please contact the server administrator, cgiadmin@yourhostingaccount.com and inform them of the time the error occurred, and anything you might have done that may have caused the error.
    More information about this error may be available in the server error log.
    Additionally, a 500 Internal Server Error error was encountered while trying to use an ErrorDocument to handle the request.

    i am using the wordpress theme flexform. any idea what i am doing wrong?

    • Justin Stern 2 months ago Reply

      No, really not sure, this code has been verified to work on numerous systems, and the nature of PHP is that if it works in one environment it will work in another, so I’d have to think the change was some coincidence, or something else was going on. I know it’s been a while, but I hope you got this resolved anyhow!

  • Sidnei 2 months ago Reply

    Why in the world talk about changing the status from another status and no one says anything about change of status from a client action? Example: After the purchase the customer must approve an image by clicking a button of “approved” and automatically change the status?? Is it very difficult?

    • Justin Stern 2 months ago Reply

      Nope, it’s certainly easy enough to change the status of an order programmatically, be that from a client action like you’ve described, or otherwise. The WC_Order object defines a method update_status() which can be used to update the status of an order like so: $order->update_status( 'completed' );

  • João G. 2 months ago Reply

    Hi, thanks for sharing your code! I will try it right now but I have a doubt: will your code work with downloadable products (free products) ? Thanks man!

    • Beka Rice 2 months ago Reply

      Hi, there’s a setting (I think under WooCommerce > Settings > General) to complete an order once a downloadable product is purchased, so you won’t even need to use this code for that :)

      • Nick Meisher 2 months ago Reply

        Beka,

        There is only this setting

        Grant access to downloadable products after payment
        Enable this option to grant access to downloads when orders are “processing”, rather than “completed”.

        This code makes transactions completed for virtual products, since if the box is checked for the option you mentioned, the admin will still have to mark the order as completed but when the code is used, that extra step is no longer necessary.

  • Oktay 2 months ago Reply

    Hi, I tried the function.php hook and it works fine, thanks but:
    Is that possible to also force sending the completed order e-mail to the customer ?
    i’m selling a virtual product which usage is described into the completed order e-mail (template override to display customized information).

    • Justin Stern 2 months ago Reply

      Actually the completed order email *should* be sent to the customer when the status is changed. If it’s not happening, there’s probably some other issue at play

  • Jhon 2 months ago Reply

    What if product is not virtual? that product have shipping and tax what you advice to add in this code

    • Justin Stern 2 months ago Reply

      This code simply shows an approach to marking virtual orders automatically as “complete”. It certainly could be adapted to perform in other cases, it all depends on what you’re trying to do

  • Mike 1 month ago Reply

    Thanks for this. It works as expected, however, how can I make sure all other actions from other plugins fire when triggered by autocompletion? Is there a woocommerce hook/action that is supposed to fire when the order is manually completed (by hitting the button, for instance.)?

    I have another plugin that is triggered by completion to trade data with another system. It does not seems to fire when autocompletion occurs.

    Thanks very much!

    • Max Rice 1 month ago Reply

      You’d have to find out which hook the plugin is using, as this set of code should trigger the same actions that would normally be run when a gateway completes an order.

  • Eric 1 month ago Reply

    Thanks for this code. I have it up and working. I’m wondering if this functionality could be moved into a homemade extension. I tried that first and my website didn’t seem to like it so I deleted the homemade extension and put the code into the functions.php file. I’d rather not have to edit a theme related file so a homemade extension would be ideal.

    • Max Rice 1 month ago Reply

      Hey Eric,

      Sure you could, building a plugin is a bit more complex than adding to your functions.php but totally doable. Alternatively you could purchase the Order Status Control extension which does this for you :)

  • Dimitar 1 month ago Reply

    Hi there thx for the great solution but i need something else related to this. I need this solution to works for all orders that are made and paid by PayPal and other gateways. I also want to be able to manualy process and complete the orders that are made using bank transfer or pay by cheque? What do i need to change ?

    Thx

    • Beka Rice 1 month ago Reply

      Hi there, the code provided should work just as you’ve described, as it won’t autocomplete orders via check, bank transfer, or manual gateways.

  • James 1 month ago Reply

    Thank you very much! This is a very useful article.

  • James Vreeken 1 month ago Reply

    I am designing a meal plan website and I can’t seem to figure out how to get orders that have used a 100% off coupon to have the order autocomplete. It doesn’t seem to be working when the price they pay is $0. any ideas?

    • Beka Rice 1 month ago Reply

      Hey there, since free orders don’t use your payment gateway, the order will go straight to processing for anything with a $0 cost. You’d need some custom code specific to free orders to get this to work.

  • Rose 1 month ago Reply

    I’ve been trying to use this function but it seems that when trying to make payment via paypal, WooCommerce is not doing the payment_complete function. I’ve tried to fiddle with the checkout class to confirm this.

  • Emil 27 weeks ago Reply

    Hi

    I get this error message after copying the code to my functions file:

    Fatal error: Cannot redeclare virtual_order_payment_complete_order_status() in /public_html/wp-content/themes/retail-therapy/functions.php on line 34

    Maybe I should just buy the plugin, but do you know what I am doing wrong? :)

    • Beka Rice 27 weeks ago Reply

      Sounds like code may have gotten duplicated – make sure there’s only one function virtual_order_payment_complete_order_status() as you may have pasted twice.

  • David Wang 21 weeks ago Reply

    Hi Justin, would this code work in a site functionality plugin? I have this snippet in a plugin in my mu-plugins directory but it doesn’t work. It works though when it’s in functions.php

    • Beka Rice 21 weeks ago Reply

      Yep, you could do this. If you want to make it easy, we have a plugin available that we maintain and update, as I’m sure at some point this post will be out of date.

  • james 21 weeks ago Reply

    Hi, i am having an entirely different problem here. For some reason all our orders are marked as completed automatically without us making any changes at all? We are trying to make it default to processing but it wouldnt. We are selling physical goods and have not ticked virtual goods on our products. We cant for our life figure out why its doing that. We have not added any codes anywhere or plugins that would lead to this. Wondering if you can help?

  • james 21 weeks ago Reply

    just reviewing my problem. we are selling physical goods. by default which im not sure why its marking all our orders completed when we dont want to as we need to dispatch it. Did not install any plugins, write any codes or tick the virtual goods checkbox. So we are unsure of why this is happening. Tried using the codes above and it worked by replacing the complete status with processing. However its causing issues in terms of triggering email notifications.

    This is what we are after:
    Processing>Manually Complete – This sends out 2 emails, one order confirmation and another dispatch/completion email.

    Right now this is happening:
    AutoComplete>AutoProcessing>Manually Complete – This sends out 1 email, order confirmation. Whenw e tick the complete order, it does not send out email anymore.

    Can you please advise how we can fix this?

    • Beka Rice 21 weeks ago Reply

      Hey James, the scenario you’re after is how WooCommerce works by default. You should remove any code present, as only virtual orders are completed by default. Physical orders are set to processing and manually completed (typically when shipped). Try setting up a staging environment with a default theme and deactivating all plugins except WooCommerce, then place a test order. You should see this workflow. You can then re-enable one-by-one to see if a plugin or some code in your theme’s functions.php is at fault.

  • Kazin 9 weeks ago Reply

    Hello,

    I realize this is an old article, but I hope you still read this.

    The code works perfectly. But there is one small issue with causes an error on my website.
    This code bypasses the ”processing” status.

    Is it possible to, instead of going from ”pending payment -> completed” go from ”pending payment -> processing -> completed” automatically once payment is received?

  • Alessandro 5 weeks ago Reply

    Hi guys!
    Thanks for your great snippet!
    I have a question, though: is it possible to make order status as complete by adding a custom field within the order? I’m thinking about the tracking code. I need to flag order as complete only as soon as my carrier has taken the purchased items.
    What do you think about?
    Thanks in advance for your help.

  • Amber 5 weeks ago Reply

    Thanks for providing the snippet. Unfortunately it’s not working in my child theme functions.php… virtual orders don’t autocomplete. : (

  • Sandra 5 weeks ago Reply

    Thank you so much for this useful code! I really needed the orders to autocomplete and didn’t know how to do it. You have saved my life :-)

    Thank you!!
    Sandra

Submit a Comment