Automatically cancel order after X days if no payment in WooCommerce

后端 未结 1 1251
陌清茗
陌清茗 2020-12-09 23:24

I have managed to put this together after searching the web and yet, it does not work. My aim is to automatically cancel ALL orders with the status on-hold no matter the pay

相关标签:
1条回答
  • 2020-12-09 23:45

    Update 4

    Note: in WooCommerce, there is already a function hooked in woocommerce_cancel_unpaid_orders action hook that cancel unpaid orders after 7 days.

    I didn't find woocommerce_cancel_unpaid_submitted action hook, so I don't know if it exist and if it is triggered.

    Now there is some mistakes in your code and you can better use wc_get_orders() which give you directly the correct array of WC_Order Objects instead…

    Here are some different ways to make it (last ones are untested):

    1) This last solution is tested and works When shop manager or administrator user roles browse the Admin orders list (only executed once a day):

    add_action( 'restrict_manage_posts', 'cancel_unpaid_orders' );
    function cancel_unpaid_orders() {
        global $pagenow, $post_type;
    
        // Enable the process to be executed daily when browsing Admin order list 
        if( 'shop_order' === $post_type && 'edit.php' === $pagenow 
            && get_option( 'unpaid_orders_daily_process' ) < time() ) :
    
        $days_delay = 5; // <=== SET the delay (number of days to wait before cancelation)
    
        $one_day    = 24 * 60 * 60;
        $today      = strtotime( date('Y-m-d') );
    
        // Get unpaid orders (5 days old)
        $unpaid_orders = (array) wc_get_orders( array(
            'limit'        => -1,
            'status'       => 'on-hold',
            'date_created' => '<' . ( $today - ($days_delay * $one_day) ),
        ) );
    
        if ( sizeof($unpaid_orders) > 0 ) {
            $cancelled_text = __("The order was cancelled due to no payment from customer.", "woocommerce");
    
            // Loop through orders
            foreach ( $unpaid_orders as $unpaid_order ) {
                $unpaid_order->update_status( 'cancelled', $cancelled_text );
            }
        }
        // Schedule the process to the next day (executed once restriction)
        update_option( 'unpaid_orders_daily_process', $today + $one_day );
    
        endif;
    }
    

    Code goes in function.php file of your active child theme (or active theme).


    2) This third solution is tested and works: The function is triggered when any order change to "processing" or "completed" status (only executed once a day):

    // Triggered on orders status change to "processing" or "completed"
    add_action( 'woocommerce_order_status_changed', 'daily_cancel_unpaid_orders', 10, 4 );
    function daily_cancel_unpaid_orders( $order_id, $old_status, $new_status, $order ) {
        // Enable the process to be executed daily
        if( in_array( $new_status, array('processing', 'completed') ) 
            && get_option( 'unpaid_orders_daily_process' ) < time() ) :
    
        $days_delay = 5; // <=== SET the delay (number of days to wait before cancelation)
    
        $one_day    = 24 * 60 * 60;
        $today      = strtotime( date('Y-m-d') );
    
        // Get unpaid orders (5 days old)
        $unpaid_orders = (array) wc_get_orders( array(
            'limit'        => -1,
            'status'       => 'on-hold',
            'date_created' => '<' . ( $today - ($days_delay * $one_day) ),
        ) );
    
        if ( sizeof($unpaid_orders) > 0 ) {
            $cancelled_text = __("The order was cancelled due to no payment from customer.", "woocommerce");
    
            // Loop through WC_Order Objects
            foreach ( $unpaid_orders as $order ) {
                $order->update_status( 'cancelled', $cancelled_text );
            }
        }
        // Schedule the process to the next day (executed once restriction)
        update_option( 'unpaid_orders_daily_process', $today + $one_day );
    
        endif;
    }
    

    Code goes in function.php file of your active child theme (or active theme).


    3) So you can try with woocommerce_cancel_unpaid_submitted action hook:

    add_action( 'woocommerce_cancel_unpaid_submitted', 'cancel_unpaid_orders' );
    function cancel_unpaid_orders() {
        $days_delay = 5; // <=== SET the delay (number of days to wait before cancelation)
    
        $one_day    = 24 * 60 * 60;
        $today      = strtotime( date('Y-m-d') );
    
        // Get unpaid orders (5 days old here)
        $unpaid_orders = (array) wc_get_orders( array(
            'limit'        => -1,
            'status'       => 'on-hold',
            'date_created' => '<' . ( $today - ($days_delay * $one_day) ),
        ) );
    
        if ( sizeof($unpaid_orders) > 0 ) {
            $cancelled_text = __("The order was cancelled due to no payment from customer.", "woocommerce");
    
            // Loop through orders
            foreach ( $unpaid_orders as $order ) {
                $order->update_status( 'cancelled', $cancelled_text );
            }
        }
    }
    

    Code goes in function.php file of your active child theme (or active theme).

    The function code should better works. For the hook I really don't know.


    4) You can try also with woocommerce_cancel_unpaid_orders action hook instead.

    0 讨论(0)
提交回复
热议问题