skip to Main Content

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?

2

Answers


  1. There are several issues with the code you’ve provided:

    You’ve duplicated the expire_after_x_days() function. This will cause a fatal error in PHP.
    The date format mdy is not an ideal choice for date comparisons. You should use a format that provides a more natural order, such as Ymd.
    You are using get_the_time(‘mdy’, $order->ID ) to fetch the date. Instead, you should use get_post_time().
    $order_id is not defined. It should be $order->ID.
    Hooking this function to admin_footer is not an ideal choice. Every time an admin page is loaded, you’ll be querying and potentially deleting old orders. A scheduled event or a cron job is a better fit.
    Using SQL directly can be risky, especially for important tasks. WooCommerce provides a way to query orders that should be preferred over direct SQL whenever possible.

    function expire_after_x_days(){
        global $wpdb;
    
        // Get current time
        $today = date("Ymd");
    
        // Set time to expire
        $time_to_expire = "-180 days";
        $expiration_date = date("Ymd", strtotime($time_to_expire));
    
        // Query WooCommerce orders using WC_Order_Query
        $args = array(
            'status' => 'completed',
            'date_before' => $expiration_date,
            'return' => 'ids',  // Only return IDs
        );
        
        $orders = wc_get_orders($args);
    
        foreach ($orders as $order_id){
            wp_delete_post($order_id, true);
        }
    } 
    
    // Schedule this event using WP Cron for regular cleanup. 
    if (! wp_next_scheduled ( 'expire_after_x_days' )) {
        wp_schedule_event(time(), 'daily', 'expire_after_x_days');
    }
    

    This function makes use of the wc_get_orders() function from WooCommerce to fetch old completed orders. The function is then scheduled to run daily using WP Cron.

    Login or Signup to reply.
  2. 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);
            }
        }
    } 
    

    It should work.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search