1 <?php
  2 /**
  3  * WooCommerce Order Functions
  4  *
  5  * Functions for order specific things.
  6  *
  7  * @author      WooThemes
  8  * @category    Core
  9  * @package     WooCommerce/Functions
 10  * @version     2.1.0
 11  */
 12 
 13 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
 14 
 15 /**
 16  * Finds an Order ID based on an order key.
 17  *
 18  * @access public
 19  * @param string $order_key An order key has generated by
 20  * @return int The ID of an order, or 0 if the order could not be found
 21  */
 22 function wc_get_order_id_by_order_key( $order_key ) {
 23     global $wpdb;
 24 
 25     // Faster than get_posts()
 26     $order_id = $wpdb->get_var( "SELECT post_id FROM {$wpdb->prefix}postmeta WHERE meta_key = '_order_key' AND meta_value = '{$order_key}'" );
 27 
 28     return $order_id;
 29 }
 30 
 31 /**
 32  * Grant downloadable product access to the file identified by $download_id
 33  *
 34  * @access public
 35  * @param string $download_id file identifier
 36  * @param int $product_id product identifier
 37  * @param WC_Order $order the order
 38  * @return int|bool insert id or false on failure
 39  */
 40 function wc_downloadable_file_permission( $download_id, $product_id, $order ) {
 41     global $wpdb;
 42 
 43     $user_email = sanitize_email( $order->billing_email );
 44     $limit      = trim( get_post_meta( $product_id, '_download_limit', true ) );
 45     $expiry     = trim( get_post_meta( $product_id, '_download_expiry', true ) );
 46 
 47     $limit      = empty( $limit ) ? '' : absint( $limit );
 48 
 49     // Default value is NULL in the table schema
 50     $expiry     = empty( $expiry ) ? null : absint( $expiry );
 51 
 52     if ( $expiry ) {
 53         $order_completed_date = date_i18n( "Y-m-d", strtotime( $order->completed_date ) );
 54         $expiry = date_i18n( "Y-m-d", strtotime( $order_completed_date . ' + ' . $expiry . ' DAY' ) );
 55     }
 56 
 57     $data = apply_filters( 'woocommerce_downloadable_file_permission_data', array(
 58         'download_id'           => $download_id,
 59         'product_id'            => $product_id,
 60         'user_id'               => absint( $order->user_id ),
 61         'user_email'            => $user_email,
 62         'order_id'              => $order->id,
 63         'order_key'             => $order->order_key,
 64         'downloads_remaining'   => $limit,
 65         'access_granted'        => current_time( 'mysql' ),
 66         'download_count'        => 0
 67     ));
 68 
 69     $format = apply_filters( 'woocommerce_downloadable_file_permission_format', array(
 70         '%s',
 71         '%s',
 72         '%s',
 73         '%s',
 74         '%s',
 75         '%s',
 76         '%s',
 77         '%s',
 78         '%d'
 79     ), $data);
 80 
 81     if ( ! is_null( $expiry ) ) {
 82             $data['access_expires'] = $expiry;
 83             $format[] = '%s';
 84     }
 85 
 86     // Downloadable product - give access to the customer
 87     $result = $wpdb->insert( $wpdb->prefix . 'woocommerce_downloadable_product_permissions',
 88         $data,
 89         $format
 90     );
 91 
 92     do_action( 'woocommerce_grant_product_download_access', $data );
 93 
 94     return $result ? $wpdb->insert_id : false;
 95 }
 96 
 97 /**
 98  * Order Status completed - GIVE DOWNLOADABLE PRODUCT ACCESS TO CUSTOMER
 99  *
100  * @access public
101  * @param int $order_id
102  * @return void
103  */
104 function wc_downloadable_product_permissions( $order_id ) {
105     if ( get_post_meta( $order_id, '_download_permissions_granted', true ) == 1 ) {
106         return; // Only do this once
107     }
108 
109     $order = new WC_Order( $order_id );
110 
111     if ( $order->status == 'processing' && get_option( 'woocommerce_downloads_grant_access_after_payment' ) == 'no' ) {
112         return;
113     }
114 
115     if ( sizeof( $order->get_items() ) > 0 ) {
116         foreach ( $order->get_items() as $item ) {
117             $_product = $order->get_product_from_item( $item );
118 
119             if ( $_product && $_product->exists() && $_product->is_downloadable() ) {
120                 $downloads = $_product->get_files();
121 
122                 foreach ( array_keys( $downloads ) as $download_id ) {
123                     wc_downloadable_file_permission( $download_id, $item['variation_id'] > 0 ? $item['variation_id'] : $item['product_id'], $order );
124                 }
125             }
126         }
127     }
128 
129     update_post_meta( $order_id, '_download_permissions_granted', 1 );
130 
131     do_action( 'woocommerce_grant_product_download_permissions', $order_id );
132 }
133 
134 add_action( 'woocommerce_order_status_completed', 'wc_downloadable_product_permissions' );
135 add_action( 'woocommerce_order_status_processing', 'wc_downloadable_product_permissions' );
136 
137 
138 /**
139  * Add a item to an order (for example a line item).
140  *
141  * @access public
142  * @param int $order_id
143  * @param array $data
144  * @return mixed
145  */
146 function wc_add_order_item( $order_id, $item ) {
147     global $wpdb;
148 
149     $order_id = absint( $order_id );
150 
151     if ( ! $order_id )
152         return false;
153 
154     $defaults = array(
155         'order_item_name'       => '',
156         'order_item_type'       => 'line_item',
157     );
158 
159     $item = wp_parse_args( $item, $defaults );
160 
161     $wpdb->insert(
162         $wpdb->prefix . "woocommerce_order_items",
163         array(
164             'order_item_name'       => $item['order_item_name'],
165             'order_item_type'       => $item['order_item_type'],
166             'order_id'              => $order_id
167         ),
168         array(
169             '%s', '%s', '%d'
170         )
171     );
172 
173     $item_id = absint( $wpdb->insert_id );
174 
175     do_action( 'woocommerce_new_order_item', $item_id, $item, $order_id );
176 
177     return $item_id;
178 }
179 
180 /**
181  * Delete an item from the order it belongs to based on item id
182  *
183  * @access public
184  * @param int $item_id
185  * @return bool
186  */
187 function wc_delete_order_item( $item_id ) {
188     global $wpdb;
189 
190     $item_id = absint( $item_id );
191 
192     if ( ! $item_id )
193         return false;
194 
195     do_action( 'woocommerce_before_delete_order_item', $item_id );
196 
197     $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_item_id = %d", $item_id ) );
198     $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id = %d", $item_id ) );
199 
200     do_action( 'woocommerce_delete_order_item', $item_id );
201 
202     return true;
203 }
204 
205 /**
206  * WooCommerce Order Item Meta API - Update term meta
207  *
208  * @access public
209  * @param mixed $item_id
210  * @param mixed $meta_key
211  * @param mixed $meta_value
212  * @param string $prev_value (default: '')
213  * @return bool
214  */
215 function wc_update_order_item_meta( $item_id, $meta_key, $meta_value, $prev_value = '' ) {
216     return update_metadata( 'order_item', $item_id, $meta_key, $meta_value, $prev_value );
217 }
218 
219 /**
220  * WooCommerce Order Item Meta API - Add term meta
221  *
222  * @access public
223  * @param mixed $item_id
224  * @param mixed $meta_key
225  * @param mixed $meta_value
226  * @param bool $unique (default: false)
227  * @return bool
228  */
229 function wc_add_order_item_meta( $item_id, $meta_key, $meta_value, $unique = false ) {
230     return add_metadata( 'order_item', $item_id, $meta_key, $meta_value, $unique );
231 }
232 
233 /**
234  * WooCommerce Order Item Meta API - Delete term meta
235  *
236  * @access public
237  * @param mixed $item_id
238  * @param mixed $meta_key
239  * @param string $meta_value (default: '')
240  * @param bool $delete_all (default: false)
241  * @return bool
242  */
243 function wc_delete_order_item_meta( $item_id, $meta_key, $meta_value = '', $delete_all = false ) {
244     return delete_metadata( 'order_item', $item_id, $meta_key, $meta_value, $delete_all );
245 }
246 
247 /**
248  * WooCommerce Order Item Meta API - Get term meta
249  *
250  * @access public
251  * @param mixed $item_id
252  * @param mixed $key
253  * @param bool $single (default: true)
254  * @return mixed
255  */
256 function wc_get_order_item_meta( $item_id, $key, $single = true ) {
257     return get_metadata( 'order_item', $item_id, $key, $single );
258 }
259 
260 /**
261  * Cancel all unpaid orders after held duration to prevent stock lock for those products
262  *
263  * @access public
264  * @return void
265  */
266 function wc_cancel_unpaid_orders() {
267     global $wpdb;
268 
269     $held_duration = get_option( 'woocommerce_hold_stock_minutes' );
270 
271     if ( $held_duration < 1 || get_option( 'woocommerce_manage_stock' ) != 'yes' )
272         return;
273 
274     $date = date( "Y-m-d H:i:s", strtotime( '-' . absint( $held_duration ) . ' MINUTES', current_time( 'timestamp' ) ) );
275 
276     $unpaid_orders = $wpdb->get_col( $wpdb->prepare( "
277         SELECT posts.ID
278         FROM {$wpdb->posts} AS posts
279         LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID=rel.object_ID
280         LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
281         LEFT JOIN {$wpdb->terms} AS term USING( term_id )
282 
283         WHERE   posts.post_type   = 'shop_order'
284         AND     posts.post_status = 'publish'
285         AND     tax.taxonomy      = 'shop_order_status'
286         AND     term.slug         = 'pending'
287         AND     posts.post_modified < %s
288     ", $date ) );
289 
290     if ( $unpaid_orders ) {
291         foreach ( $unpaid_orders as $unpaid_order ) {
292             $order = new WC_Order( $unpaid_order );
293 
294             if ( apply_filters( 'woocommerce_cancel_unpaid_order', true, $order ) )
295                 $order->update_status( 'cancelled', __( 'Unpaid order cancelled - time limit reached.', 'woocommerce' ) );
296         }
297     }
298 
299     wp_clear_scheduled_hook( 'woocommerce_cancel_unpaid_orders' );
300     wp_schedule_single_event( time() + ( absint( $held_duration ) * 60 ), 'woocommerce_cancel_unpaid_orders' );
301 }
302 add_action( 'woocommerce_cancel_unpaid_orders', 'wc_cancel_unpaid_orders' );
303 
304 
305 /**
306  * Return the count of processing orders.
307  *
308  * @access public
309  * @return int
310  */
311 function wc_processing_order_count() {
312     if ( false === ( $order_count = get_transient( 'woocommerce_processing_order_count' ) ) ) {
313         $order_statuses = get_terms( 'shop_order_status' );
314         $order_count    = false;
315         if ( is_array( $order_statuses ) ) {
316             foreach ( $order_statuses as $status ) {
317                     if ( $status->slug === 'processing' ) {
318                             $order_count += $status->count;
319                             break;
320                     }
321             }
322             $order_count = apply_filters( 'woocommerce_admin_menu_count', intval( $order_count ) );
323             set_transient( 'woocommerce_processing_order_count', $order_count, YEAR_IN_SECONDS );
324         }
325     }
326 
327     return $order_count;
328 }
329 
330 /**
331  * Clear all transients cache for order data.
332  *
333  * @param int $post_id (default: 0)
334  */
335 function wc_delete_shop_order_transients( $post_id = 0 ) {
336     global $wpdb;
337 
338     $post_id = absint( $post_id );
339 
340     // Clear core transients
341     $transients_to_clear = array(
342         'woocommerce_processing_order_count'
343     );
344 
345     // Clear report transients
346     $reports = WC_Admin_Reports::get_reports();
347 
348     foreach ( $reports as $report_group ) {
349         foreach ( $report_group['reports'] as $report_key => $report ) {
350             $transients_to_clear[] = 'wc_report_' . $report_key;
351         }
352     }
353 
354     // clear API report transient
355     $transients_to_clear[] = 'wc_admin_report';
356 
357     // Clear transients where we have names
358     foreach( $transients_to_clear as $transient ) {
359         delete_transient( $transient );
360     }
361 
362     do_action( 'woocommerce_delete_shop_order_transients', $post_id );
363 }
364 
WooCommerce API documentation generated by ApiGen 2.8.0