Search code examples
phpwordpresswoocommercehook-woocommerceorders

How to automatically delete old completed orders in Woocommerce


I need to set up Woocommerce to automatically clean up old completed orders. Moving to trash would be OK, but I would really prefer to have them deleted. Here's what I'm using now, but it doesn't seem to work:

function expire_after_x_days(){
        global $wpdb;
    // Get current time
        $today = date("mdy");

    // set time to expire
        $time_to_expire = "-180 days";
        $expiration_date = date("mdy", strtotime( $today . $time_to_expire));

    // Get orders with processing status
        $result = $wpdb->get_results("SELECT * FROM $wpdb->posts WHERE post_type = 'shop_order' AND post_status = 'wc-completed'");

        if( !empty($result)) foreach ($result as $order){
            // Get order's time
            $order_time = get_the_time('mdy', $order->ID );

    // Compare order's time with current time -10 days
        if ( $order_time < $expiration_date ){

    // Update order status    
               wp_delete_post($order_id,true);
            }
        }
} 

    // Use the best HOOK for your case 
    add_action( 'admin_footer', 'expire_after_x_days' );

    // OR simply call the function if you are pasting this in your functions.php 

What am I doing wrong?

function expire_after_x_days(){
        global $wpdb;
    // Get current time
        $today = date("mdy");

    // set time to expire
        $time_to_expire = "-180 days";
        $expiration_date = date("mdy", strtotime( $today . $time_to_expire));

    // Get orders with processing status
        $result = $wpdb->get_results("SELECT * FROM $wpdb->posts WHERE post_type = 'shop_order' AND post_status = 'wc-completed'");

        if( !empty($result)) foreach ($result as $order){
            // Get order's time
            $order_time = get_the_time('mdy', $order->ID );

    // Compare order's time with current time -10 days
        if ( $order_time < $expiration_date ){

    // Update order status    
               wp_delete_post($order_id,true);
            }
        }
} 

    // Use the best HOOK for your case 
    add_action( 'admin_footer', 'expire_after_x_days' );

    // OR simply call the function if you are pasting this in your functions.php 

What am I doing wrong?


Solution

  • Use instead the following that will trash and delete all old completed orders (older than 180 days), by batch of 200 to avoid crashing your website. No need to use any WordPress scheduled actions that are really not reliable.

    Here is a simplified and improved code version:

    add_action( 'admin_footer', 'auto_trash_old_completed_orders' );
    function auto_trash_old_completed_orders(){
        $completed_order_ids = wc_get_orders( array(
            'limit'         => 200, // By batch of 200 orders
            'status'        => 'completed', 
            'return'        => 'ids',
            'date_created'  => '<' . date("Y-m-d", strtotime("-6 months")),
        ) );
    
        if ( count($completed_order_ids) > 0 ){
            foreach($completed_order_ids as $completed_order_id ) {
                wp_trash_post($completed_order_id); //
                wp_delete_post($completed_order_id, true);
            }
        }
    } 
    

    Code goes in functions.php file of your child theme (or in a plugin). It should work.

    For HPOS: Auto delete completed orders older than 3 months in Woocommerce with HPOS