WooCommerce : Update order automatically based on meta key

Setup cron job to update WooCommerce order status on the basis of status, order date and some custom order meta key.

WooCommerce : Update order automatically based on meta key

Its a common request of woocommerce store owners to be able to change the state of order automatically when the order meta gets updated.

We will see how can be use WP Cron and wc_get_query to update order status autmatically.

1. Setting up the CRON Job.

/*
 * Trigger the code when everything is loaded.
 * */
add_action( 'init', 'bks_setup_cron_task' );

/*
 * Set a cron job for daily Midnight.
 * */
function bks_setup_cron_task() {
    if ( ! wp_next_scheduled( 'bks_update_order_status' ) ) {
        wp_schedule_event( time() , 'daily', 'bks_update_order_status' );
    }
}

// Plug the cron job with function 'bks_mark_order_complete_if_delivered'
add_action( 'bks_update_order_status', 'bks_mark_order_complete_if_delivered' );

There are multiple things going on here. Let's take a look at them one by one.

We are using add_action function with init hook which fires after WordPress has finished loading but before any headers are sent. We have passed a funtion in bks_setup_cron_task which would run when this hook is executed.

if ( ! wp_next_scheduled( 'bks_update_order_status' ) ) { ... }

Inside this function we are checking if a cron job named bks_update_order_status is scheduled or not using wp_next_scheduled function.

wp_schedule_event( time() , 'daily', 'bks_update_order_status' );

And then we use wp_schedule_event function to set when it should run next.

The functions accepts 5 parameter but we are using only the 3 which are required ones.

  • $timestamp (int) - Unix timestamp (UTC) for when to next run the event.
  • $recurrence (string) - This determines how often the event should subsequently recur. We have set it to daily. Default values you can set here are ‘hourly’, ‘twicedaily’, ‘daily’, and ‘weekly’.
  • $hook (string) Action hook to execute when the event is run. We have set it to a function called bks_mark_order_complete_if_delivered.
add_action( 'bks_update_order_status', 'bks_mark_order_complete_if_delivered' );

And finally using the cron hook bks_update_order_status to execute a function

You can see in the screenshot below that we have successfully registered a cron job which would execute bks_mark_order_complete_if_delivered() function.

image.png

I have used WP Crontrol plugin to monitor my cron job.

2. Writing the logic to actually update the order status

function bks_mark_order_complete_if_delivered(){
    $args = array(
        'status' => array( 'wc-processing'),
        'limit'  => -1,
        'date_created' => '>' . ( time() - 864000 ),
        'delivery_status' => 'delivered'
    );


    $orders = wc_get_orders( $args );

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

Here we are using wc_get_orders function where we pass 4 parameters.

  1. status : array( 'wc-processing') - we only want order which has the status of wc-processing
  2. limit : -1 - No limit, we want all the orders without any limit
  3. date_created : '>' . ( time() - 864000 ) - orders whose date is greater than time() [ current time ] - 864000 seconds ( = 10 days ). ie. in last 10 days.
  4. delivery_satus ; delivered : This is a custom paramater created which checks if the value of deliver_status order meta is delivery or not and only those orders are returned which satisfy the condition.

You can add Custom parameter like this.

function bks_handle_custom_query_var( $query, $query_vars ) {
    if ( ! empty( $query_vars['delivery_status'] ) ) {
        $query['meta_query'][] = array(
            'key' => 'delivery_status',
            'value' => esc_attr( $query_vars['delivery_status'] ),
        );
    }

    return $query;
}

add_filter( 'woocommerce_order_data_store_cpt_get_orders_query', 'bks_handle_custom_query_var', 10, 2 );

Once the args is done we get

  1. all the orders
  2. with processing status
  3. in last 10 days
  4. having delivery_status meta as delivered.

We the loop through the order, update the status and save.

$order->update_status( 'completed' );
$order->save();

Summary

So you have to finally add this combined code in your functions.php of your child theme.

/*
 * Trigger the code when everything is loaded.
 * */
add_action( 'init', 'bks_setup_cron_task' );

/*
 * Set a cron job for daily Midnight.
 * */
function bks_setup_cron_task() {
    if ( ! wp_next_scheduled( 'bks_update_order_status' ) ) {
        wp_schedule_event( time() , 'daily', 'bks_update_order_status' );
    }
}

// Plug the cron job with function 'bks_mark_order_complete_if_delivered'
add_action( 'bks_update_order_status', 'bks_mark_order_complete_if_delivered' );

function bks_mark_order_complete_if_delivered(){
    $args = array(
        'status' => array( 'wc-processing'),
        'limit'  => -1,
        'date_created' => '>' . ( time() - 864000 ),
        'delivery_status' => 'delivered'
    );


    $orders = wc_get_orders( $args );

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

function bks_handle_custom_query_var( $query, $query_vars ) {
    if ( ! empty( $query_vars['delivery_status'] ) ) {
        $query['meta_query'][] = array(
            'key' => 'delivery_status',
            'value' => esc_attr( $query_vars['delivery_status'] ),
        );
    }

    return $query;
}

add_filter( 'woocommerce_order_data_store_cpt_get_orders_query', 'bks_handle_custom_query_var', 10, 2 );

This comes from the two different question which I answered on stackoverflow :

Did you find this article valuable?

Support Bhanu Singh by becoming a sponsor. Any amount is appreciated!