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.
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 calledbks_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.
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.
- status :
array( 'wc-processing')
- we only want order which has the status of wc-processing - limit :
-1
- No limit, we want all the orders without any limit - date_created :
'>' . ( time() - 864000 )
- orders whose date is greater than time() [ current time ] - 864000 seconds ( = 10 days ). ie. in last 10 days. - delivery_satus ;
delivered
: This is a custom paramater created which checks if the value ofdeliver_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
- all the orders
- with processing status
- in last 10 days
- having
delivery_status
meta asdelivered
.
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 );