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 .
*
* @ author WooThemes
* @ category Core
* @ package WooCommerce / Functions
* @ version 2.1 . 0
*/
2014-09-20 19:10:04 +00:00
if ( ! defined ( 'ABSPATH' ) ) {
exit ; // Exit if accessed directly
}
2013-08-09 16:11:15 +00:00
2016-03-09 13:25:36 +00:00
/**
* Wrapper for get_posts specific to orders .
*
* This function should be used for order retrieval so that when we move to
* custom tables , functions still work .
*
* Args :
* status array | string List of order statuses to find
* type array | string Order type , e . g . shop_order or shop_order_refund
* parent int post / order parent
2016-03-09 14:50:34 +00:00
* customer int | string | array User ID or billing email to limit orders to a
* particular user . Accepts array of values . Array of values is OR 'ed. If array of array is passed, each array will be AND' ed .
* e . g . test @ test . com , 1 , array ( 1 , 2 , 3 ), array ( array ( 1 , 'test@test.com' ), 2 , 3 )
2016-03-09 13:25:36 +00:00
* limit int Maximum of orders to retrieve .
* offset int Offset of orders to retrieve .
* page int Page of orders to retrieve . Ignored when using the 'offset' arg .
* exclude array Order IDs to exclude from the query .
* orderby string Order by date , title , id , modified , rand etc
* order string ASC or DESC
2016-03-09 16:11:05 +00:00
* return string Type of data to return . Allowed values :
* ids array of order ids
* objects array of order objects ( default )
* paginate bool If true , the return value will be an array with values :
* 'orders' => array of data ( return value above ),
* 'total' => total number of orders matching the query
* 'max_num_pages' => max number of pages found
2016-03-09 13:25:36 +00:00
*
* @ since 2.6 . 0
* @ param array $args Array of args ( above )
2016-03-14 16:08:42 +00:00
* @ return array | 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 ) {
$args = wp_parse_args ( $args , array (
'status' => array_keys ( wc_get_order_statuses () ),
'type' => wc_get_order_types ( 'view-orders' ),
'parent' => null ,
2016-03-14 16:08:42 +00:00
'customer' => null ,
2016-03-09 14:50:34 +00:00
'email' => '' ,
2016-03-14 16:08:42 +00:00
'limit' => get_option ( 'posts_per_page' ),
2016-03-09 13:25:36 +00:00
'offset' => null ,
'page' => 1 ,
'exclude' => array (),
'orderby' => 'date' ,
'order' => 'DESC' ,
2016-03-09 16:11:05 +00:00
'return' => 'objects' ,
'paginate' => false ,
2016-03-09 13:25:36 +00:00
) );
// Handle some BW compatibility arg names where wp_query args differ in naming.
2016-03-14 16:08:42 +00:00
$map_legacy = array (
'numberposts' => 'limit' ,
'post_type' => 'type' ,
'post_status' => 'status' ,
'post_parent' => 'parent' ,
'author' => 'customer' ,
'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
/**
* Generate WP_Query args . This logic will change if orders are moved to
* custom tables in the future .
*/
$wp_query_args = array (
2016-03-09 16:11:05 +00:00
'post_type' => $args [ 'type' ] ? $args [ 'type' ] : 'shop_order' ,
2016-03-09 13:25:36 +00:00
'post_status' => $args [ 'status' ],
'posts_per_page' => $args [ 'limit' ],
'meta_query' => array (),
'fields' => 'ids' ,
'orderby' => $args [ 'orderby' ],
'order' => $args [ 'order' ],
);
if ( ! is_null ( $args [ 'parent' ] ) ) {
$wp_query_args [ 'post_parent' ] = absint ( $args [ 'parent' ] );
}
if ( ! is_null ( $args [ 'offset' ] ) ) {
$wp_query_args [ 'offset' ] = absint ( $args [ 'offset' ] );
} else {
$wp_query_args [ 'paged' ] = absint ( $args [ 'page' ] );
}
if ( ! empty ( $args [ 'customer' ] ) ) {
2016-03-09 14:50:34 +00:00
$values = is_array ( $args [ 'customer' ] ) ? $args [ 'customer' ] : array ( $args [ 'customer' ] );
$wp_query_args [ 'meta_query' ][] = _wc_get_orders_generate_customer_meta_query ( $values );
2016-03-09 13:25:36 +00:00
}
if ( ! empty ( $args [ 'exclude' ] ) ) {
$wp_query_args [ 'post__not_in' ] = array_map ( 'absint' , $args [ 'exclude' ] );
}
2016-03-09 16:11:05 +00:00
if ( ! $args [ 'paginate' ] ) {
$wp_query_args [ 'no_found_rows' ] = true ;
}
2016-03-09 13:25:36 +00:00
// Get results.
$orders = new WP_Query ( $wp_query_args );
if ( 'objects' === $args [ 'return' ] ) {
$return = array_map ( 'wc_get_order' , $orders -> posts );
} else {
$return = $orders -> posts ;
}
2016-03-09 16:11:05 +00:00
if ( $args [ 'paginate' ] ) {
return ( object ) array (
'orders' => $return ,
'total' => $orders -> found_posts ,
'max_num_pages' => $orders -> max_num_pages ,
);
} else {
return $return ;
}
2016-03-09 13:25:36 +00:00
}
2016-03-09 14:50:34 +00:00
/**
* Generate meta query for wc_get_orders . Used internally only .
* @ since 2.6 . 0
* @ param array $values
* @ param string $relation
* @ return array
*/
function _wc_get_orders_generate_customer_meta_query ( $values , $relation = 'or' ) {
$meta_query = array (
'relation' => strtoupper ( $relation ),
'customer_emails' => array (
'key' => '_billing_email' ,
'value' => array (),
2016-03-14 16:08:42 +00:00
'compare' => 'IN' ,
2016-03-09 14:50:34 +00:00
),
'customer_ids' => array (
'key' => '_customer_user' ,
'value' => array (),
2016-03-14 16:08:42 +00:00
'compare' => 'IN' ,
2016-03-09 14:50:34 +00:00
)
);
foreach ( $values as $value ) {
if ( is_array ( $value ) ) {
$meta_query [] = _wc_get_orders_generate_customer_meta_query ( $value , 'and' );
} elseif ( is_email ( $value ) ) {
$meta_query [ 'customer_emails' ][ 'value' ][] = sanitize_email ( $value );
} else {
$meta_query [ 'customer_ids' ][ 'value' ][] = strval ( absint ( $value ) );
}
}
if ( empty ( $meta_query [ 'customer_emails' ][ 'value' ] ) ) {
unset ( $meta_query [ 'customer_emails' ] );
unset ( $meta_query [ 'relation' ] );
}
if ( empty ( $meta_query [ 'customer_ids' ][ 'value' ] ) ) {
unset ( $meta_query [ 'customer_ids' ] );
unset ( $meta_query [ 'relation' ] );
}
return $meta_query ;
}
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
* @ return array
*/
function wc_get_order_statuses () {
$order_statuses = array (
2014-10-29 11:15:00 +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' ),
2014-10-29 11:15:00 +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 .
* @ param string $maybe_status Status , including any wc - prefix
* @ return bool
*/
function wc_is_order_status ( $maybe_status ) {
$order_statuses = wc_get_order_statuses ();
return isset ( $order_statuses [ $maybe_status ] );
}
2014-06-13 13:21:10 +00:00
/**
* Main function for returning orders , uses the WC_Order_Factory class .
*
2014-09-12 13:01:49 +00:00
* @ since 2.2
* @ param mixed $the_order Post object or post ID of the order .
2016-06-06 17:57:24 +00:00
* @ return WC_Order | WC_Refund
2014-06-13 13:21:10 +00:00
*/
2014-08-15 12:56:43 +00:00
function wc_get_order ( $the_order = false ) {
2016-01-04 10:43:48 +00:00
if ( ! did_action ( 'woocommerce_init' ) ) {
_doing_it_wrong ( __FUNCTION__ , __ ( 'wc_get_order should not be called before the woocommerce_init action.' , 'woocommerce' ), '2.5' );
return false ;
}
2014-08-15 12:56:43 +00:00
return WC () -> order_factory -> get_order ( $the_order );
2014-06-13 13:21:10 +00:00
}
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
2014-05-30 16:43:21 +00:00
* @ param string $status
* @ 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
}
2013-08-09 16:11:15 +00:00
/**
* Finds an Order ID based on an order key .
*
* @ access public
* @ 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-11-25 13:54:52 +00:00
function wc_get_order_id_by_order_key ( $order_key ) {
2013-08-09 16:11:15 +00:00
global $wpdb ;
// Faster than get_posts()
2014-09-16 09:45:28 +00:00
$order_id = $wpdb -> get_var ( $wpdb -> prepare ( " SELECT post_id FROM { $wpdb -> prefix } postmeta WHERE meta_key = '_order_key' AND meta_value = %s " , $order_key ) );
2013-08-09 16:11:15 +00:00
return $order_id ;
}
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
*
* $for optionally define what you are getting order types for so only relevent types are returned .
*
* e . g . for 'order-meta-boxes' , 'order-count'
*
* @ since 2.2
* @ param string $for
* @ 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 ) {
case 'order-count' :
foreach ( $wc_order_types as $type => $args ) {
if ( ! $args [ 'exclude_from_order_count' ] ) {
$order_types [] = $type ;
}
}
break ;
case 'order-meta-boxes' :
foreach ( $wc_order_types as $type => $args ) {
if ( $args [ 'add_order_meta_boxes' ] ) {
$order_types [] = $type ;
}
}
break ;
case 'view-orders' :
foreach ( $wc_order_types as $type => $args ) {
if ( ! $args [ 'exclude_from_order_views' ] ) {
$order_types [] = $type ;
}
}
break ;
case 'reports' :
foreach ( $wc_order_types as $type => $args ) {
if ( ! $args [ 'exclude_from_order_reports' ] ) {
$order_types [] = $type ;
}
}
break ;
2014-10-06 12:39:49 +00:00
case 'sales-reports' :
foreach ( $wc_order_types as $type => $args ) {
if ( ! $args [ 'exclude_from_order_sales_reports' ] ) {
$order_types [] = $type ;
}
}
break ;
2015-05-12 04:01:23 +00:00
case 'order-webhooks' :
foreach ( $wc_order_types as $type => $args ) {
if ( ! $args [ 'exclude_from_order_webhooks' ] ) {
$order_types [] = $type ;
}
}
break ;
2014-07-11 11:43:42 +00:00
default :
$order_types = array_keys ( $wc_order_types );
break ;
}
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 .
2014-07-11 11:43:42 +00:00
* @ param string post type name
* @ return bool | array of datails about the order type
*/
function wc_get_order_type ( $type ) {
global $wc_order_types ;
if ( isset ( $wc_order_types [ $type ] ) ) {
return $wc_order_types [ $type ];
} else {
return false ;
}
}
/**
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 :
2015-11-03 13:31:20 +00:00
* - exclude_from_orders_screen ( bool ) Whether or not this order type also get shown in the main .
2014-07-11 11:43:42 +00:00
* 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 .
2015-11-03 13:31:20 +00:00
* - exclude_from_order_views ( bool ) Whether or not this order type is visible by customers when .
2014-07-11 11:43:42 +00:00
* viewing orders e . g . on the my account page .
* - exclude_from_order_reports ( bool ) Whether or not to exclude this type from core reports .
2014-10-06 12:39:49 +00:00
* - 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
* @ param string $type Post type . ( max . 20 characters , can not contain capital letters or spaces )
* @ param array $args An array of arguments .
* @ 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 ();
}
// Register as a post type
if ( is_wp_error ( register_post_type ( $type , $args ) ) ) {
return false ;
}
// Register for WC usage
$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 ,
'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
/**
2015-11-03 13:31:20 +00:00
* Grant downloadable product access to the file identified by $download_id .
2013-08-09 16:11:15 +00:00
*
* @ access public
* @ param string $download_id file identifier
* @ param int $product_id product identifier
* @ param WC_Order $order the order
2015-02-17 14:03:42 +00:00
* @ param int $qty purchased
2013-11-29 18:50:31 +00:00
* @ return int | bool insert id or false on failure
2013-08-09 16:11:15 +00:00
*/
2015-02-17 14:03:42 +00:00
function wc_downloadable_file_permission ( $download_id , $product_id , $order , $qty = 1 ) {
2013-08-09 16:11:15 +00:00
global $wpdb ;
$user_email = sanitize_email ( $order -> billing_email );
$limit = trim ( get_post_meta ( $product_id , '_download_limit' , true ) );
$expiry = trim ( get_post_meta ( $product_id , '_download_expiry' , true ) );
2015-02-17 14:03:42 +00:00
$limit = empty ( $limit ) ? '' : absint ( $limit ) * $qty ;
2013-08-09 16:11:15 +00:00
// Default value is NULL in the table schema
$expiry = empty ( $expiry ) ? null : absint ( $expiry );
2013-12-17 05:07:19 +00:00
if ( $expiry ) {
$order_completed_date = date_i18n ( " Y-m-d " , strtotime ( $order -> completed_date ) );
$expiry = date_i18n ( " Y-m-d " , strtotime ( $order_completed_date . ' + ' . $expiry . ' DAY' ) );
}
2013-08-09 16:11:15 +00:00
2013-09-10 11:26:31 +00:00
$data = apply_filters ( 'woocommerce_downloadable_file_permission_data' , array (
'download_id' => $download_id ,
2013-08-09 16:11:15 +00:00
'product_id' => $product_id ,
'user_id' => absint ( $order -> user_id ),
'user_email' => $user_email ,
'order_id' => $order -> id ,
'order_key' => $order -> order_key ,
'downloads_remaining' => $limit ,
'access_granted' => current_time ( 'mysql' ),
'download_count' => 0
2013-09-10 11:26:31 +00:00
));
2013-08-09 16:11:15 +00:00
2013-09-10 11:26:31 +00:00
$format = apply_filters ( 'woocommerce_downloadable_file_permission_format' , array (
'%s' ,
2013-08-09 16:11:15 +00:00
'%s' ,
'%s' ,
'%s' ,
'%s' ,
'%s' ,
'%s' ,
'%s' ,
'%d'
2013-09-24 08:10:46 +00:00
), $data );
2013-08-09 16:11:15 +00:00
2013-09-10 11:26:31 +00:00
if ( ! is_null ( $expiry ) ) {
$data [ 'access_expires' ] = $expiry ;
$format [] = '%s' ;
}
2013-08-09 16:11:15 +00:00
// Downloadable product - give access to the customer
$result = $wpdb -> insert ( $wpdb -> prefix . 'woocommerce_downloadable_product_permissions' ,
2013-09-10 11:26:31 +00:00
$data ,
2013-09-10 14:08:20 +00:00
$format
2013-09-10 11:26:31 +00:00
);
do_action ( 'woocommerce_grant_product_download_access' , $data );
2013-08-09 16:11:15 +00:00
2013-09-10 11:26:31 +00:00
return $result ? $wpdb -> insert_id : false ;
2013-08-09 16:11:15 +00:00
}
2013-12-16 23:27:57 +00:00
2013-08-09 16:11:15 +00:00
/**
2015-11-03 13:31:20 +00:00
* Order Status completed - GIVE DOWNLOADABLE PRODUCT ACCESS TO CUSTOMER .
2013-08-09 16:11:15 +00:00
*
* @ access public
* @ param int $order_id
*/
2013-11-25 13:54:52 +00:00
function wc_downloadable_product_permissions ( $order_id ) {
2014-02-17 10:50:36 +00:00
if ( get_post_meta ( $order_id , '_download_permissions_granted' , true ) == 1 ) {
2013-08-09 16:11:15 +00:00
return ; // Only do this once
2014-02-17 10:50:36 +00:00
}
2013-08-09 16:11:15 +00:00
2014-08-15 12:29:21 +00:00
$order = wc_get_order ( $order_id );
2013-08-09 16:11:15 +00:00
2015-08-12 16:21:07 +00:00
if ( $order && $order -> has_status ( 'processing' ) && get_option ( 'woocommerce_downloads_grant_access_after_payment' ) == 'no' ) {
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
2013-09-20 16:01:09 +00:00
if ( sizeof ( $order -> get_items () ) > 0 ) {
foreach ( $order -> get_items () as $item ) {
2013-08-09 16:11:15 +00:00
$_product = $order -> get_product_from_item ( $item );
2013-09-20 16:01:09 +00:00
if ( $_product && $_product -> exists () && $_product -> is_downloadable () ) {
2013-12-16 23:27:57 +00:00
$downloads = $_product -> get_files ();
2013-08-09 16:11:15 +00:00
2013-12-16 23:27:57 +00:00
foreach ( array_keys ( $downloads ) as $download_id ) {
2015-02-17 14:03:42 +00:00
wc_downloadable_file_permission ( $download_id , $item [ 'variation_id' ] > 0 ? $item [ 'variation_id' ] : $item [ 'product_id' ], $order , $item [ 'qty' ] );
2013-12-16 23:27:57 +00:00
}
2013-09-20 16:01:09 +00:00
}
}
}
2013-08-09 16:11:15 +00:00
2013-09-20 16:01:09 +00:00
update_post_meta ( $order_id , '_download_permissions_granted' , 1 );
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' );
2013-08-09 16:11:15 +00:00
/**
* Add a item to an order ( for example a line item ) .
*
* @ access public
* @ param int $order_id
* @ return mixed
*/
2013-11-25 13:54:52 +00:00
function wc_add_order_item ( $order_id , $item ) {
2013-08-09 16:11:15 +00:00
global $wpdb ;
$order_id = absint ( $order_id );
if ( ! $order_id )
return false ;
$defaults = array (
'order_item_name' => '' ,
'order_item_type' => 'line_item' ,
);
$item = wp_parse_args ( $item , $defaults );
$wpdb -> insert (
$wpdb -> prefix . " woocommerce_order_items " ,
array (
'order_item_name' => $item [ 'order_item_name' ],
'order_item_type' => $item [ 'order_item_type' ],
'order_id' => $order_id
),
array (
'%s' , '%s' , '%d'
)
);
$item_id = absint ( $wpdb -> insert_id );
do_action ( 'woocommerce_new_order_item' , $item_id , $item , $order_id );
return $item_id ;
}
2014-07-28 03:21:16 +00:00
/**
2015-11-03 13:31:20 +00:00
* Update an item for an order .
2014-07-28 03:21:16 +00:00
*
* @ since 2.2
* @ param int $item_id
* @ param array $args either `order_item_type` or `order_item_name`
* @ return bool true if successfully updated , false otherwise
*/
function wc_update_order_item ( $item_id , $args ) {
global $wpdb ;
$update = $wpdb -> update ( $wpdb -> prefix . 'woocommerce_order_items' , $args , array ( 'order_item_id' => $item_id ) );
if ( false === $update ) {
return false ;
}
do_action ( 'woocommerce_update_order_item' , $item_id , $args );
return true ;
}
2013-08-09 16:11:15 +00:00
/**
2015-11-03 13:31:20 +00:00
* Delete an item from the order it belongs to based on item id .
2013-08-09 16:11:15 +00:00
*
* @ access public
* @ param int $item_id
* @ return bool
*/
2013-11-25 13:54:52 +00:00
function wc_delete_order_item ( $item_id ) {
2013-08-09 16:11:15 +00:00
global $wpdb ;
$item_id = absint ( $item_id );
if ( ! $item_id )
return false ;
do_action ( 'woocommerce_before_delete_order_item' , $item_id );
$wpdb -> query ( $wpdb -> prepare ( " DELETE FROM { $wpdb -> prefix } woocommerce_order_items WHERE order_item_id = %d " , $item_id ) );
$wpdb -> query ( $wpdb -> prepare ( " DELETE FROM { $wpdb -> prefix } woocommerce_order_itemmeta WHERE order_item_id = %d " , $item_id ) );
do_action ( 'woocommerce_delete_order_item' , $item_id );
return true ;
}
/**
2015-11-03 13:31:20 +00:00
* WooCommerce Order Item Meta API - Update term meta .
2013-08-09 16:11:15 +00:00
*
* @ access public
* @ param mixed $item_id
* @ param mixed $meta_key
* @ param mixed $meta_value
* @ param string $prev_value ( default : '' )
* @ return bool
*/
2013-11-25 13:54:52 +00:00
function wc_update_order_item_meta ( $item_id , $meta_key , $meta_value , $prev_value = '' ) {
2016-05-09 09:01:12 +00:00
if ( update_metadata ( 'order_item' , $item_id , $meta_key , $meta_value , $prev_value ) ) {
$cache_key = WC_Cache_Helper :: get_cache_prefix ( 'orders' ) . 'item_meta_array_' . $item_id ;
wp_cache_delete ( $cache_key , 'orders' );
return true ;
}
return false ;
2013-08-09 16:11:15 +00:00
}
/**
2015-11-03 13:31:20 +00:00
* WooCommerce Order Item Meta API - Add term meta .
2013-08-09 16:11:15 +00:00
*
* @ access public
* @ param mixed $item_id
* @ param mixed $meta_key
* @ param mixed $meta_value
* @ param bool $unique ( default : false )
2016-05-11 14:28:40 +00:00
* @ return int New row ID or 0
2013-08-09 16:11:15 +00:00
*/
2013-11-25 13:54:52 +00:00
function wc_add_order_item_meta ( $item_id , $meta_key , $meta_value , $unique = false ) {
2016-05-11 14:28:40 +00:00
if ( $meta_id = add_metadata ( 'order_item' , $item_id , $meta_key , $meta_value , $unique ) ) {
2016-05-09 09:01:12 +00:00
$cache_key = WC_Cache_Helper :: get_cache_prefix ( 'orders' ) . 'item_meta_array_' . $item_id ;
wp_cache_delete ( $cache_key , 'orders' );
2016-05-11 14:28:40 +00:00
return $meta_id ;
2016-05-09 09:01:12 +00:00
}
2016-05-11 14:28:40 +00:00
return 0 ;
2013-08-09 16:11:15 +00:00
}
/**
2015-11-03 13:31:20 +00:00
* WooCommerce Order Item Meta API - Delete term meta .
2013-08-09 16:11:15 +00:00
*
* @ access public
* @ param mixed $item_id
* @ param mixed $meta_key
* @ param string $meta_value ( default : '' )
* @ param bool $delete_all ( default : false )
* @ return bool
*/
2013-11-25 13:54:52 +00:00
function wc_delete_order_item_meta ( $item_id , $meta_key , $meta_value = '' , $delete_all = false ) {
2016-05-09 09:01:12 +00:00
if ( delete_metadata ( 'order_item' , $item_id , $meta_key , $meta_value , $delete_all ) ) {
$cache_key = WC_Cache_Helper :: get_cache_prefix ( 'orders' ) . 'item_meta_array_' . $item_id ;
wp_cache_delete ( $cache_key , 'orders' );
return true ;
}
return false ;
2013-08-09 16:11:15 +00:00
}
/**
2015-11-03 13:31:20 +00:00
* WooCommerce Order Item Meta API - Get term meta .
2013-08-09 16:11:15 +00:00
*
* @ access public
* @ param mixed $item_id
* @ param mixed $key
* @ param bool $single ( default : true )
* @ return mixed
*/
2013-11-25 13:54:52 +00:00
function wc_get_order_item_meta ( $item_id , $key , $single = true ) {
2013-08-09 16:11:15 +00:00
return get_metadata ( 'order_item' , $item_id , $key , $single );
}
/**
2015-11-03 13:31:20 +00:00
* Cancel all unpaid orders after held duration to prevent stock lock for those products .
2013-08-09 16:11:15 +00:00
*
* @ access public
*/
2013-11-25 13:54:52 +00:00
function wc_cancel_unpaid_orders () {
2013-08-09 16:11:15 +00:00
global $wpdb ;
$held_duration = get_option ( 'woocommerce_hold_stock_minutes' );
if ( $held_duration < 1 || get_option ( 'woocommerce_manage_stock' ) != 'yes' )
return ;
$date = date ( " Y-m-d H:i:s " , strtotime ( '-' . absint ( $held_duration ) . ' MINUTES' , current_time ( 'timestamp' ) ) );
$unpaid_orders = $wpdb -> get_col ( $wpdb -> prepare ( "
SELECT posts . ID
FROM { $wpdb -> posts } AS posts
2014-08-12 15:14:38 +00:00
WHERE posts . post_type IN ( '" . implode( "' , '", wc_get_order_types() ) . "' )
2014-06-03 10:29:01 +00:00
AND posts . post_status = 'wc-pending'
2013-08-09 16:11:15 +00:00
AND posts . post_modified < % s
" , $date ) );
if ( $unpaid_orders ) {
foreach ( $unpaid_orders as $unpaid_order ) {
2014-08-15 12:29:21 +00:00
$order = wc_get_order ( $unpaid_order );
2013-08-09 16:11:15 +00:00
2015-04-01 13:21:07 +00:00
if ( apply_filters ( 'woocommerce_cancel_unpaid_order' , 'checkout' === get_post_meta ( $unpaid_order , '_created_via' , true ), $order ) ) {
2013-08-09 16:11:15 +00:00
$order -> update_status ( 'cancelled' , __ ( 'Unpaid order cancelled - time limit reached.' , 'woocommerce' ) );
2015-04-01 13:21:07 +00:00
}
2013-08-09 16:11:15 +00:00
}
}
wp_clear_scheduled_hook ( 'woocommerce_cancel_unpaid_orders' );
2014-03-07 19:17:11 +00:00
wp_schedule_single_event ( time () + ( absint ( $held_duration ) * 60 ), 'woocommerce_cancel_unpaid_orders' );
2013-08-09 16:11:15 +00:00
}
2013-11-25 13:54:52 +00:00
add_action ( 'woocommerce_cancel_unpaid_orders' , 'wc_cancel_unpaid_orders' );
2013-08-09 16:11:15 +00:00
/**
* Return the count of processing orders .
*
* @ access public
* @ return int
*/
2013-11-25 13:54:52 +00:00
function wc_processing_order_count () {
2015-03-04 08:51:06 +00:00
return wc_orders_count ( 'processing' );
}
/**
* Return the orders count of a specific order status .
*
* @ access public
2015-11-05 16:05:03 +00:00
* @ param string $status
2015-03-04 08:51:06 +00:00
* @ return int
*/
function wc_orders_count ( $status ) {
2014-07-11 11:43:42 +00:00
$count = 0 ;
2015-03-04 08:51:06 +00:00
$order_statuses = array_keys ( wc_get_order_statuses () );
if ( ! in_array ( 'wc-' . $status , $order_statuses ) ) {
return 0 ;
}
2014-07-11 11:43:42 +00:00
foreach ( wc_get_order_types ( 'order-count' ) as $type ) {
2015-03-04 08:51:06 +00:00
$this_count = wp_count_posts ( $type , 'readable' );
$count += isset ( $this_count -> { 'wc-' . $status } ) ? $this_count -> { 'wc-' . $status } : 0 ;
2014-07-11 11:43:42 +00:00
}
return $count ;
2013-08-09 16:11:15 +00:00
}
2014-02-26 15:43:19 +00:00
/**
* Clear all transients cache for order data .
*
* @ param int $post_id ( default : 0 )
*/
function wc_delete_shop_order_transients ( $post_id = 0 ) {
2014-10-07 10:01:22 +00:00
$post_id = absint ( $post_id );
$transients_to_clear = array ();
2014-02-26 15:43:19 +00:00
2014-03-20 11:10:25 +00:00
// Clear report transients
$reports = WC_Admin_Reports :: get_reports ();
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
}
}
2014-04-22 19:01:08 +00:00
// clear API report transient
$transients_to_clear [] = 'wc_admin_report' ;
2014-03-18 10:48:18 +00:00
// Clear transients where we have names
2014-02-26 15:43:19 +00:00
foreach ( $transients_to_clear as $transient ) {
delete_transient ( $transient );
}
2016-02-08 12:26:46 +00:00
// Clear money spent for user associated with order
if ( $post_id && ( $user_id = get_post_meta ( $post_id , '_customer_user' , true ) ) ) {
delete_user_meta ( $user_id , '_money_spent' );
delete_user_meta ( $user_id , '_order_count' );
}
2015-03-27 13:17:54 +00:00
// Increments the transient version to invalidate cache
WC_Cache_Helper :: get_transient_version ( 'orders' , true );
2015-11-05 15:21:28 +00:00
// Do the same for regular cache
2015-11-13 23:11:05 +00:00
WC_Cache_Helper :: incr_cache_prefix ( 'orders' );
2015-11-05 15:21:28 +00:00
2014-02-26 15:43:19 +00:00
do_action ( 'woocommerce_delete_shop_order_transients' , $post_id );
}
2014-06-17 20:39:02 +00:00
/**
2015-11-03 13:31:20 +00:00
* See if we only ship to billing addresses .
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
* @ param array $args
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 (
2014-07-24 14:34:14 +00:00
'amount' => '' ,
'reason' => null ,
'order_id' => 0 ,
'refund_id' => 0 ,
2015-05-15 15:27:11 +00:00
'line_items' => array (),
'date' => current_time ( 'mysql' , 0 )
2014-07-08 14:32:47 +00:00
);
$args = wp_parse_args ( $args , $default_args );
$refund_data = array ();
2015-06-15 20:20:31 +00:00
// prevent negative refunds
if ( 0 > $args [ 'amount' ] ) {
$args [ 'amount' ] = 0 ;
}
2014-07-08 14:32:47 +00:00
if ( $args [ 'refund_id' ] > 0 ) {
$updating = true ;
$refund_data [ 'ID' ] = $args [ 'refund_id' ];
} else {
$updating = false ;
2014-07-11 11:43:42 +00:00
$refund_data [ 'post_type' ] = 'shop_order_refund' ;
2014-07-24 14:34:14 +00:00
$refund_data [ 'post_status' ] = 'wc-completed' ;
2014-07-08 14:32:47 +00:00
$refund_data [ 'ping_status' ] = 'closed' ;
2014-10-23 10:36:12 +00:00
$refund_data [ 'post_author' ] = get_current_user_id () ? get_current_user_id () : 1 ;
2014-07-08 14:32:47 +00:00
$refund_data [ 'post_password' ] = uniqid ( 'refund_' );
$refund_data [ 'post_parent' ] = absint ( $args [ 'order_id' ] );
$refund_data [ 'post_title' ] = sprintf ( __ ( 'Refund – %s' , 'woocommerce' ), strftime ( _x ( '%b %d, %Y @ %I:%M %p' , 'Order date parsed by strftime' , 'woocommerce' ) ) );
2015-05-15 15:27:11 +00:00
$refund_data [ 'post_date' ] = $args [ 'date' ];
2014-07-08 14:32:47 +00:00
}
if ( ! is_null ( $args [ 'reason' ] ) ) {
$refund_data [ 'post_excerpt' ] = $args [ 'reason' ];
}
if ( $updating ) {
$refund_id = wp_update_post ( $refund_data );
} else {
$refund_id = wp_insert_post ( apply_filters ( 'woocommerce_new_refund_data' , $refund_data ), true );
}
if ( is_wp_error ( $refund_id ) ) {
return $refund_id ;
}
2014-07-23 16:56:43 +00:00
2014-07-08 14:32:47 +00:00
if ( ! $updating ) {
2014-07-23 16:41:35 +00:00
// Default refund meta data
2014-07-08 14:32:47 +00:00
update_post_meta ( $refund_id , '_refund_amount' , wc_format_decimal ( $args [ 'amount' ] ) );
2014-10-06 12:39:49 +00:00
// Get refund object
$refund = wc_get_order ( $refund_id );
2015-06-04 07:55:24 +00:00
$order = wc_get_order ( $args [ 'order_id' ] );
// Refund currency is the same used for the parent order
update_post_meta ( $refund_id , '_order_currency' , $order -> get_order_currency () );
2014-10-06 12:39:49 +00:00
2014-07-23 16:41:35 +00:00
// Negative line items
2014-07-24 14:34:14 +00:00
if ( sizeof ( $args [ 'line_items' ] ) > 0 ) {
$order_items = $order -> get_items ( array ( 'line_item' , 'fee' , 'shipping' ) );
2014-07-23 16:41:35 +00:00
2014-07-24 14:34:14 +00:00
foreach ( $args [ 'line_items' ] as $refund_item_id => $refund_item ) {
if ( isset ( $order_items [ $refund_item_id ] ) ) {
if ( empty ( $refund_item [ 'qty' ] ) && empty ( $refund_item [ 'refund_total' ] ) && empty ( $refund_item [ 'refund_tax' ] ) ) {
continue ;
}
2014-07-28 13:59:55 +00:00
// Prevents errors when the order has no taxes
if ( ! isset ( $refund_item [ 'refund_tax' ] ) ) {
$refund_item [ 'refund_tax' ] = array ();
}
2014-07-24 14:34:14 +00:00
switch ( $order_items [ $refund_item_id ][ 'type' ] ) {
case 'line_item' :
2014-10-06 12:39:49 +00:00
$line_item_args = array (
2014-07-24 14:34:14 +00:00
'totals' => array (
'subtotal' => wc_format_refund_total ( $refund_item [ 'refund_total' ] ),
'total' => wc_format_refund_total ( $refund_item [ 'refund_total' ] ),
'subtotal_tax' => wc_format_refund_total ( array_sum ( $refund_item [ 'refund_tax' ] ) ),
'tax' => wc_format_refund_total ( array_sum ( $refund_item [ 'refund_tax' ] ) ),
'tax_data' => array ( 'total' => array_map ( 'wc_format_refund_total' , $refund_item [ 'refund_tax' ] ), 'subtotal' => array_map ( 'wc_format_refund_total' , $refund_item [ 'refund_tax' ] ) )
)
);
2016-01-22 16:28:29 +00:00
$new_item_id = $refund -> add_product ( $order -> get_product_from_item ( $order_items [ $refund_item_id ] ), isset ( $refund_item [ 'qty' ] ) ? $refund_item [ 'qty' ] * - 1 : 0 , $line_item_args );
2014-07-25 15:48:19 +00:00
wc_add_order_item_meta ( $new_item_id , '_refunded_item_id' , $refund_item_id );
2014-07-24 14:34:14 +00:00
break ;
case 'shipping' :
2016-04-29 10:44:28 +00:00
$shipping = new WC_Shipping_Rate ( $order_items [ $refund_item_id ][ 'method_id' ], $order_items [ $refund_item_id ][ 'name' ], wc_format_refund_total ( $refund_item [ 'refund_total' ] ), array_map ( 'wc_format_refund_total' , $refund_item [ 'refund_tax' ] ), $order_items [ $refund_item_id ][ 'method_id' ] );
2014-07-25 15:48:19 +00:00
$new_item_id = $refund -> add_shipping ( $shipping );
wc_add_order_item_meta ( $new_item_id , '_refunded_item_id' , $refund_item_id );
2014-07-24 14:34:14 +00:00
break ;
case 'fee' :
$fee = new stdClass ();
$fee -> name = $order_items [ $refund_item_id ][ 'name' ];
$fee -> tax_class = $order_items [ $refund_item_id ][ 'tax_class' ];
$fee -> taxable = $fee -> tax_class !== '0' ;
$fee -> amount = wc_format_refund_total ( $refund_item [ 'refund_total' ] );
$fee -> tax = wc_format_refund_total ( array_sum ( $refund_item [ 'refund_tax' ] ) );
$fee -> tax_data = array_map ( 'wc_format_refund_total' , $refund_item [ 'refund_tax' ] );
2014-07-28 13:59:55 +00:00
2014-07-25 15:48:19 +00:00
$new_item_id = $refund -> add_fee ( $fee );
wc_add_order_item_meta ( $new_item_id , '_refunded_item_id' , $refund_item_id );
2014-07-24 14:34:14 +00:00
break ;
}
2014-07-23 16:41:35 +00:00
}
}
2014-07-24 14:34:14 +00:00
$refund -> update_taxes ();
2014-07-23 16:41:35 +00:00
}
2014-10-06 12:39:49 +00:00
$refund -> calculate_totals ( false );
// Set total to total refunded which may vary from order items
$refund -> set_total ( wc_format_decimal ( $args [ 'amount' ] ) * - 1 , 'total' );
2014-10-07 22:58:21 +00:00
2015-06-22 15:54:45 +00:00
do_action ( 'woocommerce_refund_created' , $refund_id , $args );
2014-07-23 16:41:35 +00:00
}
2014-07-23 16:56:43 +00:00
2014-10-06 12:39:49 +00:00
// Clear transients
wc_delete_shop_order_transients ( $args [ 'order_id' ] );
2014-07-08 14:32:47 +00:00
return new WC_Order_Refund ( $refund_id );
}
2014-07-19 04:08:02 +00:00
/**
* Get tax class by tax id .
*
* @ since 2.2
* @ param int $tax_id
* @ return string
*/
function wc_get_tax_class_by_tax_id ( $tax_id ) {
global $wpdb ;
$tax_class = $wpdb -> get_var ( $wpdb -> prepare ( " SELECT tax_rate_class FROM { $wpdb -> prefix } woocommerce_tax_rates WHERE tax_rate_id = %d " , $tax_id ) );
return wc_clean ( $tax_class );
}
2014-07-22 15:13:35 +00:00
/**
* Get payment gateway class by order data .
*
* @ since 2.2
* @ param int | WC_Order $order
* @ return WC_Payment_Gateway | bool
*/
function wc_get_payment_gateway_by_order ( $order ) {
if ( WC () -> payment_gateways () ) {
$payment_gateways = WC () -> payment_gateways -> payment_gateways ();
} 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
}
return isset ( $payment_gateways [ $order -> payment_method ] ) ? $payment_gateways [ $order -> payment_method ] : false ;
}
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
* @ param int $order_id
*/
function wc_order_fully_refunded ( $order_id ) {
$order = wc_get_order ( $order_id );
$max_refund = wc_format_decimal ( $order -> get_total () - $order -> get_total_refunded () );
if ( ! $max_refund ) {
return ;
}
// Create the refund object
2016-06-06 17:57:24 +00:00
wc_create_refund ( array (
2015-04-24 14:58:13 +00:00
'amount' => $max_refund ,
'reason' => __ ( 'Order Fully Refunded' , 'woocommerce' ),
'order_id' => $order_id ,
'line_items' => array ()
) );
wc_delete_shop_order_transients ( $order_id );
}
add_action ( 'woocommerce_order_status_refunded' , 'wc_order_fully_refunded' );
2016-06-13 13:42:10 +00:00
/**
* Search in orders .
*
* @ since 2.6 . 0
* @ param string $term Term to search .
* @ return array List of orders ID .
*/
function wc_order_search ( $term ) {
global $wpdb ;
$term = str_replace ( 'Order #' , '' , wc_clean ( $term ) );
2016-06-13 18:26:14 +00:00
$post_ids = array ();
2016-06-13 13:42:10 +00:00
// Search fields.
$search_fields = array_map ( 'wc_clean' , apply_filters ( 'woocommerce_shop_order_search_fields' , array (
'_order_key' ,
'_billing_company' ,
'_billing_address_1' ,
'_billing_address_2' ,
'_billing_city' ,
'_billing_postcode' ,
'_billing_country' ,
'_billing_state' ,
'_billing_email' ,
'_billing_phone' ,
'_shipping_address_1' ,
'_shipping_address_2' ,
'_shipping_city' ,
'_shipping_postcode' ,
'_shipping_country' ,
'_shipping_state'
) ) );
// Search orders.
if ( is_numeric ( $term ) ) {
$post_ids = array_unique ( array_merge (
$wpdb -> get_col (
$wpdb -> prepare ( " SELECT DISTINCT p1.post_id FROM { $wpdb -> postmeta } p1 WHERE p1.meta_key IN (' " . implode ( " ',' " , array_map ( 'esc_sql' , $search_fields ) ) . " ') AND p1.meta_value LIKE '%%%d%%'; " , absint ( $term ) )
),
array ( absint ( $term ) )
) );
} elseif ( ! empty ( $search_fields ) ) {
$post_ids = array_unique ( array_merge (
$wpdb -> get_col (
$wpdb -> prepare ( "
SELECT DISTINCT p1 . post_id
FROM { $wpdb -> postmeta } p1
INNER JOIN { $wpdb -> postmeta } p2 ON p1 . post_id = p2 . post_id
WHERE
( p1 . meta_key = '_billing_first_name' AND p2 . meta_key = '_billing_last_name' AND CONCAT ( p1 . meta_value , ' ' , p2 . meta_value ) LIKE '%%%s%%' )
OR
( p1 . meta_key = '_shipping_first_name' AND p2 . meta_key = '_shipping_last_name' AND CONCAT ( p1 . meta_value , ' ' , p2 . meta_value ) LIKE '%%%s%%' )
OR
( p1 . meta_key IN ( '" . implode( "' , '", array_map( ' esc_sql ', $search_fields ) ) . "' ) AND p1 . meta_value LIKE '%%%s%%' )
" ,
$term , $term , $term
)
),
$wpdb -> get_col (
$wpdb -> prepare ( "
SELECT order_id
FROM { $wpdb -> prefix } woocommerce_order_items as order_items
WHERE order_item_name LIKE '%%%s%%'
" ,
$term
)
)
) );
}
return $post_ids ;
}