Search code examples
phpwordpresswoocommercehook-woocommerce

WooCommerce: Change order status based on custom Meta Value


I'm trying to run the following function daily, to auto-complete all processing order older than 10 days and who have a specific custom meta value.

I'm using the following snippet, however this will simply not work. Any idea as to why?

function autoComplete(){
    $orders = wc_get_orders( array(
            'status' => 'wc-processing',
            'date_created' => '<' . ( time() - 10 * DAY_IN_SECONDS ),
            'meta_key'     => 'status_us',
            'meta_compare' => '=',
            'meta_value'   => 'Sent to USA',
    ) );

    foreach ($orders as $order){
        $order->update_status( 'completed' );
    }
}

if ( ! wp_next_scheduled( 'autoComplete' ) ) {
    wp_schedule_event( time(), 'daily', 'autoComplete' );
} 

Is there any error I've missed? Thanks for your help!


Solution

  • You did a good attempt but you made a few mistakes.

    The following code goes inside your functions.php.

    add_action( 'wp_loaded','start_custom_code' );
    
    // Once everything theme and plugins are loaded we register our cron job.
    function start_custom_code() {
        if ( ! wp_next_scheduled( 'bks_mark_processing_order_complete_if_sent_to_usa' ) ) {
            wp_schedule_event( time(), 'daily', 'bks_mark_processing_order_complete_if_sent_to_usa' );
        }
    }
    
    add_action( 'bks_mark_processing_order_complete_if_sent_to_usa', 'bks_mark_processing_order_complete_if_sent_to_usa' );
    

    Your function has minor errors bks_mark_processing_order_complete_if_sent_to_usa()

    function bks_mark_processing_order_complete_if_sent_to_usa(){
        $args = array(
            'status' => array( 'wc-processing'),
            'limit'  => -1,
            'date_created' => '>' . ( time() - 864000 ), // your mistake 1
            'status_us' => 'Sent to USA', // your mistake 2
        );
    
    
        $orders = wc_get_orders( $args );
    
        foreach ($orders as $order){
            $order->update_status( 'completed' );
            $order->save(); // your mistake 3
        }
    };
    

    Mistake Explanations

    1. While your attempt was in right direction but 'date_created' => '<' . ( time() - 10 * DAY_IN_SECONDS ), you had to use > instead of < also you didn't acutally set DAY_IN_SECONDS You had to replace it with 86400. So the correct value would be '>' . ( time() - 864000 ). For 10 days 10 * 86400 = 864000. You can read about this explanation here in the WooCommerce documentation.

    2. Here I have created new custom variable for you which is set using woocommerce_order_data_store_cpt_get_orders_query and then queried. Code that needs to be added.

    function handle_custom_query_var( $query, $query_vars ) {
        if ( ! empty( $query_vars['status_us'] ) ) {
            $query['meta_query'][] = array(
                'key' => 'status_us',
                'value' => esc_attr( $query_vars['status_us'] ),
            );
        }
    
        return $query;
    }
    
    add_filter( 'woocommerce_order_data_store_cpt_get_orders_query', 'handle_custom_query_var', 10, 2 );
    
    1. You updated the status but you forgot to save it. $order->save();

    So to summarise you have to add the following code in your functions.php

    add_action( 'wp_loaded','start_custom_code' );
    add_action( 'bks_mark_processing_order_complete_if_sent_to_usa', 'bks_mark_processing_order_complete_if_sent_to_usa' );
    
    
    function start_custom_code() {
        if ( ! wp_next_scheduled( 'bks_mark_processing_order_complete_if_sent_to_usa' ) ) {
            wp_schedule_event( time(), 'daily', 'bks_mark_processing_order_complete_if_sent_to_usa' );
        }
    }
    
    function bks_mark_processing_order_complete_if_sent_to_usa(){
        $args = array(
            'status' => array( 'wc-processing'),
            'limit'  => -1,
            'date_created' => '>' . ( time() - 864000 ),
            'status_us' => 'Sent to USA',
        );
    
    
        $orders = wc_get_orders( $args );
    
        foreach ($orders as $order){
            $order->update_status( 'completed' );
            $order->save();
        }
    };
    
    function handle_custom_query_var( $query, $query_vars ) {
        if ( ! empty( $query_vars['status_us'] ) ) {
            $query['meta_query'][] = array(
                'key' => 'status_us',
                'value' => esc_attr( $query_vars['status_us'] ),
            );
        }
    
        return $query;
    }
    
    add_filter( 'woocommerce_order_data_store_cpt_get_orders_query', 'handle_custom_query_var', 10, 2 );
    

    The above code is TESTED and WORKS.

    Proof: enter image description here

    Install WP CRON plugin to check your cron. See above screenshot. You can test by hitting Run Now.

    Caveat :
    WP Cron runs, when somebody visits your website. Thus if nobody visits, ?>the cron never runs.

    Read this : https://wordpress.stackexchange.com/a/179774/204925