# 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](https://developer.wordpress.org/plugins/cron/) and  [wc_get_query](https://github.com/woocommerce/woocommerce/wiki/wc_get_orders-and-WC_Order_Query)  to update order status autmatically.

#### 1. Setting up the CRON Job.

```php
/*
 * 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`](https://developer.wordpress.org/reference/functions/add_action/) function with  [`init`](https://developer.wordpress.org/reference/hooks/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`](https://developer.wordpress.org/reference/functions/wp_next_scheduled/)  function.


```
wp_schedule_event( time() , 'daily', 'bks_update_order_status' );
```
And then we use  [`wp_schedule_event`](https://developer.wordpress.org/reference/functions/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](https://cdn.hashnode.com/res/hashnode/image/upload/v1622926815454/d1hB74GEn.png)
> I have used  [WP Crontrol plugin](https://wordpress.org/plugins/wp-crontrol/) 
 to monitor my cron job.

#### 2. Writing the logic to actually update the order status

```php
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`](https://github.com/woocommerce/woocommerce/wiki/wc_get_orders-and-WC_Order_Query)  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](https://github.com/woocommerce/woocommerce/wiki/wc_get_orders-and-WC_Order_Query#adding-custom-parameter-support) 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.

```php
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 
1. with processing status
1. in last 10 days
1. having `delivery_status` meta as `delivered`.

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

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

#### Summary

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

```php
/*
 * 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 :

%[https://stackoverflow.com/questions/67838546/update-order-status-from-custom-statuses-to-completed-in-woocommerce-everyday-at/67844705#67844705]

%[https://stackoverflow.com/questions/67689647/woocommerce-change-order-status-based-on-custom-meta-value/67755204#67755204]
