2013-08-09 16:11:15 +00:00
< ? php
/**
2015-11-03 13:53:50 +00:00
* WooCommerce Order Functions
2013-08-09 16:11:15 +00:00
*
* Functions for order specific things .
*
2020-08-05 16:36:24 +00:00
* @ package WooCommerce\Functions
2018-03-08 18:47:54 +00:00
* @ version 3.4 . 0
2013-08-09 16:11:15 +00:00
*/
2018-03-08 18:47:54 +00:00
defined ( 'ABSPATH' ) || exit ;
2013-08-09 16:11:15 +00:00
2020-06-24 13:23:52 +00:00
use Automattic\WooCommerce\Models\CacheHydration ;
2016-03-09 13:25:36 +00:00
/**
2017-05-12 18:45:01 +00:00
* Standard way of retrieving orders based on certain parameters .
2016-03-09 13:25:36 +00:00
*
* This function should be used for order retrieval so that when we move to
* custom tables , functions still work .
*
2017-06-01 18:58:43 +00:00
* Args and usage : https :// github . com / woocommerce / woocommerce / wiki / wc_get_orders - and - WC_Order_Query
2016-03-09 13:25:36 +00:00
*
* @ since 2.6 . 0
2018-03-08 18:47:54 +00:00
* @ param array $args Array of args ( above ) .
2018-04-20 12:01:53 +00:00
* @ return WC_Order [] | stdClass Number of pages and an array of order objects if
2016-03-09 16:11:05 +00:00
* paginate is true , or just an array of values .
2016-03-09 13:25:36 +00:00
*/
function wc_get_orders ( $args ) {
2016-03-14 16:08:42 +00:00
$map_legacy = array (
'numberposts' => 'limit' ,
'post_type' => 'type' ,
'post_status' => 'status' ,
'post_parent' => 'parent' ,
'author' => 'customer' ,
2017-05-12 18:45:01 +00:00
'email' => 'billing_email' ,
2016-03-14 16:08:42 +00:00
'posts_per_page' => 'limit' ,
'paged' => 'page' ,
);
foreach ( $map_legacy as $from => $to ) {
if ( isset ( $args [ $from ] ) ) {
$args [ $to ] = $args [ $from ];
}
}
2016-03-09 13:25:36 +00:00
2017-05-12 18:45:01 +00:00
// Map legacy date args to modern date args.
2017-05-12 19:59:54 +00:00
$date_before = false ;
2017-05-12 22:31:34 +00:00
$date_after = false ;
2017-05-12 19:59:54 +00:00
if ( ! empty ( $args [ 'date_before' ] ) ) {
2017-05-12 22:31:34 +00:00
$datetime = wc_string_to_datetime ( $args [ 'date_before' ] );
2017-05-12 22:25:15 +00:00
$date_before = strpos ( $args [ 'date_before' ], ':' ) ? $datetime -> getOffsetTimestamp () : $datetime -> date ( 'Y-m-d' );
2017-05-12 19:59:54 +00:00
}
2017-05-13 19:22:22 +00:00
if ( ! empty ( $args [ 'date_after' ] ) ) {
2017-05-12 22:31:34 +00:00
$datetime = wc_string_to_datetime ( $args [ 'date_after' ] );
2017-05-12 22:25:15 +00:00
$date_after = strpos ( $args [ 'date_after' ], ':' ) ? $datetime -> getOffsetTimestamp () : $datetime -> date ( 'Y-m-d' );
2017-05-12 19:59:54 +00:00
}
2017-05-12 18:45:01 +00:00
if ( $date_before && $date_after ) {
2017-07-01 00:30:16 +00:00
$args [ 'date_created' ] = $date_after . '...' . $date_before ;
2017-05-12 18:45:01 +00:00
} elseif ( $date_before ) {
$args [ 'date_created' ] = '<' . $date_before ;
} elseif ( $date_after ) {
$args [ 'date_created' ] = '>' . $date_after ;
}
$query = new WC_Order_Query ( $args );
return $query -> get_orders ();
2016-03-09 13:25:36 +00:00
}
2016-03-09 14:50:34 +00:00
/**
2016-11-18 14:07:21 +00:00
* Main function for returning orders , uses the WC_Order_Factory class .
*
* @ since 2.2
2017-05-15 11:50:52 +00:00
*
2020-06-24 13:23:52 +00:00
* @ param mixed $the_order Post object or post ID of the order .
* @ param CacheHydration $cache_hydration Optional , cache_hydration to initialize cache data from if available .
2017-05-15 11:50:52 +00:00
*
2018-10-09 18:58:15 +00:00
* @ return bool | WC_Order | WC_Order_Refund
2016-03-09 14:50:34 +00:00
*/
2020-06-24 13:23:52 +00:00
function wc_get_order ( $the_order = false , $cache_hydration = null ) {
2017-03-28 11:37:17 +00:00
if ( ! did_action ( 'woocommerce_after_register_post_type' ) ) {
2017-06-06 12:10:22 +00:00
wc_doing_it_wrong ( __FUNCTION__ , 'wc_get_order should not be called before post types are registered (woocommerce_after_register_post_type action)' , '2.5' );
2016-11-18 14:07:21 +00:00
return false ;
2016-03-09 14:50:34 +00:00
}
2020-06-24 13:23:52 +00:00
if ( is_a ( $cache_hydration , CacheHydration :: class ) ) {
return WC () -> order_factory -> get_order_from_hydration ( $the_order , $cache_hydration );
}
2016-11-18 14:07:21 +00:00
return WC () -> order_factory -> get_order ( $the_order );
2016-03-09 14:50:34 +00:00
}
2014-05-30 15:03:11 +00:00
/**
2015-11-03 13:31:20 +00:00
* Get all order statuses .
2014-05-30 15:03:11 +00:00
*
* @ since 2.2
2017-04-04 10:52:54 +00:00
* @ used - by WC_Order :: set_status
2014-05-30 15:03:11 +00:00
* @ return array
*/
function wc_get_order_statuses () {
$order_statuses = array (
2016-10-12 10:16:30 +00:00
'wc-pending' => _x ( 'Pending payment' , 'Order status' , 'woocommerce' ),
2014-06-03 10:04:56 +00:00
'wc-processing' => _x ( 'Processing' , 'Order status' , 'woocommerce' ),
2016-10-12 10:16:30 +00:00
'wc-on-hold' => _x ( 'On hold' , 'Order status' , 'woocommerce' ),
2014-06-03 10:04:56 +00:00
'wc-completed' => _x ( 'Completed' , 'Order status' , 'woocommerce' ),
'wc-cancelled' => _x ( 'Cancelled' , 'Order status' , 'woocommerce' ),
'wc-refunded' => _x ( 'Refunded' , 'Order status' , 'woocommerce' ),
'wc-failed' => _x ( 'Failed' , 'Order status' , 'woocommerce' ),
2014-05-30 15:03:11 +00:00
);
return apply_filters ( 'wc_order_statuses' , $order_statuses );
}
2014-11-27 15:37:42 +00:00
/**
* See if a string is an order status .
2018-03-08 18:47:54 +00:00
*
* @ param string $maybe_status Status , including any wc - prefix .
2014-11-27 15:37:42 +00:00
* @ return bool
*/
function wc_is_order_status ( $maybe_status ) {
$order_statuses = wc_get_order_statuses ();
return isset ( $order_statuses [ $maybe_status ] );
}
2016-11-03 11:27:03 +00:00
/**
* Get list of statuses which are consider 'paid' .
2018-03-08 18:47:54 +00:00
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2016-11-03 11:27:03 +00:00
* @ return array
*/
function wc_get_is_paid_statuses () {
return apply_filters ( 'woocommerce_order_is_paid_statuses' , array ( 'processing' , 'completed' ) );
}
2019-01-10 10:43:14 +00:00
/**
* Get list of statuses which are consider 'pending payment' .
*
2019-01-22 13:12:26 +00:00
* @ since 3.6 . 0
2019-01-10 10:43:14 +00:00
* @ return array
*/
function wc_get_is_pending_statuses () {
return apply_filters ( 'woocommerce_order_is_pending_statuses' , array ( 'pending' ) );
}
2014-05-30 16:43:21 +00:00
/**
2015-11-03 13:31:20 +00:00
* Get the nice name for an order status .
2014-09-12 13:01:49 +00:00
*
* @ since 2.2
2018-03-08 18:47:54 +00:00
* @ param string $status Status .
2014-05-30 16:43:21 +00:00
* @ return string
*/
function wc_get_order_status_name ( $status ) {
$statuses = wc_get_order_statuses ();
2014-09-12 13:01:49 +00:00
$status = 'wc-' === substr ( $status , 0 , 3 ) ? substr ( $status , 3 ) : $status ;
$status = isset ( $statuses [ 'wc-' . $status ] ) ? $statuses [ 'wc-' . $status ] : $status ;
2014-10-29 11:15:00 +00:00
return $status ;
2014-05-30 16:43:21 +00:00
}
2019-01-21 16:02:28 +00:00
/**
2020-05-20 20:32:22 +00:00
* Generate an order key with prefix .
2019-01-21 16:02:28 +00:00
*
* @ since 3.5 . 4
2020-05-20 20:32:22 +00:00
* @ param string $key Order key without a prefix . By default generates a 13 digit secret .
2019-01-21 16:02:28 +00:00
* @ return string The order key .
*/
2020-05-20 20:32:22 +00:00
function wc_generate_order_key ( $key = '' ) {
if ( '' === $key ) {
$key = wp_generate_password ( 13 , false );
}
return 'wc_' . apply_filters ( 'woocommerce_generate_order_key' , 'order_' . $key );
2019-01-21 16:02:28 +00:00
}
2013-08-09 16:11:15 +00:00
/**
* Finds an Order ID based on an order key .
*
2018-03-08 18:47:54 +00:00
* @ param string $order_key An order key has generated by .
* @ return int The ID of an order , or 0 if the order could not be found .
2013-08-09 16:11:15 +00:00
*/
2013-11-25 13:54:52 +00:00
function wc_get_order_id_by_order_key ( $order_key ) {
2016-11-18 14:07:21 +00:00
$data_store = WC_Data_Store :: load ( 'order' );
2016-11-21 14:30:56 +00:00
return $data_store -> get_order_id_by_order_key ( $order_key );
2013-08-09 16:11:15 +00:00
}
2014-07-11 11:43:42 +00:00
/**
2015-11-03 13:31:20 +00:00
* Get all registered order types .
2014-07-11 11:43:42 +00:00
*
* @ since 2.2
2018-03-08 18:47:54 +00:00
* @ param string $for Optionally define what you are getting order types for so
* only relevant types are returned .
* e . g . for 'order-meta-boxes' , 'order-count' .
2014-07-11 11:43:42 +00:00
* @ return array
*/
function wc_get_order_types ( $for = '' ) {
global $wc_order_types ;
if ( ! is_array ( $wc_order_types ) ) {
$wc_order_types = array ();
}
$order_types = array ();
switch ( $for ) {
2018-03-08 18:47:54 +00:00
case 'order-count' :
2014-07-11 11:43:42 +00:00
foreach ( $wc_order_types as $type => $args ) {
if ( ! $args [ 'exclude_from_order_count' ] ) {
$order_types [] = $type ;
}
}
2018-03-08 18:47:54 +00:00
break ;
case 'order-meta-boxes' :
2014-07-11 11:43:42 +00:00
foreach ( $wc_order_types as $type => $args ) {
if ( $args [ 'add_order_meta_boxes' ] ) {
$order_types [] = $type ;
}
}
2018-03-08 18:47:54 +00:00
break ;
case 'view-orders' :
2014-07-11 11:43:42 +00:00
foreach ( $wc_order_types as $type => $args ) {
if ( ! $args [ 'exclude_from_order_views' ] ) {
$order_types [] = $type ;
}
}
2018-03-08 18:47:54 +00:00
break ;
case 'reports' :
2014-07-11 11:43:42 +00:00
foreach ( $wc_order_types as $type => $args ) {
if ( ! $args [ 'exclude_from_order_reports' ] ) {
$order_types [] = $type ;
}
}
2018-03-08 18:47:54 +00:00
break ;
case 'sales-reports' :
2014-10-06 12:39:49 +00:00
foreach ( $wc_order_types as $type => $args ) {
if ( ! $args [ 'exclude_from_order_sales_reports' ] ) {
$order_types [] = $type ;
}
}
2018-03-08 18:47:54 +00:00
break ;
case 'order-webhooks' :
2015-05-12 04:01:23 +00:00
foreach ( $wc_order_types as $type => $args ) {
if ( ! $args [ 'exclude_from_order_webhooks' ] ) {
$order_types [] = $type ;
}
}
2018-03-08 18:47:54 +00:00
break ;
default :
2014-07-11 11:43:42 +00:00
$order_types = array_keys ( $wc_order_types );
2018-03-08 18:47:54 +00:00
break ;
2014-07-11 11:43:42 +00:00
}
return apply_filters ( 'wc_order_types' , $order_types , $for );
}
/**
2015-11-03 13:31:20 +00:00
* Get an order type by post type name .
2018-03-08 18:47:54 +00:00
*
* @ param string $type Post type name .
* @ return bool | array Details about the order type .
2014-07-11 11:43:42 +00:00
*/
function wc_get_order_type ( $type ) {
global $wc_order_types ;
if ( isset ( $wc_order_types [ $type ] ) ) {
return $wc_order_types [ $type ];
}
2018-05-14 18:33:22 +00:00
return false ;
2014-07-11 11:43:42 +00:00
}
/**
2014-07-22 13:30:42 +00:00
* Register order type . Do not use before init .
2014-07-11 11:43:42 +00:00
*
2015-11-03 13:31:20 +00:00
* Wrapper for register post type , as well as a method of telling WC which .
2014-07-11 11:43:42 +00:00
* post types are types of orders , and having them treated as such .
*
* $args are passed to register_post_type , but there are a few specific to this function :
2016-09-14 19:00:14 +00:00
* - exclude_from_orders_screen ( bool ) Whether or not this order type also get shown in the main .
* orders screen .
* - add_order_meta_boxes ( bool ) Whether or not the order type gets shop_order meta boxes .
* - exclude_from_order_count ( bool ) Whether or not this order type is excluded from counts .
* - exclude_from_order_views ( bool ) Whether or not this order type is visible by customers when .
* viewing orders e . g . on the my account page .
* - exclude_from_order_reports ( bool ) Whether or not to exclude this type from core reports .
* - exclude_from_order_sales_reports ( bool ) Whether or not to exclude this type from core sales reports .
2014-07-11 11:43:42 +00:00
*
* @ since 2.2
* @ see register_post_type for $args used in that function
2018-03-08 18:47:54 +00:00
* @ param string $type Post type . ( max . 20 characters , can not contain capital letters or spaces ) .
* @ param array $args An array of arguments .
2014-07-11 11:43:42 +00:00
* @ return bool Success or failure
*/
function wc_register_order_type ( $type , $args = array () ) {
if ( post_type_exists ( $type ) ) {
return false ;
}
global $wc_order_types ;
if ( ! is_array ( $wc_order_types ) ) {
$wc_order_types = array ();
}
2018-03-08 18:47:54 +00:00
// Register as a post type.
2014-07-11 11:43:42 +00:00
if ( is_wp_error ( register_post_type ( $type , $args ) ) ) {
return false ;
}
2018-03-08 18:47:54 +00:00
// Register for WC usage.
2014-07-11 11:43:42 +00:00
$order_type_args = array (
2014-10-06 12:39:49 +00:00
'exclude_from_orders_screen' => false ,
'add_order_meta_boxes' => true ,
'exclude_from_order_count' => false ,
'exclude_from_order_views' => false ,
2015-05-12 04:01:23 +00:00
'exclude_from_order_webhooks' => false ,
2014-10-06 12:39:49 +00:00
'exclude_from_order_reports' => false ,
'exclude_from_order_sales_reports' => false ,
2016-08-27 01:46:45 +00:00
'class_name' => 'WC_Order' ,
2014-07-11 11:43:42 +00:00
);
$args = array_intersect_key ( $args , $order_type_args );
$args = wp_parse_args ( $args , $order_type_args );
$wc_order_types [ $type ] = $args ;
return true ;
}
2013-08-09 16:11:15 +00:00
/**
2016-11-18 14:07:21 +00:00
* Return the count of processing orders .
2013-08-09 16:11:15 +00:00
*
2016-11-18 14:07:21 +00:00
* @ return int
2013-08-09 16:11:15 +00:00
*/
2016-11-18 14:07:21 +00:00
function wc_processing_order_count () {
return wc_orders_count ( 'processing' );
}
2013-08-09 16:11:15 +00:00
2016-11-18 14:07:21 +00:00
/**
* Return the orders count of a specific order status .
*
2018-03-08 18:47:54 +00:00
* @ param string $status Status .
2016-11-18 14:07:21 +00:00
* @ return int
*/
function wc_orders_count ( $status ) {
$count = 0 ;
$status = 'wc-' . $status ;
$order_statuses = array_keys ( wc_get_order_statuses () );
2013-08-09 16:11:15 +00:00
2018-03-08 18:47:54 +00:00
if ( ! in_array ( $status , $order_statuses , true ) ) {
2016-11-18 14:07:21 +00:00
return 0 ;
}
2013-08-09 16:11:15 +00:00
2018-03-08 18:47:54 +00:00
$cache_key = WC_Cache_Helper :: get_cache_prefix ( 'orders' ) . $status ;
2016-11-18 14:07:21 +00:00
$cached_count = wp_cache_get ( $cache_key , 'counts' );
2013-08-09 16:11:15 +00:00
2016-11-18 14:07:21 +00:00
if ( false !== $cached_count ) {
return $cached_count ;
2013-12-17 05:07:19 +00:00
}
2013-08-09 16:11:15 +00:00
2016-11-18 14:07:21 +00:00
foreach ( wc_get_order_types ( 'order-count' ) as $type ) {
$data_store = WC_Data_Store :: load ( 'shop_order' === $type ? 'order' : $type );
if ( $data_store ) {
$count += $data_store -> get_order_count ( $status );
}
2013-09-10 11:26:31 +00:00
}
2013-08-09 16:11:15 +00:00
2016-11-18 14:07:21 +00:00
wp_cache_set ( $cache_key , $count , 'counts' );
2013-09-10 11:26:31 +00:00
2016-11-18 14:07:21 +00:00
return $count ;
}
2013-08-09 16:11:15 +00:00
2016-11-18 14:07:21 +00:00
/**
* Grant downloadable product access to the file identified by $download_id .
*
2018-03-08 18:47:54 +00:00
* @ param string $download_id File identifier .
* @ param int | WC_Product $product Product instance or ID .
* @ param WC_Order $order Order data .
* @ param int $qty Quantity purchased .
* @ return int | bool insert id or false on failure .
2016-11-18 14:07:21 +00:00
*/
function wc_downloadable_file_permission ( $download_id , $product , $order , $qty = 1 ) {
if ( is_numeric ( $product ) ) {
$product = wc_get_product ( $product );
}
2016-11-18 17:13:02 +00:00
$download = new WC_Customer_Download ();
$download -> set_download_id ( $download_id );
$download -> set_product_id ( $product -> get_id () );
$download -> set_user_id ( $order -> get_customer_id () );
$download -> set_order_id ( $order -> get_id () );
2016-11-18 19:29:37 +00:00
$download -> set_user_email ( $order -> get_billing_email () );
2016-11-18 17:13:02 +00:00
$download -> set_order_key ( $order -> get_order_key () );
$download -> set_downloads_remaining ( 0 > $product -> get_download_limit () ? '' : $product -> get_download_limit () * $qty );
2019-12-20 17:23:05 +00:00
$download -> set_access_granted ( time () );
2016-11-18 17:13:02 +00:00
$download -> set_download_count ( 0 );
$expiry = $product -> get_download_expiry ();
if ( $expiry > 0 ) {
2017-03-10 16:35:47 +00:00
$from_date = $order -> get_date_completed () ? $order -> get_date_completed () -> format ( 'Y-m-d' ) : current_time ( 'mysql' , true );
$download -> set_access_expires ( strtotime ( $from_date . ' + ' . $expiry . ' DAY' ) );
2016-11-18 17:13:02 +00:00
}
2018-03-29 16:58:40 +00:00
$download = apply_filters ( 'woocommerce_downloadable_file_permission' , $download , $product , $order , $qty );
2016-11-18 17:13:02 +00:00
return $download -> save ();
2013-08-09 16:11:15 +00:00
}
2013-12-16 23:27:57 +00:00
2013-08-09 16:11:15 +00:00
/**
2017-05-15 11:50:52 +00:00
* Order Status completed - give downloadable product access to customer .
2013-08-09 16:11:15 +00:00
*
2018-03-08 18:47:54 +00:00
* @ param int $order_id Order ID .
* @ param bool $force Force downloadable permissions .
2013-08-09 16:11:15 +00:00
*/
2016-11-18 17:13:02 +00:00
function wc_downloadable_product_permissions ( $order_id , $force = false ) {
2014-08-15 12:29:21 +00:00
$order = wc_get_order ( $order_id );
2013-08-09 16:11:15 +00:00
2016-11-18 17:13:02 +00:00
if ( ! $order || ( $order -> get_data_store () -> get_download_permissions_granted ( $order ) && ! $force ) ) {
2016-11-18 14:07:21 +00:00
return ;
}
if ( $order -> has_status ( 'processing' ) && 'no' === get_option ( 'woocommerce_downloads_grant_access_after_payment' ) ) {
2014-02-17 10:49:55 +00:00
return ;
2014-02-17 10:50:36 +00:00
}
2014-02-17 10:49:55 +00:00
2018-03-08 18:47:54 +00:00
if ( count ( $order -> get_items () ) > 0 ) {
2013-09-20 16:01:09 +00:00
foreach ( $order -> get_items () as $item ) {
2016-11-18 14:07:21 +00:00
$product = $item -> get_product ();
2013-08-09 16:11:15 +00:00
2016-11-18 14:07:21 +00:00
if ( $product && $product -> exists () && $product -> is_downloadable () ) {
$downloads = $product -> get_downloads ();
2013-08-09 16:11:15 +00:00
2013-12-16 23:27:57 +00:00
foreach ( array_keys ( $downloads ) as $download_id ) {
2016-11-18 14:07:21 +00:00
wc_downloadable_file_permission ( $download_id , $product , $order , $item -> get_quantity () );
2013-12-16 23:27:57 +00:00
}
2013-09-20 16:01:09 +00:00
}
}
}
2013-08-09 16:11:15 +00:00
2016-11-18 14:07:21 +00:00
$order -> get_data_store () -> set_download_permissions_granted ( $order , true );
2013-09-10 11:26:31 +00:00
do_action ( 'woocommerce_grant_product_download_permissions' , $order_id );
2013-08-09 16:11:15 +00:00
}
2014-02-17 10:49:55 +00:00
add_action ( 'woocommerce_order_status_completed' , 'wc_downloadable_product_permissions' );
add_action ( 'woocommerce_order_status_processing' , 'wc_downloadable_product_permissions' );
2014-02-26 15:43:19 +00:00
/**
* Clear all transients cache for order data .
*
2018-03-08 18:47:54 +00:00
* @ param int | WC_Order $order Order instance or ID .
2014-02-26 15:43:19 +00:00
*/
2016-11-18 11:14:09 +00:00
function wc_delete_shop_order_transients ( $order = 0 ) {
if ( is_numeric ( $order ) ) {
$order = wc_get_order ( $order );
}
$reports = WC_Admin_Reports :: get_reports ();
$transients_to_clear = array (
2018-03-08 18:47:54 +00:00
'wc_admin_report' ,
2016-11-18 11:14:09 +00:00
);
2014-03-20 11:10:25 +00:00
foreach ( $reports as $report_group ) {
foreach ( $report_group [ 'reports' ] as $report_key => $report ) {
$transients_to_clear [] = 'wc_report_' . $report_key ;
2014-03-18 10:48:18 +00:00
}
}
2016-08-27 04:23:02 +00:00
foreach ( $transients_to_clear as $transient ) {
2014-02-26 15:43:19 +00:00
delete_transient ( $transient );
}
2018-03-08 18:47:54 +00:00
// Clear money spent for user associated with order.
2016-11-18 11:14:09 +00:00
if ( is_a ( $order , 'WC_Order' ) ) {
$order_id = $order -> get_id ();
delete_user_meta ( $order -> get_customer_id (), '_money_spent' );
delete_user_meta ( $order -> get_customer_id (), '_order_count' );
} else {
$order_id = 0 ;
2016-02-08 12:26:46 +00:00
}
2018-03-08 18:47:54 +00:00
// Increments the transient version to invalidate cache.
2015-03-27 13:17:54 +00:00
WC_Cache_Helper :: get_transient_version ( 'orders' , true );
2018-03-08 18:47:54 +00:00
// Do the same for regular cache.
2019-11-28 13:03:57 +00:00
WC_Cache_Helper :: invalidate_cache_group ( 'orders' );
2015-11-05 15:21:28 +00:00
2016-11-18 11:14:09 +00:00
do_action ( 'woocommerce_delete_shop_order_transients' , $order_id );
2014-02-26 15:43:19 +00:00
}
2014-06-17 20:39:02 +00:00
/**
2015-11-03 13:31:20 +00:00
* See if we only ship to billing addresses .
2018-03-08 18:47:54 +00:00
*
2014-06-17 20:39:02 +00:00
* @ return bool
*/
function wc_ship_to_billing_address_only () {
return 'billing_only' === get_option ( 'woocommerce_ship_to_destination' );
}
2014-07-08 14:32:47 +00:00
/**
2015-11-03 13:31:20 +00:00
* Create a new order refund programmatically .
2014-07-08 14:32:47 +00:00
*
2015-02-11 14:14:42 +00:00
* Returns a new refund object on success which can then be used to add additional data .
2014-07-08 14:32:47 +00:00
*
* @ since 2.2
2018-03-08 18:47:54 +00:00
* @ throws Exception Throws exceptions when fail to create , but returns WP_Error instead .
* @ param array $args New refund arguments .
2015-02-03 15:08:36 +00:00
* @ return WC_Order_Refund | WP_Error
2014-07-08 14:32:47 +00:00
*/
function wc_create_refund ( $args = array () ) {
$default_args = array (
2017-02-08 16:19:47 +00:00
'amount' => 0 ,
'reason' => null ,
'order_id' => 0 ,
'refund_id' => 0 ,
'line_items' => array (),
'refund_payment' => false ,
'restock_items' => false ,
2014-07-08 14:32:47 +00:00
);
2016-08-24 14:26:35 +00:00
try {
2018-03-08 18:47:54 +00:00
$args = wp_parse_args ( $args , $default_args );
$order = wc_get_order ( $args [ 'order_id' ] );
2016-08-22 10:00:31 +00:00
2018-03-08 18:47:54 +00:00
if ( ! $order ) {
2016-08-24 15:02:19 +00:00
throw new Exception ( __ ( 'Invalid order ID.' , 'woocommerce' ) );
2016-08-24 14:26:35 +00:00
}
2014-07-08 14:32:47 +00:00
2017-02-08 16:19:47 +00:00
$remaining_refund_amount = $order -> get_remaining_refund_amount ();
$remaining_refund_items = $order -> get_remaining_refund_items ();
$refund_item_count = 0 ;
$refund = new WC_Order_Refund ( $args [ 'refund_id' ] );
if ( 0 > $args [ 'amount' ] || $args [ 'amount' ] > $remaining_refund_amount ) {
throw new Exception ( __ ( 'Invalid refund amount.' , 'woocommerce' ) );
2016-08-24 14:26:35 +00:00
}
2017-02-08 16:19:47 +00:00
2017-01-10 14:14:03 +00:00
$refund -> set_currency ( $order -> get_currency () );
2016-08-24 14:26:35 +00:00
$refund -> set_amount ( $args [ 'amount' ] );
$refund -> set_parent_id ( absint ( $args [ 'order_id' ] ) );
$refund -> set_refunded_by ( get_current_user_id () ? get_current_user_id () : 1 );
2019-01-19 03:38:36 +00:00
$refund -> set_prices_include_tax ( $order -> get_prices_include_tax () );
2014-07-08 14:32:47 +00:00
2016-08-24 14:26:35 +00:00
if ( ! is_null ( $args [ 'reason' ] ) ) {
$refund -> set_reason ( $args [ 'reason' ] );
}
2014-07-08 14:32:47 +00:00
2018-03-08 18:47:54 +00:00
// Negative line items.
if ( count ( $args [ 'line_items' ] ) > 0 ) {
2016-08-24 14:26:35 +00:00
$items = $order -> get_items ( array ( 'line_item' , 'fee' , 'shipping' ) );
2016-08-22 10:00:31 +00:00
2016-08-24 14:26:35 +00:00
foreach ( $items as $item_id => $item ) {
2016-09-07 09:04:56 +00:00
if ( ! isset ( $args [ 'line_items' ][ $item_id ] ) ) {
2016-08-24 14:26:35 +00:00
continue ;
}
2016-08-22 10:00:31 +00:00
2016-11-17 16:53:13 +00:00
$qty = isset ( $args [ 'line_items' ][ $item_id ][ 'qty' ] ) ? $args [ 'line_items' ][ $item_id ][ 'qty' ] : 0 ;
2016-09-07 09:04:56 +00:00
$refund_total = $args [ 'line_items' ][ $item_id ][ 'refund_total' ];
$refund_tax = isset ( $args [ 'line_items' ][ $item_id ][ 'refund_tax' ] ) ? array_filter ( ( array ) $args [ 'line_items' ][ $item_id ][ 'refund_tax' ] ) : array ();
if ( empty ( $qty ) && empty ( $refund_total ) && empty ( $args [ 'line_items' ][ $item_id ][ 'refund_tax' ] ) ) {
continue ;
2016-08-24 14:26:35 +00:00
}
2014-10-06 12:39:49 +00:00
2016-08-24 14:26:35 +00:00
$class = get_class ( $item );
$refunded_item = new $class ( $item );
$refunded_item -> set_id ( 0 );
$refunded_item -> add_meta_data ( '_refunded_item_id' , $item_id , true );
2016-09-07 09:04:56 +00:00
$refunded_item -> set_total ( wc_format_refund_total ( $refund_total ) );
2018-03-08 18:47:54 +00:00
$refunded_item -> set_taxes (
array (
'total' => array_map ( 'wc_format_refund_total' , $refund_tax ),
'subtotal' => array_map ( 'wc_format_refund_total' , $refund_tax ),
)
);
2014-10-06 12:39:49 +00:00
2016-08-24 14:26:35 +00:00
if ( is_callable ( array ( $refunded_item , 'set_subtotal' ) ) ) {
2016-09-07 09:04:56 +00:00
$refunded_item -> set_subtotal ( wc_format_refund_total ( $refund_total ) );
}
if ( is_callable ( array ( $refunded_item , 'set_quantity' ) ) ) {
2016-11-23 15:10:18 +00:00
$refunded_item -> set_quantity ( $qty * - 1 );
2016-08-24 14:26:35 +00:00
}
2014-10-07 22:58:21 +00:00
2016-08-24 14:26:35 +00:00
$refund -> add_item ( $refunded_item );
2017-02-08 16:19:47 +00:00
$refund_item_count += $qty ;
2016-08-24 14:26:35 +00:00
}
2016-08-22 12:04:57 +00:00
}
2016-08-24 14:26:35 +00:00
$refund -> update_taxes ();
$refund -> calculate_totals ( false );
$refund -> set_total ( $args [ 'amount' ] * - 1 );
2017-01-10 14:14:03 +00:00
2017-05-17 08:46:56 +00:00
// this should remain after update_taxes(), as this will save the order, and write the current date to the db
2018-03-08 18:47:54 +00:00
// so we must wait until the order is persisted to set the date.
2017-05-17 08:46:56 +00:00
if ( isset ( $args [ 'date_created' ] ) ) {
$refund -> set_date_created ( $args [ 'date_created' ] );
}
2017-01-10 14:14:03 +00:00
/**
* Action hook to adjust refund before save .
2018-03-08 18:47:54 +00:00
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2017-01-10 14:14:03 +00:00
*/
do_action ( 'woocommerce_create_refund' , $refund , $args );
2017-02-08 16:19:47 +00:00
if ( $refund -> save () ) {
if ( $args [ 'refund_payment' ] ) {
$result = wc_refund_payment ( $order , $refund -> get_amount (), $refund -> get_reason () );
if ( is_wp_error ( $result ) ) {
$refund -> delete ();
return $result ;
}
2017-12-15 16:23:26 +00:00
$refund -> set_refunded_payment ( true );
$refund -> save ();
2017-02-08 16:19:47 +00:00
}
if ( $args [ 'restock_items' ] ) {
wc_restock_refunded_items ( $order , $args [ 'line_items' ] );
}
2018-03-08 18:47:54 +00:00
// Trigger notification emails.
2017-02-08 16:19:47 +00:00
if ( ( $remaining_refund_amount - $args [ 'amount' ] ) > 0 || ( $order -> has_free_item () && ( $remaining_refund_items - $refund_item_count ) > 0 ) ) {
do_action ( 'woocommerce_order_partially_refunded' , $order -> get_id (), $refund -> get_id () );
} else {
do_action ( 'woocommerce_order_fully_refunded' , $order -> get_id (), $refund -> get_id () );
2017-02-27 11:55:09 +00:00
$parent_status = apply_filters ( 'woocommerce_order_fully_refunded_status' , 'refunded' , $order -> get_id (), $refund -> get_id () );
if ( $parent_status ) {
$order -> update_status ( $parent_status );
}
2017-02-08 16:19:47 +00:00
}
}
2016-08-24 14:26:35 +00:00
2017-01-10 14:14:03 +00:00
do_action ( 'woocommerce_refund_created' , $refund -> get_id (), $args );
2017-02-08 16:19:47 +00:00
do_action ( 'woocommerce_order_refunded' , $order -> get_id (), $refund -> get_id () );
2017-01-10 14:14:03 +00:00
2016-08-24 14:26:35 +00:00
} catch ( Exception $e ) {
2017-11-22 16:03:58 +00:00
if ( isset ( $refund ) && is_a ( $refund , 'WC_Order_Refund' ) ) {
wp_delete_post ( $refund -> get_id (), true );
}
2016-08-24 15:02:19 +00:00
return new WP_Error ( 'error' , $e -> getMessage () );
2014-07-23 16:41:35 +00:00
}
2014-07-23 16:56:43 +00:00
2016-08-22 10:00:31 +00:00
return $refund ;
2014-07-08 14:32:47 +00:00
}
2014-07-19 04:08:02 +00:00
2017-02-08 16:19:47 +00:00
/**
* Try to refund the payment for an order via the gateway .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2018-03-08 18:47:54 +00:00
* @ throws Exception Throws exceptions when fail to refund , but returns WP_Error instead .
* @ param WC_Order $order Order instance .
* @ param string $amount Amount to refund .
* @ param string $reason Refund reason .
2017-02-08 16:19:47 +00:00
* @ return bool | WP_Error
*/
function wc_refund_payment ( $order , $amount , $reason = '' ) {
try {
if ( ! is_a ( $order , 'WC_Order' ) ) {
throw new Exception ( __ ( 'Invalid order.' , 'woocommerce' ) );
}
$gateway_controller = WC_Payment_Gateways :: instance ();
$all_gateways = $gateway_controller -> payment_gateways ();
$payment_method = $order -> get_payment_method ();
$gateway = isset ( $all_gateways [ $payment_method ] ) ? $all_gateways [ $payment_method ] : false ;
if ( ! $gateway ) {
throw new Exception ( __ ( 'The payment gateway for this order does not exist.' , 'woocommerce' ) );
}
if ( ! $gateway -> supports ( 'refunds' ) ) {
throw new Exception ( __ ( 'The payment gateway for this order does not support automatic refunds.' , 'woocommerce' ) );
}
$result = $gateway -> process_refund ( $order -> get_id (), $amount , $reason );
if ( ! $result ) {
throw new Exception ( __ ( 'An error occurred while attempting to create the refund using the payment gateway API.' , 'woocommerce' ) );
}
if ( is_wp_error ( $result ) ) {
throw new Exception ( $result -> get_error_message () );
}
return true ;
} catch ( Exception $e ) {
return new WP_Error ( 'error' , $e -> getMessage () );
}
}
/**
* Restock items during refund .
*
2018-03-08 18:47:54 +00:00
* @ since 3.0 . 0
* @ param WC_Order $order Order instance .
* @ param array $refunded_line_items Refunded items list .
2017-02-08 16:19:47 +00:00
*/
function wc_restock_refunded_items ( $order , $refunded_line_items ) {
2020-02-21 18:15:09 +00:00
if ( ! apply_filters ( 'woocommerce_can_restock_refunded_items' , true , $order , $refunded_line_items ) ) {
return ;
}
2017-02-08 16:19:47 +00:00
$line_items = $order -> get_items ();
foreach ( $line_items as $item_id => $item ) {
if ( ! isset ( $refunded_line_items [ $item_id ], $refunded_line_items [ $item_id ][ 'qty' ] ) ) {
continue ;
}
2019-02-13 15:05:20 +00:00
$product = $item -> get_product ();
$item_stock_reduced = $item -> get_meta ( '_reduced_stock' , true );
2019-02-18 12:27:08 +00:00
$qty_to_refund = $refunded_line_items [ $item_id ][ 'qty' ];
2017-02-08 16:19:47 +00:00
2019-02-18 12:27:08 +00:00
if ( ! $item_stock_reduced || ! $qty_to_refund || ! $product || ! $product -> managing_stock () ) {
2019-02-13 15:05:20 +00:00
continue ;
}
2017-02-08 16:19:47 +00:00
2019-02-13 15:05:20 +00:00
$old_stock = $product -> get_stock_quantity ();
2019-02-18 12:27:08 +00:00
$new_stock = wc_update_product_stock ( $product , $qty_to_refund , 'increase' );
// Update _reduced_stock meta to track changes.
$item_stock_reduced = $item_stock_reduced - $qty_to_refund ;
if ( 0 < $item_stock_reduced ) {
$item -> update_meta_data ( '_reduced_stock' , $item_stock_reduced );
} else {
$item -> delete_meta_data ( '_reduced_stock' );
}
2017-02-08 16:19:47 +00:00
2019-02-13 15:05:20 +00:00
/* translators: 1: product ID 2: old stock level 3: new stock level */
$order -> add_order_note ( sprintf ( __ ( 'Item #%1$s stock increased from %2$s to %3$s.' , 'woocommerce' ), $product -> get_id (), $old_stock , $new_stock ) );
$item -> save ();
do_action ( 'woocommerce_restock_refunded_item' , $product -> get_id (), $old_stock , $new_stock , $order , $product );
2017-02-08 16:19:47 +00:00
}
}
2014-07-19 04:08:02 +00:00
/**
* Get tax class by tax id .
*
* @ since 2.2
2018-03-08 18:47:54 +00:00
* @ param int $tax_id Tax ID .
2014-07-19 04:08:02 +00:00
* @ return string
*/
function wc_get_tax_class_by_tax_id ( $tax_id ) {
global $wpdb ;
2016-11-18 14:07:21 +00:00
return $wpdb -> get_var ( $wpdb -> prepare ( " SELECT tax_rate_class FROM { $wpdb -> prefix } woocommerce_tax_rates WHERE tax_rate_id = %d " , $tax_id ) );
2014-07-19 04:08:02 +00:00
}
2014-07-22 15:13:35 +00:00
/**
* Get payment gateway class by order data .
*
* @ since 2.2
2018-03-08 18:47:54 +00:00
* @ param int | WC_Order $order Order instance .
2014-07-22 15:13:35 +00:00
* @ return WC_Payment_Gateway | bool
*/
function wc_get_payment_gateway_by_order ( $order ) {
if ( WC () -> payment_gateways () ) {
2017-05-29 12:02:16 +00:00
$payment_gateways = WC () -> payment_gateways () -> payment_gateways ();
2014-07-22 15:13:35 +00:00
} else {
$payment_gateways = array ();
}
2014-08-25 19:11:39 +00:00
if ( ! is_object ( $order ) ) {
$order_id = absint ( $order );
2015-07-30 18:07:34 +00:00
$order = wc_get_order ( $order_id );
2014-07-22 15:13:35 +00:00
}
2017-05-10 18:54:20 +00:00
return is_a ( $order , 'WC_Order' ) && isset ( $payment_gateways [ $order -> get_payment_method () ] ) ? $payment_gateways [ $order -> get_payment_method () ] : false ;
2014-07-22 15:13:35 +00:00
}
2015-04-24 14:58:13 +00:00
/**
* When refunding an order , create a refund line item if the partial refunds do not match order total .
*
* This is manual ; no gateway refund will be performed .
*
* @ since 2.4
2018-03-08 18:47:54 +00:00
* @ param int $order_id Order ID .
2015-04-24 14:58:13 +00:00
*/
function wc_order_fully_refunded ( $order_id ) {
2018-03-08 18:47:54 +00:00
$order = wc_get_order ( $order_id );
$max_refund = wc_format_decimal ( $order -> get_total () - $order -> get_total_refunded () );
2015-04-24 14:58:13 +00:00
if ( ! $max_refund ) {
return ;
}
2018-03-08 18:47:54 +00:00
// Create the refund object.
2020-08-13 13:32:19 +00:00
wc_switch_to_site_locale ();
2018-03-08 18:47:54 +00:00
wc_create_refund (
array (
'amount' => $max_refund ,
2019-05-16 20:57:28 +00:00
'reason' => __ ( 'Order fully refunded.' , 'woocommerce' ),
2018-03-08 18:47:54 +00:00
'order_id' => $order_id ,
'line_items' => array (),
)
);
2020-08-13 13:32:19 +00:00
wc_restore_locale ();
2019-05-16 20:57:28 +00:00
$order -> add_order_note ( __ ( 'Order status set to refunded. To return funds to the customer you will need to issue a refund through your payment gateway.' , 'woocommerce' ) );
2015-04-24 14:58:13 +00:00
}
add_action ( 'woocommerce_order_status_refunded' , 'wc_order_fully_refunded' );
2016-06-13 13:42:10 +00:00
/**
2016-11-18 14:07:21 +00:00
* Search orders .
2016-06-13 13:42:10 +00:00
*
* @ since 2.6 . 0
* @ param string $term Term to search .
* @ return array List of orders ID .
*/
function wc_order_search ( $term ) {
2016-11-18 14:07:21 +00:00
$data_store = WC_Data_Store :: load ( 'order' );
return $data_store -> search_orders ( str_replace ( 'Order #' , '' , wc_clean ( $term ) ) );
2016-06-13 13:42:10 +00:00
}
2016-06-21 19:26:35 +00:00
/**
* Update total sales amount for each product within a paid order .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2018-03-08 18:47:54 +00:00
* @ param int $order_id Order ID .
2016-06-21 19:26:35 +00:00
*/
function wc_update_total_sales_counts ( $order_id ) {
$order = wc_get_order ( $order_id );
2016-11-18 14:07:21 +00:00
if ( ! $order || $order -> get_data_store () -> get_recorded_sales ( $order ) ) {
2016-06-21 19:26:35 +00:00
return ;
}
2018-03-08 18:47:54 +00:00
if ( count ( $order -> get_items () ) > 0 ) {
2016-06-21 19:26:35 +00:00
foreach ( $order -> get_items () as $item ) {
2018-03-08 18:47:54 +00:00
$product_id = $item -> get_product_id ();
if ( $product_id ) {
2017-02-10 23:41:53 +00:00
$data_store = WC_Data_Store :: load ( 'product' );
2020-07-17 20:14:26 +00:00
$data_store -> update_product_sales ( $product_id , absint ( $item -> get_quantity () ), 'increase' );
2016-06-21 19:26:35 +00:00
}
}
}
2016-11-18 14:07:21 +00:00
$order -> get_data_store () -> set_recorded_sales ( $order , true );
2016-06-21 19:26:35 +00:00
/**
* Called when sales for an order are recorded
*
* @ param int $order_id order id
*/
do_action ( 'woocommerce_recorded_sales' , $order_id );
}
add_action ( 'woocommerce_order_status_completed' , 'wc_update_total_sales_counts' );
add_action ( 'woocommerce_order_status_processing' , 'wc_update_total_sales_counts' );
add_action ( 'woocommerce_order_status_on-hold' , 'wc_update_total_sales_counts' );
/**
* Update used coupon amount for each coupon within an order .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2018-03-08 18:47:54 +00:00
* @ param int $order_id Order ID .
2016-06-21 19:26:35 +00:00
*/
function wc_update_coupon_usage_counts ( $order_id ) {
2018-03-08 18:47:54 +00:00
$order = wc_get_order ( $order_id );
if ( ! $order ) {
2016-06-21 19:26:35 +00:00
return ;
}
2016-11-18 14:07:21 +00:00
$has_recorded = $order -> get_data_store () -> get_recorded_coupon_usage_counts ( $order );
if ( $order -> has_status ( 'cancelled' ) && $has_recorded ) {
2016-06-21 19:26:35 +00:00
$action = 'reduce' ;
2016-11-18 14:07:21 +00:00
$order -> get_data_store () -> set_recorded_coupon_usage_counts ( $order , false );
} elseif ( ! $order -> has_status ( 'cancelled' ) && ! $has_recorded ) {
2016-06-21 19:26:35 +00:00
$action = 'increase' ;
2016-11-18 14:07:21 +00:00
$order -> get_data_store () -> set_recorded_coupon_usage_counts ( $order , true );
2020-07-30 15:35:23 +00:00
} elseif ( $order -> has_status ( 'cancelled' ) ) {
$order -> get_data_store () -> release_held_coupons ( $order , true );
return ;
2016-06-21 19:26:35 +00:00
} else {
return ;
}
2019-05-14 09:21:27 +00:00
if ( count ( $order -> get_coupon_codes () ) > 0 ) {
foreach ( $order -> get_coupon_codes () as $code ) {
2016-06-21 19:26:35 +00:00
if ( ! $code ) {
continue ;
}
2018-03-08 18:47:54 +00:00
$coupon = new WC_Coupon ( $code );
$used_by = $order -> get_user_id ();
2016-06-21 19:26:35 +00:00
2018-03-08 18:47:54 +00:00
if ( ! $used_by ) {
2016-06-21 19:26:35 +00:00
$used_by = $order -> get_billing_email ();
}
switch ( $action ) {
2018-03-08 18:47:54 +00:00
case 'reduce' :
2017-03-08 23:27:37 +00:00
$coupon -> decrease_usage_count ( $used_by );
2018-03-08 18:47:54 +00:00
break ;
case 'increase' :
2019-07-09 21:07:44 +00:00
$coupon -> increase_usage_count ( $used_by , $order );
2018-03-08 18:47:54 +00:00
break ;
2016-06-21 19:26:35 +00:00
}
}
2019-07-09 21:07:44 +00:00
$order -> get_data_store () -> release_held_coupons ( $order , true );
2016-06-21 19:26:35 +00:00
}
}
2016-10-18 11:27:56 +00:00
add_action ( 'woocommerce_order_status_pending' , 'wc_update_coupon_usage_counts' );
add_action ( 'woocommerce_order_status_completed' , 'wc_update_coupon_usage_counts' );
add_action ( 'woocommerce_order_status_processing' , 'wc_update_coupon_usage_counts' );
add_action ( 'woocommerce_order_status_on-hold' , 'wc_update_coupon_usage_counts' );
add_action ( 'woocommerce_order_status_cancelled' , 'wc_update_coupon_usage_counts' );
2016-06-21 19:26:35 +00:00
/**
2016-11-02 18:50:42 +00:00
* Cancel all unpaid orders after held duration to prevent stock lock for those products .
2016-06-21 19:26:35 +00:00
*/
2016-11-02 18:50:42 +00:00
function wc_cancel_unpaid_orders () {
$held_duration = get_option ( 'woocommerce_hold_stock_minutes' );
if ( $held_duration < 1 || 'yes' !== get_option ( 'woocommerce_manage_stock' ) ) {
return ;
2016-06-21 19:26:35 +00:00
}
2016-11-18 14:07:21 +00:00
$data_store = WC_Data_Store :: load ( 'order' );
$unpaid_orders = $data_store -> get_unpaid_orders ( strtotime ( '-' . absint ( $held_duration ) . ' MINUTES' , current_time ( 'timestamp' ) ) );
2016-06-21 19:26:35 +00:00
2016-11-02 18:50:42 +00:00
if ( $unpaid_orders ) {
foreach ( $unpaid_orders as $unpaid_order ) {
$order = wc_get_order ( $unpaid_order );
2016-11-18 14:07:21 +00:00
if ( apply_filters ( 'woocommerce_cancel_unpaid_order' , 'checkout' === $order -> get_created_via (), $order ) ) {
2016-11-02 18:50:42 +00:00
$order -> update_status ( 'cancelled' , __ ( 'Unpaid order cancelled - time limit reached.' , 'woocommerce' ) );
2016-06-21 19:26:35 +00:00
}
}
}
2016-11-02 18:50:42 +00:00
wp_clear_scheduled_hook ( 'woocommerce_cancel_unpaid_orders' );
wp_schedule_single_event ( time () + ( absint ( $held_duration ) * 60 ), 'woocommerce_cancel_unpaid_orders' );
2016-06-21 19:26:35 +00:00
}
2016-11-02 18:50:42 +00:00
add_action ( 'woocommerce_cancel_unpaid_orders' , 'wc_cancel_unpaid_orders' );
2017-05-31 20:34:00 +00:00
2017-06-01 11:08:48 +00:00
/**
* Sanitize order id removing unwanted characters .
*
* E . g Users can sometimes try to track an order id using # with no success.
* This function will fix this .
*
* @ since 3.1 . 0
2018-03-08 18:47:54 +00:00
* @ param int $order_id Order ID .
2017-06-01 11:08:48 +00:00
*/
function wc_sanitize_order_id ( $order_id ) {
2018-10-04 13:53:55 +00:00
return ( int ) filter_var ( $order_id , FILTER_SANITIZE_NUMBER_INT );
2017-05-31 20:34:00 +00:00
}
2017-06-01 11:08:48 +00:00
add_filter ( 'woocommerce_shortcode_order_tracking_order_id' , 'wc_sanitize_order_id' );
2017-07-12 21:03:39 +00:00
/**
2017-07-12 21:05:44 +00:00
* Get an order note .
2017-07-12 21:03:39 +00:00
*
* @ since 3.2 . 0
* @ param int | WP_Comment $data Note ID ( or WP_Comment instance for internal use only ) .
* @ return stdClass | null Object with order note details or null when does not exists .
*/
function wc_get_order_note ( $data ) {
if ( is_numeric ( $data ) ) {
$data = get_comment ( $data );
}
if ( ! is_a ( $data , 'WP_Comment' ) ) {
return null ;
}
2018-03-08 18:47:54 +00:00
return ( object ) apply_filters (
2019-01-22 13:12:26 +00:00
'woocommerce_get_order_note' ,
array (
2018-03-08 18:47:54 +00:00
'id' => ( int ) $data -> comment_ID ,
'date_created' => wc_string_to_datetime ( $data -> comment_date ),
'content' => $data -> comment_content ,
'customer_note' => ( bool ) get_comment_meta ( $data -> comment_ID , 'is_customer_note' , true ),
'added_by' => __ ( 'WooCommerce' , 'woocommerce' ) === $data -> comment_author ? 'system' : $data -> comment_author ,
2019-01-22 13:12:26 +00:00
),
$data
2018-03-08 18:47:54 +00:00
);
2017-07-12 21:03:39 +00:00
}
/**
* Get order notes .
*
* @ since 3.2 . 0
* @ param array $args Query arguments {
* Array of query parameters .
*
* @ type string $limit Maximum number of notes to retrieve .
* Default empty ( no limit ) .
* @ type int $order_id Limit results to those affiliated with a given order ID .
* Default 0.
* @ type array $order__in Array of order IDs to include affiliated notes for .
* Default empty .
* @ type array $order__not_in Array of order IDs to exclude affiliated notes for .
* Default empty .
* @ type string $orderby Define how should sort notes .
* Accepts 'date_created' , 'date_created_gmt' or 'id' .
* Default : 'id' .
* @ type string $order How to order retrieved notes .
* Accepts 'ASC' or 'DESC' .
* Default : 'DESC' .
* @ type string $type Define what type of note should retrieve .
* Accepts 'customer' , 'internal' or empty for both .
* Default empty .
* }
* @ return stdClass [] Array of stdClass objects with order notes details .
*/
function wc_get_order_notes ( $args ) {
$key_mapping = array (
'limit' => 'number' ,
'order_id' => 'post_id' ,
'order__in' => 'post__in' ,
'order__not_in' => 'post__not_in' ,
);
foreach ( $key_mapping as $query_key => $db_key ) {
if ( isset ( $args [ $query_key ] ) ) {
$args [ $db_key ] = $args [ $query_key ];
unset ( $args [ $query_key ] );
}
}
// Define orderby.
$orderby_mapping = array (
'date_created' => 'comment_date' ,
'date_created_gmt' => 'comment_date_gmt' ,
'id' => 'comment_ID' ,
);
$args [ 'orderby' ] = ! empty ( $args [ 'orderby' ] ) && in_array ( $args [ 'orderby' ], array ( 'date_created' , 'date_created_gmt' , 'id' ), true ) ? $orderby_mapping [ $args [ 'orderby' ] ] : 'comment_ID' ;
// Set WooCommerce order type.
if ( isset ( $args [ 'type' ] ) && 'customer' === $args [ 'type' ] ) {
2018-03-08 18:47:54 +00:00
$args [ 'meta_query' ] = array ( // WPCS: slow query ok.
2017-07-12 21:03:39 +00:00
array (
'key' => 'is_customer_note' ,
'value' => 1 ,
'compare' => '=' ,
),
);
} elseif ( isset ( $args [ 'type' ] ) && 'internal' === $args [ 'type' ] ) {
2018-03-08 18:47:54 +00:00
$args [ 'meta_query' ] = array ( // WPCS: slow query ok.
2017-07-12 21:03:39 +00:00
array (
'key' => 'is_customer_note' ,
'compare' => 'NOT EXISTS' ,
),
);
}
// Set correct comment type.
$args [ 'type' ] = 'order_note' ;
// Always approved.
$args [ 'status' ] = 'approve' ;
2018-03-08 18:47:54 +00:00
// Does not support 'count' or 'fields'.
2017-07-12 21:45:27 +00:00
unset ( $args [ 'count' ], $args [ 'fields' ] );
2017-07-12 21:03:39 +00:00
remove_filter ( 'comments_clauses' , array ( 'WC_Comments' , 'exclude_order_comments' ), 10 , 1 );
$notes = get_comments ( $args );
add_filter ( 'comments_clauses' , array ( 'WC_Comments' , 'exclude_order_comments' ), 10 , 1 );
return array_filter ( array_map ( 'wc_get_order_note' , $notes ) );
}
/**
* Create an order note .
*
* @ since 3.2 . 0
* @ param int $order_id Order ID .
* @ param string $note Note to add .
2018-03-08 18:47:54 +00:00
* @ param bool $is_customer_note If is a costumer note .
* @ param bool $added_by_user If note is create by an user .
2017-07-12 21:03:39 +00:00
* @ return int | WP_Error Integer when created or WP_Error when found an error .
*/
function wc_create_order_note ( $order_id , $note , $is_customer_note = false , $added_by_user = false ) {
$order = wc_get_order ( $order_id );
if ( ! $order ) {
return new WP_Error ( 'invalid_order_id' , __ ( 'Invalid order ID.' , 'woocommerce' ), array ( 'status' => 400 ) );
}
return $order -> add_order_note ( $note , ( int ) $is_customer_note , $added_by_user );
}
/**
2017-07-12 21:05:44 +00:00
* Delete an order note .
2017-07-12 21:03:39 +00:00
*
2017-07-12 21:05:44 +00:00
* @ since 3.2 . 0
2017-07-12 21:03:39 +00:00
* @ param int $note_id Order note .
* @ return bool True on success , false on failure .
*/
function wc_delete_order_note ( $note_id ) {
return wp_delete_comment ( $note_id , true );
}