1 <?php
  2 /**
  3  * Admin functions for the shop order post type
  4  *
  5  * @author      WooThemes
  6  * @category    Admin
  7  * @package     WooCommerce/Admin/Post Types
  8  * @version     2.1.0
  9  */
 10 
 11 // Exit if accessed directly
 12 if ( ! defined( 'ABSPATH' ) ) {
 13     exit;
 14 }
 15 
 16 if ( ! class_exists( 'WC_Admin_CPT' ) ) {
 17     include( 'class-wc-admin-cpt.php' );
 18 }
 19 
 20 if ( ! class_exists( 'WC_Admin_CPT_Shop_Order' ) ) :
 21 
 22 /**
 23  * WC_Admin_CPT_Shop_Order Class
 24  */
 25 class WC_Admin_CPT_Shop_Order extends WC_Admin_CPT {
 26 
 27     /**
 28      * Constructor
 29      */
 30     public function __construct() {
 31         $this->type = 'shop_order';
 32 
 33         // Before data updates
 34         add_filter( 'wp_insert_post_data', array( $this, 'wp_insert_post_data' ) );
 35 
 36         // Admin Columns
 37         add_filter( 'manage_edit-' . $this->type . '_columns', array( $this, 'edit_columns' ) );
 38         add_action( 'manage_' . $this->type . '_posts_custom_column', array( $this, 'custom_columns' ), 2 );
 39 
 40         // Views and filtering
 41         add_filter( 'views_edit-shop_order', array( $this, 'custom_order_views' ) );
 42         add_filter( 'bulk_actions-edit-shop_order', array( $this, 'bulk_actions' ) );
 43         add_filter( 'post_row_actions', array( $this, 'remove_row_actions' ), 10, 1 );
 44         add_action( 'restrict_manage_posts', array( $this, 'restrict_manage_orders' ) );
 45         add_filter( 'request', array( $this, 'orders_by_customer_query' ) );
 46         add_filter( "manage_edit-shop_order_sortable_columns", array( $this, 'custom_shop_order_sort' ) );
 47         add_filter( 'request', array( $this, 'custom_shop_order_orderby' ) );
 48         add_filter( 'get_search_query', array( $this, 'shop_order_search_label' ) );
 49         add_filter( 'query_vars', array( $this, 'add_custom_query_var' ) );
 50         add_action( 'parse_query', array( $this, 'shop_order_search_custom_fields' ) );
 51         add_action( 'before_delete_post', array( $this, 'delete_order_items' ) );
 52 
 53         // Bulk edit
 54         add_action( 'admin_footer', array( $this, 'bulk_admin_footer' ), 10 );
 55         add_action( 'load-edit.php', array( $this, 'bulk_action' ) );
 56         add_action( 'admin_notices', array( $this, 'bulk_admin_notices' ) );
 57 
 58         // Call WC_Admin_CPT constructor
 59         parent::__construct();
 60     }
 61 
 62     /**
 63      * Forces the order posts to have a title in a certain format (containing the date)
 64      *
 65      * @param array $data
 66      * @return array
 67      */
 68     public function wp_insert_post_data( $data ) {
 69         global $post;
 70 
 71         if ( $data['post_type'] == 'shop_order' && isset( $data['post_date'] ) ) {
 72 
 73             $order_title = 'Order';
 74             if ( $data['post_date'] ) {
 75                 $order_title.= ' &ndash; ' . date_i18n( 'F j, Y @ h:i A', strtotime( $data['post_date'] ) );
 76             }
 77 
 78             $data['post_title'] = $order_title;
 79         }
 80 
 81         return $data;
 82     }
 83 
 84     /**
 85      * Change the columns shown in admin.
 86      */
 87     public function edit_columns( $existing_columns ) {
 88         $columns = array();
 89 
 90         $columns['cb']               = '<input type="checkbox" />';
 91         $columns['order_status']     = '<span class="status_head tips" data-tip="' . esc_attr__( 'Status', 'woocommerce' ) . '">' . esc_attr__( 'Status', 'woocommerce' ) . '</span>';
 92         $columns['order_title']      = __( 'Order', 'woocommerce' );
 93         $columns['order_items']      = __( 'Purchased', 'woocommerce' );
 94         $columns['shipping_address'] = __( 'Ship to', 'woocommerce' );
 95 
 96         $columns['customer_message'] = '<span class="notes_head tips" data-tip="' . esc_attr__( 'Customer Message', 'woocommerce' ) . '">' . esc_attr__( 'Customer Message', 'woocommerce' ) . '</span>';
 97         $columns['order_notes']      = '<span class="order-notes_head tips" data-tip="' . esc_attr__( 'Order Notes', 'woocommerce' ) . '">' . esc_attr__( 'Order Notes', 'woocommerce' ) . '</span>';
 98         $columns['order_date']       = __( 'Date', 'woocommerce' );
 99         $columns['order_total']      = __( 'Total', 'woocommerce' );
100         $columns['order_actions']    = __( 'Actions', 'woocommerce' );
101 
102         return $columns;
103     }
104 
105     /**
106      * Define our custom columns shown in admin.
107      * @param  string $column
108      */
109     public function custom_columns( $column ) {
110         global $post, $woocommerce, $the_order;
111 
112         if ( empty( $the_order ) || $the_order->id != $post->ID ) {
113             $the_order = new WC_Order( $post->ID );
114         }
115 
116         switch ( $column ) {
117             case 'order_status' :
118 
119                 printf( '<mark class="%s tips" data-tip="%s">%s</mark>', sanitize_title( $the_order->status ), esc_html__( $the_order->status, 'woocommerce' ), esc_html__( $the_order->status, 'woocommerce' ) );
120 
121             break;
122             case 'order_date' :
123 
124                 if ( '0000-00-00 00:00:00' == $post->post_date ) {
125                     $t_time = $h_time = __( 'Unpublished', 'woocommerce' );
126                 } else {
127                     $t_time    = get_the_time( __( 'Y/m/d g:i:s A', 'woocommerce' ), $post );
128                     $gmt_time  = strtotime( $post->post_date_gmt . ' UTC' );
129                     $time_diff = current_time( 'timestamp', 1 ) - $gmt_time;
130                     $h_time    = get_the_time( __( 'Y/m/d', 'woocommerce' ), $post );
131                 }
132 
133                 echo '<abbr title="' . esc_attr( $t_time ) . '">' . esc_html( apply_filters( 'post_date_column_time', $h_time, $post ) ) . '</abbr>';
134 
135             break;
136             case 'customer_message' :
137 
138                 if ( $the_order->customer_message )
139                     echo '<span class="note-on tips" data-tip="' . esc_attr( $the_order->customer_message ) . '">' . __( 'Yes', 'woocommerce' ) . '</span>';
140                 else
141                     echo '<span class="na">&ndash;</span>';
142 
143             break;
144             case 'billing_address' :
145                 if ( $the_order->get_formatted_billing_address() )
146                     echo '<a target="_blank" href="' . esc_url( 'http://maps.google.com/maps?&q=' . urlencode( $the_order->get_billing_address() ) . '&z=16' ) . '">' . esc_html( preg_replace( '#<br\s*/?>#i', ', ', $the_order->get_formatted_billing_address() ) ) .'</a>';
147                 else
148                     echo '&ndash;';
149 
150                 if ( $the_order->payment_method_title )
151                     echo '<small class="meta">' . __( 'Via', 'woocommerce' ) . ' ' . esc_html( $the_order->payment_method_title ) . '</small>';
152             break;
153             case 'order_items' :
154 
155                 printf( '<a href="#" class="show_order_items">' . _n( '%d item', '%d items', sizeof( $the_order->get_items() ), 'woocommerce' ) . '</a>', sizeof( $the_order->get_items() ) );
156 
157                 if ( sizeof( $the_order->get_items() ) > 0 ) {
158 
159                     echo '<table class="order_items" cellspacing="0">';
160 
161                     foreach ( $the_order->get_items() as $item ) {
162                         $_product       = apply_filters( 'woocommerce_order_item_product', $the_order->get_product_from_item( $item ), $item );
163                         $item_meta      = new WC_Order_Item_Meta( $item['item_meta'] );
164                         $item_meta_html = $item_meta->display( true, true );
165                         ?>
166                         <tr>
167                             <td class="qty"><?php echo absint( $item['qty'] ); ?></td>
168                             <td class="name">
169                                 <?php if ( wc_product_sku_enabled() && $_product && $_product->get_sku() ) echo $_product->get_sku() . ' - '; ?><?php echo apply_filters( 'woocommerce_order_item_name', $item['name'], $item ); ?>
170                                 <?php if ( $item_meta_html ) : ?>
171                                     <a class="tips" href="#" data-tip="<?php echo esc_attr( $item_meta_html ); ?>">[?]</a>
172                                 <?php endif; ?>
173                             </td>
174                         </tr>
175                         <?php
176                     }
177 
178                     echo '</table>';
179 
180                 } else echo '&ndash;';
181             break;
182             case 'shipping_address' :
183                 if ( $the_order->get_formatted_shipping_address() )
184                     echo '<a target="_blank" href="' . esc_url( 'http://maps.google.com/maps?&q=' . urlencode( $the_order->get_shipping_address() ) . '&z=16' ) . '">'. esc_html( preg_replace( '#<br\s*/?>#i', ', ', $the_order->get_formatted_shipping_address() ) ) .'</a>';
185                 else
186                     echo '&ndash;';
187 
188                 if ( $the_order->get_shipping_method() )
189                     echo '<small class="meta">' . __( 'Via', 'woocommerce' ) . ' ' . esc_html( $the_order->get_shipping_method() ) . '</small>';
190 
191             break;
192             case 'order_notes' :
193 
194                 if ( $post->comment_count ) {
195 
196                     // check the status of the post
197                     ( $post->post_status !== 'trash' ) ? $status = '' : $status = 'post-trashed';
198 
199                     $latest_notes = get_comments( array(
200                         'post_id'   => $post->ID,
201                         'number'    => 1,
202                         'status'    => $status
203                     ) );
204 
205                     $latest_note = current( $latest_notes );
206 
207                     if ( $post->comment_count == 1 ) {
208                         echo '<span class="note-on tips" data-tip="' . esc_attr( $latest_note->comment_content ) . '">' . __( 'Yes', 'woocommerce' ) . '</span>';
209                     } else {
210                         $note_tip = isset( $latest_note->comment_content ) ? esc_attr( $latest_note->comment_content . '<small style="display:block">' . sprintf( _n( 'plus %d other note', 'plus %d other notes', ( $post->comment_count - 1 ), 'woocommerce' ), ( $post->comment_count - 1 ) ) . '</small>' ) : sprintf( _n( '%d note', '%d notes', $post->comment_count, 'woocommerce' ), $post->comment_count );
211 
212                         echo '<span class="note-on tips" data-tip="' . $note_tip . '">' . __( 'Yes', 'woocommerce' ) . '</span>';
213                     }
214 
215                 } else {
216                     echo '<span class="na">&ndash;</span>';
217                 }
218 
219             break;
220             case 'order_total' :
221                 echo esc_html( strip_tags( $the_order->get_formatted_order_total() ) );
222 
223                 if ( $the_order->payment_method_title ) {
224                     echo '<small class="meta">' . __( 'Via', 'woocommerce' ) . ' ' . esc_html( $the_order->payment_method_title ) . '</small>';
225                 }
226             break;
227             case 'order_title' :
228 
229                 $customer_tip = '';
230 
231                 if ( $address = $the_order->get_formatted_billing_address() ) {
232                     $customer_tip .= __( 'Billing:', 'woocommerce' ) . ' ' . $address . '<br/><br/>';
233                 }
234 
235                 if ( $the_order->billing_phone ) {
236                     $customer_tip .= __( 'Tel:', 'woocommerce' ) . ' ' . $the_order->billing_phone;
237                 }
238 
239                 echo '<div class="tips" data-tip="' . esc_attr( $customer_tip ) . '">';
240 
241                 if ( $the_order->user_id ) {
242                     $user_info = get_userdata( $the_order->user_id );
243                 }
244 
245                 if ( ! empty( $user_info ) ) {
246 
247                     $username = '<a href="user-edit.php?user_id=' . absint( $user_info->ID ) . '">';
248 
249                     if ( $user_info->first_name || $user_info->last_name ) {
250                         $username .= esc_html( ucfirst( $user_info->first_name ) . ' ' . ucfirst( $user_info->last_name ) );
251                     } else {
252                         $username .= esc_html( ucfirst( $user_info->display_name ) );
253                     }
254 
255                     $username .= '</a>';
256 
257                 } else {
258                     if ( $the_order->billing_first_name || $the_order->billing_last_name ) {
259                         $username = trim( $the_order->billing_first_name . ' ' . $the_order->billing_last_name );
260                     } else {
261                         $username = __( 'Guest', 'woocommerce' );
262                     }
263                 }
264 
265                 printf( __( '%s by %s', 'woocommerce' ), '<a href="' . admin_url( 'post.php?post=' . absint( $post->ID ) . '&action=edit' ) . '"><strong>' . esc_attr( $the_order->get_order_number() ) . '</strong></a>', $username );
266 
267                 if ( $the_order->billing_email ) {
268                     echo '<small class="meta email"><a href="' . esc_url( 'mailto:' . $the_order->billing_email ) . '">' . esc_html( $the_order->billing_email ) . '</a></small>';
269                 }
270 
271                 echo '</div>';
272 
273             break;
274             case 'order_actions' :
275 
276                 ?><p>
277                     <?php
278                         do_action( 'woocommerce_admin_order_actions_start', $the_order );
279 
280                         $actions = array();
281 
282                         if ( in_array( $the_order->status, array( 'pending', 'on-hold' ) ) ) {
283                             $actions['processing'] = array(
284                                 'url'       => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_mark_order_processing&order_id=' . $post->ID ), 'woocommerce-mark-order-processing' ),
285                                 'name'      => __( 'Processing', 'woocommerce' ),
286                                 'action'    => "processing"
287                             );
288                         }
289 
290                         if ( in_array( $the_order->status, array( 'pending', 'on-hold', 'processing' ) ) ) {
291                             $actions['complete'] = array(
292                                 'url'       => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_mark_order_complete&order_id=' . $post->ID ), 'woocommerce-mark-order-complete' ),
293                                 'name'      => __( 'Complete', 'woocommerce' ),
294                                 'action'    => "complete"
295                             );
296                         }
297 
298                         $actions['view'] = array(
299                             'url'       => admin_url( 'post.php?post=' . $post->ID . '&action=edit' ),
300                             'name'      => __( 'View', 'woocommerce' ),
301                             'action'    => "view"
302                         );
303 
304                         $actions = apply_filters( 'woocommerce_admin_order_actions', $actions, $the_order );
305 
306                         foreach ( $actions as $action ) {
307                             printf( '<a class="button tips %s" href="%s" data-tip="%s">%s</a>', esc_attr( $action['action'] ), esc_url( $action['url'] ), esc_attr( $action['name'] ), esc_attr( $action['name'] ) );
308                         }
309 
310                         do_action( 'woocommerce_admin_order_actions_end', $the_order );
311                     ?>
312                 </p><?php
313 
314             break;
315 
316         }
317     }
318 
319     /**
320      * Filters for the order page.
321      *
322      * @access public
323      * @param mixed $views
324      * @return array
325      */
326     public function custom_order_views( $views ) {
327 
328         unset( $views['publish'] );
329 
330         if ( isset( $views['trash'] ) ) {
331             $trash = $views['trash'];
332             unset( $views['draft'] );
333             unset( $views['trash'] );
334             $views['trash'] = $trash;
335         }
336 
337         return $views;
338     }
339 
340     /**
341      * Remove edit from the bulk actions.
342      *
343      * @access public
344      * @param mixed $actions
345      * @return array
346      */
347     public function bulk_actions( $actions ) {
348 
349         if ( isset( $actions['edit'] ) ) {
350             unset( $actions['edit'] );
351         }
352 
353         return $actions;
354     }
355 
356     /**
357      * Actions for the orders page.
358      *
359      * @access public
360      * @param mixed $actions
361      * @return array
362      */
363     public function remove_row_actions( $actions ) {
364         if ( 'shop_order' === get_post_type() ) {
365             unset( $actions['view'] );
366             unset( $actions['inline hide-if-no-js'] );
367         }
368 
369         return $actions;
370     }
371 
372     /**
373      * Show custom filters to filter orders by status/customer.
374      *
375      * @access public
376      * @return void
377      */
378     public function restrict_manage_orders() {
379         global $woocommerce, $typenow, $wp_query;
380 
381         if ( 'shop_order' != $typenow ) {
382             return;
383         }
384 
385         // Status
386         ?>
387         <select name='shop_order_status' id='dropdown_shop_order_status'>
388             <option value=""><?php _e( 'Show all statuses', 'woocommerce' ); ?></option>
389             <?php
390                 $terms = get_terms('shop_order_status');
391 
392                 foreach ( $terms as $term ) {
393                     echo '<option value="' . esc_attr( $term->slug ) . '"';
394 
395                     if ( isset( $wp_query->query['shop_order_status'] ) ) {
396                         selected( $term->slug, $wp_query->query['shop_order_status'] );
397                     }
398 
399                     echo '>' . esc_html__( $term->name, 'woocommerce' ) . ' (' . absint( $term->count ) . ')</option>';
400                 }
401             ?>
402             </select>
403         <?php
404 
405         // Customers
406         ?>
407         <select id="dropdown_customers" name="_customer_user">
408             <option value=""><?php _e( 'Show all customers', 'woocommerce' ) ?></option>
409             <?php
410                 if ( ! empty( $_GET['_customer_user'] ) ) {
411                     $user = get_user_by( 'id', absint( $_GET['_customer_user'] ) );
412                     echo '<option value="' . absint( $user->ID ) . '" ';
413                     selected( 1, 1 );
414                     echo '>' . esc_html( $user->display_name ) . ' (#' . absint( $user->ID ) . ' &ndash; ' . esc_html( $user->user_email ) . ')</option>';
415                 }
416             ?>
417         </select>
418         <?php
419 
420         wc_enqueue_js( "
421 
422             jQuery('select#dropdown_shop_order_status, select[name=m]').css('width', '150px').chosen();
423 
424             jQuery('select#dropdown_customers').css('width', '250px').ajaxChosen({
425                 method:         'GET',
426                 url:            '" . admin_url( 'admin-ajax.php' ) . "',
427                 dataType:       'json',
428                 afterTypeDelay: 100,
429                 minTermLength:  1,
430                 data:       {
431                     action:     'woocommerce_json_search_customers',
432                     security:   '" . wp_create_nonce( 'search-customers' ) . "',
433                     default:    '" . __( 'Show all customers', 'woocommerce' ) . "'
434                 }
435             }, function (data) {
436 
437                 var terms = {};
438 
439                 $.each(data, function (i, val) {
440                     terms[i] = val;
441                 });
442 
443                 return terms;
444             });
445         " );
446     }
447 
448     /**
449      * Filter the orders by the posted customer.
450      *
451      * @access public
452      * @param mixed $vars
453      * @return array
454      */
455     public function orders_by_customer_query( $vars ) {
456         global $typenow, $wp_query;
457 
458         if ( $typenow == 'shop_order' && isset( $_GET['_customer_user'] ) && $_GET['_customer_user'] > 0 ) {
459             $vars['meta_key'] = '_customer_user';
460             $vars['meta_value'] = (int) $_GET['_customer_user'];
461         }
462 
463         return $vars;
464     }
465 
466     /**
467      * Make order columns sortable.
468      *
469      * https://gist.github.com/906872
470      *
471      * @access public
472      * @param mixed $columns
473      * @return array
474      */
475     public function custom_shop_order_sort( $columns ) {
476         $custom = array(
477             'order_title'   => 'ID',
478             'order_total'   => 'order_total',
479             'order_date'    => 'date'
480         );
481         unset( $columns['comments'] );
482 
483         return wp_parse_args( $custom, $columns );
484     }
485 
486     /**
487      * Order column orderby/request.
488      *
489      * @access public
490      * @param mixed $vars
491      * @return array
492      */
493     public function custom_shop_order_orderby( $vars ) {
494         global $typenow, $wp_query;
495 
496         if ( 'shop_order' != $typenow ) {
497             return $vars;
498         }
499 
500         // Sorting
501         if ( isset( $vars['orderby'] ) ) {
502             if ( 'order_total' == $vars['orderby'] ) {
503                 $vars = array_merge( $vars, array(
504                     'meta_key'  => '_order_total',
505                     'orderby'   => 'meta_value_num'
506                 ) );
507             }
508         }
509 
510         return $vars;
511     }
512 
513     /**
514      * Search custom fields as well as content.
515      *
516      * @access public
517      * @param WP_Query $wp
518      * @return void
519      */
520     public function shop_order_search_custom_fields( $wp ) {
521         global $pagenow, $wpdb;
522 
523         if ( 'edit.php' != $pagenow || empty( $wp->query_vars['s'] ) || $wp->query_vars['post_type'] != 'shop_order' ) {
524             return;
525         }
526 
527         $search_fields = array_map( 'wc_clean', apply_filters( 'woocommerce_shop_order_search_fields', array(
528             '_order_key',
529             '_billing_company',
530             '_billing_address_1',
531             '_billing_address_2',
532             '_billing_city',
533             '_billing_postcode',
534             '_billing_country',
535             '_billing_state',
536             '_billing_email',
537             '_billing_phone',
538             '_shipping_address_1',
539             '_shipping_address_2',
540             '_shipping_city',
541             '_shipping_postcode',
542             '_shipping_country',
543             '_shipping_state'
544         ) ) );
545 
546         $search_order_id = str_replace( 'Order #', '', $_GET['s'] );
547         if ( ! is_numeric( $search_order_id ) ) {
548             $search_order_id = 0;
549         }
550 
551         // Search orders
552         $post_ids = array_unique( array_merge(
553             $wpdb->get_col(
554                 $wpdb->prepare( "
555                     SELECT p1.post_id
556                     FROM {$wpdb->postmeta} p1
557                     INNER JOIN {$wpdb->postmeta} p2 ON p1.post_id = p2.post_id
558                     WHERE
559                         ( p1.meta_key = '_billing_first_name' AND p2.meta_key = '_billing_last_name' AND CONCAT(p1.meta_value, ' ', p2.meta_value) LIKE '%%%s%%' )
560                     OR
561                         ( p1.meta_key = '_shipping_first_name' AND p2.meta_key = '_shipping_last_name' AND CONCAT(p1.meta_value, ' ', p2.meta_value) LIKE '%%%s%%' )
562                     OR
563                         ( p1.meta_key IN ('" . implode( "','", $search_fields ) . "') AND p1.meta_value LIKE '%%%s%%' )
564                     ",
565                     esc_attr( $_GET['s'] ), esc_attr( $_GET['s'] ), esc_attr( $_GET['s'] )
566                 )
567             ),
568             $wpdb->get_col(
569                 $wpdb->prepare( "
570                     SELECT order_id
571                     FROM {$wpdb->prefix}woocommerce_order_items as order_items
572                     WHERE order_item_name LIKE '%%%s%%'
573                     ",
574                     esc_attr( $_GET['s'] )
575                 )
576             ),
577             array( $search_order_id )
578         ) );
579 
580         // Remove s - we don't want to search order name
581         unset( $wp->query_vars['s'] );
582 
583         // so we know we're doing this
584         $wp->query_vars['shop_order_search'] = true;
585 
586         // Search by found posts
587         $wp->query_vars['post__in'] = $post_ids;
588     }
589 
590     /**
591      * Change the label when searching orders.
592      *
593      * @access public
594      * @param mixed $query
595      * @return string
596      */
597     public function shop_order_search_label( $query ) {
598         global $pagenow, $typenow;
599 
600         if ( 'edit.php' != $pagenow ) {
601             return $query;
602         }
603 
604         if ( $typenow != 'shop_order' ) {
605             return $query;
606         }
607 
608         if ( ! get_query_var( 'shop_order_search' ) ) {
609             return $query;
610         }
611 
612         return wp_unslash( $_GET['s'] );
613     }
614 
615     /**
616      * Query vars for custom searches.
617      *
618      * @access public
619      * @param mixed $public_query_vars
620      * @return array
621      */
622     public function add_custom_query_var( $public_query_vars ) {
623         $public_query_vars[] = 'sku';
624         $public_query_vars[] = 'shop_order_search';
625 
626         return $public_query_vars;
627     }
628 
629     /**
630      * Remove item meta on permanent deletion
631      *
632      * @access public
633      * @return void
634      **/
635     public function delete_order_items( $postid ) {
636         global $wpdb;
637 
638         if ( get_post_type( $postid ) == 'shop_order' ) {
639             do_action( 'woocommerce_delete_order_items', $postid );
640 
641             $wpdb->query( "
642                 DELETE {$wpdb->prefix}woocommerce_order_items, {$wpdb->prefix}woocommerce_order_itemmeta
643                 FROM {$wpdb->prefix}woocommerce_order_items
644                 JOIN {$wpdb->prefix}woocommerce_order_itemmeta ON {$wpdb->prefix}woocommerce_order_items.order_item_id = {$wpdb->prefix}woocommerce_order_itemmeta.order_item_id
645                 WHERE {$wpdb->prefix}woocommerce_order_items.order_id = '{$postid}';
646                 " );
647 
648             do_action( 'woocommerce_deleted_order_items', $postid );
649         }
650     }
651 
652     /**
653      * Add extra bulk action options to mark orders as complete or processing
654      *
655      * Using Javascript until WordPress core fixes: http://core.trac.wordpress.org/ticket/16031
656      *
657      * @access public
658      * @return void
659      */
660     public function bulk_admin_footer() {
661         global $post_type;
662 
663         if ( 'shop_order' == $post_type ) {
664             ?>
665             <script type="text/javascript">
666             jQuery(function() {
667                 jQuery('<option>').val('mark_processing').text('<?php _e( 'Mark processing', 'woocommerce' )?>').appendTo("select[name='action']");
668                 jQuery('<option>').val('mark_processing').text('<?php _e( 'Mark processing', 'woocommerce' )?>').appendTo("select[name='action2']");
669 
670                 jQuery('<option>').val('mark_on-hold').text('<?php _e( 'Mark on-hold', 'woocommerce' )?>').appendTo("select[name='action']");
671                 jQuery('<option>').val('mark_on-hold').text('<?php _e( 'Mark on-hold', 'woocommerce' )?>').appendTo("select[name='action2']");
672 
673                 jQuery('<option>').val('mark_completed').text('<?php _e( 'Mark completed', 'woocommerce' )?>').appendTo("select[name='action']");
674                 jQuery('<option>').val('mark_completed').text('<?php _e( 'Mark completed', 'woocommerce' )?>').appendTo("select[name='action2']");
675             });
676             </script>
677             <?php
678         }
679     }
680 
681     /**
682      * Process the new bulk actions for changing order status
683      *
684      * @access public
685      * @return void
686      */
687     public function bulk_action() {
688         $wp_list_table = _get_list_table( 'WP_Posts_List_Table' );
689         $action = $wp_list_table->current_action();
690 
691         switch ( $action ) {
692             case 'mark_completed':
693                 $new_status = 'completed';
694                 $report_action = 'marked_completed';
695                 break;
696             case 'mark_processing':
697                 $new_status = 'processing';
698                 $report_action = 'marked_processing';
699                 break;
700             case 'mark_on-hold' :
701                 $new_status = 'on-hold';
702                 $report_action = 'marked_on-hold';
703                 break;
704             break;
705             default:
706                 return;
707         }
708 
709         $changed = 0;
710 
711         $post_ids = array_map( 'absint', (array) $_REQUEST['post'] );
712 
713         foreach ( $post_ids as $post_id ) {
714             $order = new WC_Order( $post_id );
715             $order->update_status( $new_status, __( 'Order status changed by bulk edit:', 'woocommerce' ) );
716             $changed++;
717         }
718 
719         $sendback = add_query_arg( array( 'post_type' => 'shop_order', $report_action => true, 'changed' => $changed, 'ids' => join( ',', $post_ids ) ), '' );
720         wp_redirect( $sendback );
721         exit();
722     }
723 
724     /**
725      * Show confirmation message that order status changed for number of orders
726      *
727      * @access public
728      * @return void
729      */
730     public function bulk_admin_notices() {
731         global $post_type, $pagenow;
732 
733         if ( isset( $_REQUEST['marked_completed'] ) || isset( $_REQUEST['marked_processing'] ) || isset( $_REQUEST['marked_on-hold'] ) ) {
734             $number = isset( $_REQUEST['changed'] ) ? absint( $_REQUEST['changed'] ) : 0;
735 
736             if ( 'edit.php' == $pagenow && 'shop_order' == $post_type ) {
737                 $message = sprintf( _n( 'Order status changed.', '%s order statuses changed.', $number, 'woocommerce' ), number_format_i18n( $number ) );
738                 echo '<div class="updated"><p>' . $message . '</p></div>';
739             }
740         }
741     }
742 
743 }
744 
745 endif;
746 
747 return new WC_Admin_CPT_Shop_Order();
748 
WooCommerce API documentation generated by ApiGen 2.8.0