1 <?php
2 3 4 5 6 7 8 9
10
11 if ( ! defined( 'ABSPATH' ) ) {
12 exit;
13 }
14
15 if ( ! class_exists( 'WC_Admin_CPT' ) ) {
16 include( 'class-wc-admin-cpt.php' );
17 }
18
19 if ( ! class_exists( 'WC_Admin_CPT_Product' ) ) :
20
21 22 23
24 class WC_Admin_CPT_Product extends WC_Admin_CPT {
25
26 27 28
29 public function __construct() {
30 $this->type = 'product';
31
32
33 add_filter( 'enter_title_here', array( $this, 'enter_title_here' ), 1, 2 );
34
35
36 add_filter( 'gettext', array( $this, 'featured_image_gettext' ) );
37 add_filter( 'media_view_strings', array( $this, 'media_view_strings' ), 10, 2 );
38
39
40 add_action( 'post_submitbox_misc_actions', array( $this, 'product_data_visibility' ) );
41
42
43 add_action( 'pre_post_update', array( $this, 'pre_post_update' ) );
44 add_filter( 'wp_insert_post_data', array( $this, 'wp_insert_post_data' ) );
45
46
47 add_filter( 'manage_edit-product_columns', array( $this, 'edit_columns' ) );
48 add_action( 'manage_product_posts_custom_column', array( $this, 'custom_columns' ), 2 );
49 add_filter( 'manage_edit-product_sortable_columns', array( $this, 'custom_columns_sort' ) );
50 add_filter( 'request', array( $this, 'custom_columns_orderby' ) );
51
52
53 add_filter( 'views_edit-product', array( $this, 'default_sorting_link' ) );
54
55
56 add_action( 'restrict_manage_posts', array( $this, 'product_filters' ) );
57 add_filter( 'parse_query', array( $this, 'product_filters_query' ) );
58
59
60 add_filter( 'posts_search', array( $this, 'product_search' ) );
61
62
63 add_filter( 'wp_terms_checklist_args', array( $this, 'disable_checked_ontop' ) );
64
65
66 add_action( 'bulk_edit_custom_box', array( $this, 'bulk_edit' ), 10, 2 );
67 add_action( 'quick_edit_custom_box', array( $this, 'quick_edit' ), 10, 2 );
68 add_action( 'save_post', array( $this, 'bulk_and_quick_edit_save_post' ), 10, 2 );
69
70
71 add_filter( 'upload_dir', array( $this, 'upload_dir' ) );
72 add_action( 'media_upload_downloadable_product', array( $this, 'media_upload_downloadable_product' ) );
73 add_filter( 'mod_rewrite_rules', array( $this, 'ms_protect_download_rewite_rules' ) );
74
75
76 add_action( 'woocommerce_process_product_file_download_paths', array( $this, 'process_product_file_download_paths' ), 10, 3 );
77
78
79 parent::__construct();
80 }
81
82 83 84 85
86 private function is_editing_product() {
87 if ( ! empty( $_GET['post_type'] ) && 'product' == $_GET['post_type'] ) {
88 return true;
89 }
90 if ( ! empty( $_GET['post'] ) && 'product' == get_post_type( $_GET['post'] ) ) {
91 return true;
92 }
93 if ( ! empty( $_REQUEST['post_id'] ) && 'product' == get_post_type( $_REQUEST['post_id'] ) ) {
94 return true;
95 }
96 return false;
97 }
98
99 100 101 102 103
104 public function featured_image_gettext( $string = '' ) {
105 if ( 'Featured Image' == $string && $this->is_editing_product() ) {
106 $string = __( 'Product Image', 'woocommerce' );
107 } elseif ( 'Remove featured image' == $string && $this->is_editing_product() ) {
108 $string = __( 'Remove product image', 'woocommerce' );
109 } elseif ( 'Set featured image' == $string && $this->is_editing_product() ) {
110 $string = __( 'Set product image', 'woocommerce' );
111 }
112 return $string;
113 }
114
115 116 117 118 119 120
121 public function media_view_strings( $strings = array(), $post = null ) {
122 if ( is_object( $post ) ) {
123 if ( 'product' == $post->post_type ) {
124 $strings['setFeaturedImageTitle'] = __( 'Set product image', 'woocommerce' );
125 $strings['setFeaturedImage'] = __( 'Set product image', 'woocommerce' );
126 }
127 }
128 return $strings;
129 }
130
131 132 133 134 135 136
137 public function enter_title_here( $text, $post ) {
138 if ( $post->post_type == 'product' ) {
139 return __( 'Product name', 'woocommerce' );
140 }
141
142 return $text;
143 }
144
145 146 147 148 149 150
151 public function product_data_visibility() {
152 global $post;
153
154 if ( 'product' != $post->post_type ) {
155 return;
156 }
157
158 $current_visibility = ( $current_visibility = get_post_meta( $post->ID, '_visibility', true ) ) ? $current_visibility : 'visible';
159 $current_featured = ( $current_featured = get_post_meta( $post->ID, '_featured', true ) ) ? $current_featured : 'no';
160
161 $visibility_options = apply_filters( 'woocommerce_product_visibility_options', array(
162 'visible' => __( 'Catalog/search', 'woocommerce' ),
163 'catalog' => __( 'Catalog', 'woocommerce' ),
164 'search' => __( 'Search', 'woocommerce' ),
165 'hidden' => __( 'Hidden', 'woocommerce' )
166 ) );
167 ?>
168 <div class="misc-pub-section" id="catalog-visibility">
169 <?php _e( 'Catalog visibility:', 'woocommerce' ); ?> <strong id="catalog-visibility-display"><?php
170 echo isset( $visibility_options[ $current_visibility ] ) ? esc_html( $visibility_options[ $current_visibility ] ) : esc_html( $current_visibility );
171
172 if ( 'yes' == $current_featured ) {
173 echo ', ' . __( 'Featured', 'woocommerce' );
174 }
175 ?></strong>
176
177 <a href="#catalog-visibility" class="edit-catalog-visibility hide-if-no-js"><?php _e( 'Edit', 'woocommerce' ); ?></a>
178
179 <div id="catalog-visibility-select" class="hide-if-js">
180
181 <input type="hidden" name="current_visibility" id="current_visibility" value="<?php echo esc_attr( $current_visibility ); ?>" />
182 <input type="hidden" name="current_featured" id="current_featured" value="<?php echo esc_attr( $current_featured ); ?>" />
183
184 <?php
185 echo '<p>' . __( 'Define the loops this product should be visible in. The product will still be accessible directly.', 'woocommerce' ) . '</p>';
186
187 foreach ( $visibility_options as $name => $label ) {
188 echo '<input type="radio" name="_visibility" id="_visibility_' . esc_attr( $name ) . '" value="' . esc_attr( $name ) . '" ' . checked( $current_visibility, $name, false ) . ' data-label="' . esc_attr( $label ) . '" /> <label for="_visibility_' . esc_attr( $name ) . '" class="selectit">' . esc_html( $label ) . '</label><br />';
189 }
190
191 echo '<p>' . __( 'Enable this option to feature this product.', 'woocommerce' ) . '</p>';
192
193 echo '<input type="checkbox" name="_featured" id="_featured" ' . checked( $current_featured, 'yes', false ) . ' /> <label for="_featured">' . __( 'Featured Product', 'woocommerce' ) . '</label><br />';
194 ?>
195 <p>
196 <a href="#catalog-visibility" class="save-post-visibility hide-if-no-js button"><?php _e( 'OK', 'woocommerce' ); ?></a>
197 <a href="#catalog-visibility" class="cancel-post-visibility hide-if-no-js"><?php _e( 'Cancel', 'woocommerce' ); ?></a>
198 </p>
199 </div>
200 </div>
201 <?php
202 }
203
204 205 206 207 208
209 public function pre_post_update( $post_id ) {
210 if ( isset( $_POST['_visibility'] ) ) {
211 update_post_meta( $post_id, '_visibility', stripslashes( $_POST['_visibility'] ) );
212 }
213
214 if ( isset( $_POST['_stock_status'] ) ) {
215 wc_update_product_stock_status( $post_id, wc_clean( $_POST['_stock_status'] ) );
216 }
217 }
218
219 220 221 222 223 224
225 public function wp_insert_post_data( $data ) {
226 global $post;
227
228 if ( 'product' == $data['post_type'] && isset( $_POST['product-type'] ) ) {
229 $product_type = stripslashes( $_POST['product-type'] );
230 switch ( $product_type ) {
231 case 'grouped' :
232 case 'variable' :
233 $data['post_parent'] = 0;
234 break;
235
236 default :
237 break;
238 }
239 }
240
241 return $data;
242 }
243
244 245 246
247 public function edit_columns( $existing_columns ) {
248
249 if ( empty( $existing_columns ) && ! is_array( $existing_columns ) ) {
250 $existing_columns = array();
251 }
252
253 unset( $existing_columns['title'], $existing_columns['comments'], $existing_columns['date'] );
254
255 $columns = array();
256 $columns['cb'] = '<input type="checkbox" />';
257 $columns['thumb'] = '<span class="wc-image tips" data-tip="' . __( 'Image', 'woocommerce' ) . '">' . __( 'Image', 'woocommerce' ) . '</span>';
258
259 $columns['name'] = __( 'Name', 'woocommerce' );
260
261 if ( wc_product_sku_enabled() ) {
262 $columns['sku'] = __( 'SKU', 'woocommerce' );
263 }
264
265 if ( 'yes' == get_option( 'woocommerce_manage_stock' ) ) {
266 $columns['is_in_stock'] = __( 'Stock', 'woocommerce' );
267 }
268
269 $columns['price'] = __( 'Price', 'woocommerce' );
270
271 $columns['product_cat'] = __( 'Categories', 'woocommerce' );
272 $columns['product_tag'] = __( 'Tags', 'woocommerce' );
273 $columns['featured'] = '<span class="wc-featured tips" data-tip="' . __( 'Featured', 'woocommerce' ) . '">' . __( 'Featured', 'woocommerce' ) . '</span>';
274 $columns['product_type'] = '<span class="wc-type tips" data-tip="' . __( 'Type', 'woocommerce' ) . '">' . __( 'Type', 'woocommerce' ) . '</span>';
275 $columns['date'] = __( 'Date', 'woocommerce' );
276
277 return array_merge( $columns, $existing_columns );
278 }
279
280 281 282 283
284 public function custom_columns( $column ) {
285 global $post, $woocommerce, $the_product;
286
287 if ( empty( $the_product ) || $the_product->id != $post->ID ) {
288 $the_product = get_product( $post );
289 }
290
291 switch ( $column ) {
292 case 'thumb' :
293 echo '<a href="' . get_edit_post_link( $post->ID ) . '">' . $the_product->get_image() . '</a>';
294 break;
295 case 'name' :
296 $edit_link = get_edit_post_link( $post->ID );
297 $title = _draft_or_post_title();
298 $post_type_object = get_post_type_object( $post->post_type );
299 $can_edit_post = current_user_can( $post_type_object->cap->edit_post, $post->ID );
300
301 echo '<strong><a class="row-title" href="' . esc_url( $edit_link ) .'">' . $title.'</a>';
302
303 _post_states( $post );
304
305 echo '</strong>';
306
307 if ( $post->post_parent > 0 ) {
308 echo ' ← <a href="'. get_edit_post_link( $post->post_parent ) .'">'. get_the_title( $post->post_parent ) .'</a>';
309 }
310
311
312 if ( isset( $_GET['mode'] ) && 'excerpt' == $_GET['mode'] ) {
313 echo apply_filters( 'the_excerpt', $post->post_excerpt );
314 }
315
316
317 $actions = array();
318
319 $actions['id'] = 'ID: ' . $post->ID;
320
321 if ( $can_edit_post && 'trash' != $post->post_status ) {
322 $actions['edit'] = '<a href="' . get_edit_post_link( $post->ID, true ) . '" title="' . esc_attr( __( 'Edit this item', 'woocommerce' ) ) . '">' . __( 'Edit', 'woocommerce' ) . '</a>';
323 $actions['inline hide-if-no-js'] = '<a href="#" class="editinline" title="' . esc_attr( __( 'Edit this item inline', 'woocommerce' ) ) . '">' . __( 'Quick Edit', 'woocommerce' ) . '</a>';
324 }
325 if ( current_user_can( $post_type_object->cap->delete_post, $post->ID ) ) {
326 if ( 'trash' == $post->post_status ) {
327 $actions['untrash'] = '<a title="' . esc_attr( __( 'Restore this item from the Trash', 'woocommerce' ) ) . '" href="' . wp_nonce_url( admin_url( sprintf( $post_type_object->_edit_link . '&action=untrash', $post->ID ) ), 'untrash-post_' . $post->ID ) . '">' . __( 'Restore', 'woocommerce' ) . '</a>';
328 } elseif ( EMPTY_TRASH_DAYS ) {
329 $actions['trash'] = '<a class="submitdelete" title="' . esc_attr( __( 'Move this item to the Trash', 'woocommerce' ) ) . '" href="' . get_delete_post_link( $post->ID ) . '">' . __( 'Trash', 'woocommerce' ) . '</a>';
330 }
331
332 if ( 'trash' == $post->post_status || ! EMPTY_TRASH_DAYS ) {
333 $actions['delete'] = '<a class="submitdelete" title="' . esc_attr( __( 'Delete this item permanently', 'woocommerce' ) ) . '" href="' . get_delete_post_link( $post->ID, '', true ) . '">' . __( 'Delete Permanently', 'woocommerce' ) . '</a>';
334 }
335 }
336 if ( $post_type_object->public ) {
337 if ( in_array( $post->post_status, array( 'pending', 'draft', 'future' ) ) ) {
338 if ( $can_edit_post )
339 $actions['view'] = '<a href="' . esc_url( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) ) . '" title="' . esc_attr( sprintf( __( 'Preview “%s”', 'woocommerce' ), $title ) ) . '" rel="permalink">' . __( 'Preview', 'woocommerce' ) . '</a>';
340 } elseif ( 'trash' != $post->post_status ) {
341 $actions['view'] = '<a href="' . get_permalink( $post->ID ) . '" title="' . esc_attr( sprintf( __( 'View “%s”', 'woocommerce' ), $title ) ) . '" rel="permalink">' . __( 'View', 'woocommerce' ) . '</a>';
342 }
343 }
344
345 $actions = apply_filters( 'post_row_actions', $actions, $post );
346
347 echo '<div class="row-actions">';
348
349 $i = 0;
350 $action_count = sizeof($actions);
351
352 foreach ( $actions as $action => $link ) {
353 ++$i;
354 ( $i == $action_count ) ? $sep = '' : $sep = ' | ';
355 echo '<span class="' . $action . '">' . $link . $sep . '</span>';
356 }
357 echo '</div>';
358
359 get_inline_data( $post );
360
361
362 echo '
363 <div class="hidden" id="woocommerce_inline_' . $post->ID . '">
364 <div class="menu_order">' . $post->menu_order . '</div>
365 <div class="sku">' . $the_product->sku . '</div>
366 <div class="regular_price">' . $the_product->regular_price . '</div>
367 <div class="sale_price">' . $the_product->sale_price . '</div>
368 <div class="weight">' . $the_product->weight . '</div>
369 <div class="length">' . $the_product->length . '</div>
370 <div class="width">' . $the_product->width . '</div>
371 <div class="height">' . $the_product->height . '</div>
372 <div class="visibility">' . $the_product->visibility . '</div>
373 <div class="stock_status">' . $the_product->stock_status . '</div>
374 <div class="stock">' . $the_product->stock . '</div>
375 <div class="manage_stock">' . $the_product->manage_stock . '</div>
376 <div class="featured">' . $the_product->featured . '</div>
377 <div class="product_type">' . $the_product->product_type . '</div>
378 <div class="product_is_virtual">' . $the_product->virtual . '</div>
379 <div class="tax_status">' . $the_product->tax_status . '</div>
380 <div class="tax_class">' . $the_product->tax_class . '</div>
381 <div class="backorders">' . $the_product->backorders . '</div>
382 </div>
383 ';
384
385 break;
386 case 'sku' :
387 echo $the_product->get_sku() ? $the_product->get_sku() : '<span class="na">–</span>';
388 break;
389 case 'product_type' :
390 if ( 'grouped' == $the_product->product_type ) {
391 echo '<span class="product-type tips grouped" data-tip="' . __( 'Grouped', 'woocommerce' ) . '"></span>';
392 } elseif ( 'external' == $the_product->product_type ) {
393 echo '<span class="product-type tips external" data-tip="' . __( 'External/Affiliate', 'woocommerce' ) . '"></span>';
394 } elseif ( 'simple' == $the_product->product_type ) {
395
396 if ( $the_product->is_virtual() ) {
397 echo '<span class="product-type tips virtual" data-tip="' . __( 'Virtual', 'woocommerce' ) . '"></span>';
398 } elseif ( $the_product->is_downloadable() ) {
399 echo '<span class="product-type tips downloadable" data-tip="' . __( 'Downloadable', 'woocommerce' ) . '"></span>';
400 } else {
401 echo '<span class="product-type tips simple" data-tip="' . __( 'Simple', 'woocommerce' ) . '"></span>';
402 }
403
404 } elseif ( 'variable' == $the_product->product_type ) {
405 echo '<span class="product-type tips variable" data-tip="' . __( 'Variable', 'woocommerce' ) . '"></span>';
406 } else {
407
408 echo '<span class="product-type tips ' . $the_product->product_type . '" data-tip="' . ucfirst( $the_product->product_type ) . '"></span>';
409 }
410 break;
411 case 'price' :
412 echo $the_product->get_price_html() ? $the_product->get_price_html() : '<span class="na">–</span>';
413 break;
414 case 'product_cat' :
415 case 'product_tag' :
416 if ( ! $terms = get_the_terms( $post->ID, $column ) ) {
417 echo '<span class="na">–</span>';
418 } else {
419 foreach ( $terms as $term ) {
420 $termlist[] = '<a href="' . admin_url( 'edit.php?' . $column . '=' . $term->slug . '&post_type=product' ) . ' ">' . $term->name . '</a>';
421 }
422
423 echo implode( ', ', $termlist );
424 }
425 break;
426 case 'featured' :
427 $url = wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_feature_product&product_id=' . $post->ID ), 'woocommerce-feature-product' );
428 echo '<a href="' . esc_url( $url ) . '" title="'. __( 'Toggle featured', 'woocommerce' ) . '">';
429 if ( $the_product->is_featured() ) {
430 echo '<span class="wc-featured tips" data-tip="' . __( 'Yes', 'woocommerce' ) . '">' . __( 'Yes', 'woocommerce' ) . '</span>';
431 } else {
432 echo '<span class="wc-featured not-featured tips" data-tip="' . __( 'No', 'woocommerce' ) . '">' . __( 'No', 'woocommerce' ) . '</span>';
433 }
434 echo '</a>';
435 break;
436 case 'is_in_stock' :
437
438 if ( $the_product->is_in_stock() ) {
439 echo '<mark class="instock">' . __( 'In stock', 'woocommerce' ) . '</mark>';
440 } else {
441 echo '<mark class="outofstock">' . __( 'Out of stock', 'woocommerce' ) . '</mark>';
442 }
443
444 if ( $the_product->managing_stock() ) {
445 echo ' × ' . $the_product->get_total_stock();
446 }
447
448 break;
449
450 default :
451 break;
452 }
453 }
454
455 456 457 458 459 460 461 462 463
464 public function custom_columns_sort( $columns ) {
465 $custom = array(
466 'price' => 'price',
467 'featured' => 'featured',
468 'sku' => 'sku',
469 'name' => 'title'
470 );
471 return wp_parse_args( $custom, $columns );
472 }
473
474 475 476 477 478 479 480 481 482
483 public function custom_columns_orderby( $vars ) {
484 if ( isset( $vars['orderby'] ) ) {
485 if ( 'price' == $vars['orderby'] ) {
486 $vars = array_merge( $vars, array(
487 'meta_key' => '_price',
488 'orderby' => 'meta_value_num'
489 ) );
490 }
491 if ( 'featured' == $vars['orderby'] ) {
492 $vars = array_merge( $vars, array(
493 'meta_key' => '_featured',
494 'orderby' => 'meta_value'
495 ) );
496 }
497 if ( 'sku' == $vars['orderby'] ) {
498 $vars = array_merge( $vars, array(
499 'meta_key' => '_sku',
500 'orderby' => 'meta_value'
501 ) );
502 }
503 }
504
505 return $vars;
506 }
507
508 509 510 511 512 513 514 515
516 public function default_sorting_link( $views ) {
517 global $post_type, $wp_query;
518
519 if ( ! current_user_can('edit_others_pages') ) {
520 return $views;
521 }
522
523 $class = ( isset( $wp_query->query['orderby'] ) && $wp_query->query['orderby'] == 'menu_order title' ) ? 'current' : '';
524 $query_string = remove_query_arg(array( 'orderby', 'order' ));
525 $query_string = add_query_arg( 'orderby', urlencode('menu_order title'), $query_string );
526 $query_string = add_query_arg( 'order', urlencode('ASC'), $query_string );
527 $views['byorder'] = '<a href="'. $query_string . '" class="' . esc_attr( $class ) . '">' . __( 'Sort Products', 'woocommerce' ) . '</a>';
528
529 return $views;
530 }
531
532 533 534
535 public function product_filters() {
536 global $typenow, $wp_query;
537
538 if ( 'product' != $typenow ) {
539 return;
540 }
541
542
543 wc_product_dropdown_categories();
544
545
546 $terms = get_terms( 'product_type' );
547 $output = '<select name="product_type" id="dropdown_product_type">';
548 $output .= '<option value="">' . __( 'Show all product types', 'woocommerce' ) . '</option>';
549
550 foreach ( $terms as $term ) {
551 $output .= '<option value="' . sanitize_title( $term->name ) . '" ';
552
553 if ( isset( $wp_query->query['product_type'] ) ) {
554 $output .= selected( $term->slug, $wp_query->query['product_type'], false );
555 }
556
557 $output .= '>';
558
559 switch ( $term->name ) {
560 case 'grouped' :
561 $output .= __( 'Grouped product', 'woocommerce' );
562 break;
563 case 'external' :
564 $output .= __( 'External/Affiliate product', 'woocommerce' );
565 break;
566 case 'variable' :
567 $output .= __( 'Variable product', 'woocommerce' );
568 break;
569 case 'simple' :
570 $output .= __( 'Simple product', 'woocommerce' );
571 break;
572 default :
573
574 $output .= ucfirst( $term->name );
575 break;
576 }
577
578 $output .= " ($term->count)</option>";
579
580 if ( 'simple' == $term->name ) {
581
582 $output .= '<option value="downloadable" ';
583
584 if ( isset( $wp_query->query['product_type'] ) ) {
585 $output .= selected( 'downloadable', $wp_query->query['product_type'], false );
586 }
587
588 $output .= '> → ' . __( 'Downloadable', 'woocommerce' ) . '</option>';
589
590 $output .= '<option value="virtual" ';
591
592 if ( isset( $wp_query->query['product_type'] ) ) {
593 $output .= selected( 'virtual', $wp_query->query['product_type'], false );
594 }
595
596 $output .= '> → ' . __( 'Virtual', 'woocommerce' ) . '</option>';
597 }
598 }
599
600 $output .= '</select>';
601
602 echo apply_filters( 'woocommerce_product_filters', $output );
603 }
604
605 606 607 608 609
610 public function product_filters_query( $query ) {
611 global $typenow, $wp_query;
612
613 if ( 'product' == $typenow ) {
614
615 if ( isset( $query->query_vars['product_type'] ) ) {
616
617 if ( 'downloadable' == $query->query_vars['product_type'] ) {
618 $query->query_vars['product_type'] = '';
619 $query->query_vars['meta_value'] = 'yes';
620 $query->query_vars['meta_key'] = '_downloadable';
621 } elseif ( 'virtual' == $query->query_vars['product_type'] ) {
622 $query->query_vars['product_type'] = '';
623 $query->query_vars['meta_value'] = 'yes';
624 $query->query_vars['meta_key'] = '_virtual';
625 }
626 }
627
628
629 if ( isset( $_GET['product_cat'] ) && '0' == $_GET['product_cat'] ) {
630 $query->query_vars['tax_query'][] = array(
631 'taxonomy' => 'product_cat',
632 'field' => 'id',
633 'terms' => get_terms( 'product_cat', array( 'fields' => 'ids' ) ),
634 'operator' => 'NOT IN'
635 );
636 }
637 }
638 }
639
640 641 642 643 644
645 public function product_search( $where ) {
646 global $pagenow, $wpdb, $wp;
647
648 if ( 'edit.php' != $pagenow || ! is_search() || ! isset( $wp->query_vars['s'] ) || 'product' != $wp->query_vars['post_type'] ) {
649 return $where;
650 }
651
652 $search_ids = array();
653 $terms = explode( ',', $wp->query_vars['s'] );
654
655 foreach ( $terms as $term ) {
656 if ( is_numeric( $term ) ) {
657 $search_ids[] = $term;
658 }
659
660 $sku_to_id = $wpdb->get_col( $wpdb->prepare( "SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key='_sku' AND meta_value LIKE '%%%s%%';", wc_clean( $term ) ) );
661
662 if ( $sku_to_id && sizeof( $sku_to_id ) > 0 ) {
663 $search_ids = array_merge( $search_ids, $sku_to_id );
664 }
665 }
666
667 $search_ids = array_filter( array_map( 'absint', $search_ids ) );
668
669 if ( sizeof( $search_ids ) > 0 ) {
670 $where = str_replace( ')))', ") OR ({$wpdb->posts}.ID IN (" . implode( ',', $search_ids ) . "))))", $where );
671 }
672
673 return $where;
674 }
675
676 677 678 679 680
681 public function disable_checked_ontop( $args ) {
682 if ( 'product_cat' == $args['taxonomy'] ) {
683 $args['checked_ontop'] = false;
684 }
685
686 return $args;
687 }
688
689 690 691 692 693 694 695
696 public function bulk_edit( $column_name, $post_type ) {
697 if ( 'price' != $column_name || 'product' != $post_type ) {
698 return;
699 }
700
701 include( WC()->plugin_path() . '/includes/admin/views/html-bulk-edit-product.php' );
702 }
703
704 705 706 707 708 709 710
711 public function quick_edit( $column_name, $post_type ) {
712 if ( 'price' != $column_name || 'product' != $post_type ) {
713 return;
714 }
715
716 include( WC()->plugin_path() . '/includes/admin/views/html-quick-edit-product.php' );
717 }
718
719 720 721 722 723 724 725 726
727 public function bulk_and_quick_edit_save_post( $post_id, $post ) {
728
729 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
730 return $post_id;
731 }
732
733
734 if ( wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) ) {
735 return $post_id;
736 }
737
738
739 if ( 'product' != $post->post_type ) {
740 return $post_id;
741 }
742
743
744 if ( ! current_user_can( 'edit_post', $post_id ) ) {
745 return $post_id;
746 }
747
748
749 if ( ! isset( $_REQUEST['woocommerce_quick_edit_nonce'] ) && ! isset( $_REQUEST['woocommerce_bulk_edit_nonce'] ) ) {
750 return $post_id;
751 }
752 if ( isset( $_REQUEST['woocommerce_quick_edit_nonce'] ) && ! wp_verify_nonce( $_REQUEST['woocommerce_quick_edit_nonce'], 'woocommerce_quick_edit_nonce' ) ) {
753 return $post_id;
754 }
755 if ( isset( $_REQUEST['woocommerce_bulk_edit_nonce'] ) && ! wp_verify_nonce( $_REQUEST['woocommerce_bulk_edit_nonce'], 'woocommerce_bulk_edit_nonce' ) ) {
756 return $post_id;
757 }
758
759
760 $product = get_product( $post );
761
762 if ( ! empty( $_REQUEST['woocommerce_quick_edit'] ) ) {
763 $this->quick_edit_save( $post_id, $product );
764 } else {
765 $this->bulk_edit_save( $post_id, $product );
766 }
767
768
769 wc_delete_product_transients( $post_id );
770
771 return $post_id;
772 }
773
774 775 776
777 private function quick_edit_save( $post_id, $product ) {
778 global $wpdb;
779
780 $old_regular_price = $product->regular_price;
781 $old_sale_price = $product->sale_price;
782
783
784 if ( isset( $_REQUEST['_sku'] ) ) {
785 $sku = get_post_meta( $post_id, '_sku', true );
786 $new_sku = wc_clean( stripslashes( $_REQUEST['_sku'] ) );
787
788 if ( $new_sku !== $sku ) {
789 if ( ! empty( $new_sku ) ) {
790 $sku_exists = $wpdb->get_var( $wpdb->prepare("
791 SELECT $wpdb->posts.ID
792 FROM $wpdb->posts
793 LEFT JOIN $wpdb->postmeta ON ($wpdb->posts.ID = $wpdb->postmeta.post_id)
794 WHERE $wpdb->posts.post_type = 'product'
795 AND $wpdb->posts.post_status = 'publish'
796 AND $wpdb->postmeta.meta_key = '_sku' AND $wpdb->postmeta.meta_value = '%s'
797 ", $new_sku ) );
798
799 if ( ! $sku_exists ) {
800 update_post_meta( $post_id, '_sku', $new_sku );
801 }
802 } else {
803 update_post_meta( $post_id, '_sku', '' );
804 }
805 }
806 }
807
808 if ( isset( $_REQUEST['_weight'] ) ) {
809 update_post_meta( $post_id, '_weight', wc_clean( $_REQUEST['_weight'] ) );
810 }
811
812 if ( isset( $_REQUEST['_length'] ) ) {
813 update_post_meta( $post_id, '_length', wc_clean( $_REQUEST['_length'] ) );
814 }
815
816 if ( isset( $_REQUEST['_width'] ) ) {
817 update_post_meta( $post_id, '_width', wc_clean( $_REQUEST['_width'] ) );
818 }
819
820 if ( isset( $_REQUEST['_height'] ) ) {
821 update_post_meta( $post_id, '_height', wc_clean( $_REQUEST['_height'] ) );
822 }
823
824 if ( isset( $_REQUEST['_visibility'] ) ) {
825 update_post_meta( $post_id, '_visibility', wc_clean( $_REQUEST['_visibility'] ) );
826 }
827
828 if ( isset( $_REQUEST['_featured'] ) ) {
829 update_post_meta( $post_id, '_featured', 'yes' );
830 } else {
831 update_post_meta( $post_id, '_featured', 'no' );
832 }
833
834 if ( isset( $_REQUEST['_tax_status'] ) ) {
835 update_post_meta( $post_id, '_tax_status', wc_clean( $_REQUEST['_tax_status'] ) );
836 }
837
838 if ( isset( $_REQUEST['_tax_class'] ) ) {
839 update_post_meta( $post_id, '_tax_class', wc_clean( $_REQUEST['_tax_class'] ) );
840 }
841
842 if ( $product->is_type('simple') || $product->is_type('external') ) {
843
844 if ( isset( $_REQUEST['_regular_price'] ) ) {
845 $new_regular_price = $_REQUEST['_regular_price'] === '' ? '' : wc_format_decimal( $_REQUEST['_regular_price'] );
846 update_post_meta( $post_id, '_regular_price', $new_regular_price );
847 } else {
848 $new_regular_price = null;
849 }
850 if ( isset( $_REQUEST['_sale_price'] ) ) {
851 $new_sale_price = $_REQUEST['_sale_price'] === '' ? '' : wc_format_decimal( $_REQUEST['_sale_price'] );
852 update_post_meta( $post_id, '_sale_price', $new_sale_price );
853 } else {
854 $new_sale_price = null;
855 }
856
857
858 $price_changed = false;
859
860 if ( ! is_null( $new_regular_price ) && $new_regular_price != $old_regular_price ) {
861 $price_changed = true;
862 } elseif ( ! is_null( $new_sale_price ) && $new_sale_price != $old_sale_price ) {
863 $price_changed = true;
864 }
865
866 if ( $price_changed ) {
867 update_post_meta( $post_id, '_sale_price_dates_from', '' );
868 update_post_meta( $post_id, '_sale_price_dates_to', '' );
869
870 if ( ! is_null( $new_sale_price ) && $new_sale_price !== '' ) {
871 update_post_meta( $post_id, '_price', $new_sale_price );
872 } else {
873 update_post_meta( $post_id, '_price', $new_regular_price );
874 }
875 }
876 }
877
878
879 if ( isset( $_REQUEST['_stock_status'] ) ) {
880 wc_update_product_stock_status( $post_id, wc_clean( $_REQUEST['_stock_status'] ) );
881 }
882
883
884 if ( ! $product->is_type('grouped') ) {
885 if ( isset( $_REQUEST['_manage_stock'] ) ) {
886 update_post_meta( $post_id, '_manage_stock', 'yes' );
887 wc_update_product_stock( $post_id, intval( $_REQUEST['_stock'] ) );
888 } else {
889 update_post_meta( $post_id, '_manage_stock', 'no' );
890 wc_update_product_stock( $post_id, 0 );
891 }
892
893 if ( ! empty( $_REQUEST['_backorders'] ) ) {
894 update_post_meta( $post_id, '_backorders', wc_clean( $_REQUEST['_backorders'] ) );
895 }
896 }
897
898 do_action( 'woocommerce_product_quick_edit_save', $product );
899 }
900
901 902 903
904 public function bulk_edit_save( $post_id, $product ) {
905
906 $old_regular_price = $product->regular_price;
907 $old_sale_price = $product->sale_price;
908
909
910 if ( ! empty( $_REQUEST['change_weight'] ) && isset( $_REQUEST['_weight'] ) ) {
911 update_post_meta( $post_id, '_weight', wc_clean( stripslashes( $_REQUEST['_weight'] ) ) );
912 }
913
914 if ( ! empty( $_REQUEST['change_dimensions'] ) ) {
915 if ( isset( $_REQUEST['_length'] ) ) {
916 update_post_meta( $post_id, '_length', wc_clean( stripslashes( $_REQUEST['_length'] ) ) );
917 }
918 if ( isset( $_REQUEST['_width'] ) ) {
919 update_post_meta( $post_id, '_width', wc_clean( stripslashes( $_REQUEST['_width'] ) ) );
920 }
921 if ( isset( $_REQUEST['_height'] ) ) {
922 update_post_meta( $post_id, '_height', wc_clean( stripslashes( $_REQUEST['_height'] ) ) );
923 }
924 }
925
926 if ( ! empty( $_REQUEST['_tax_status'] ) ) {
927 update_post_meta( $post_id, '_tax_status', wc_clean( $_REQUEST['_tax_status'] ) );
928 }
929
930 if ( ! empty( $_REQUEST['_tax_class'] ) ) {
931 $tax_class = wc_clean( $_REQUEST['_tax_class'] );
932 if ( 'standard' == $tax_class ) {
933 $tax_class = '';
934 }
935 update_post_meta( $post_id, '_tax_class', $tax_class );
936 }
937
938 if ( ! empty( $_REQUEST['_stock_status'] ) ) {
939 wc_update_product_stock_status( $post_id, wc_clean( $_REQUEST['_stock_status'] ) );
940 }
941
942 if ( ! empty( $_REQUEST['_visibility'] ) ) {
943 update_post_meta( $post_id, '_visibility', stripslashes( $_REQUEST['_visibility'] ) );
944 }
945
946 if ( ! empty( $_REQUEST['_featured'] ) ) {
947 update_post_meta( $post_id, '_featured', stripslashes( $_REQUEST['_featured'] ) );
948 }
949
950
951 if ( $product->is_type( 'simple' ) || $product->is_type( 'external' ) ) {
952
953 $price_changed = false;
954
955 if ( ! empty( $_REQUEST['change_regular_price'] ) ) {
956
957 $change_regular_price = absint( $_REQUEST['change_regular_price'] );
958 $regular_price = esc_attr( stripslashes( $_REQUEST['_regular_price'] ) );
959
960 switch ( $change_regular_price ) {
961 case 1 :
962 $new_price = $regular_price;
963 break;
964 case 2 :
965 if ( strstr( $regular_price, '%' ) ) {
966 $percent = str_replace( '%', '', $regular_price ) / 100;
967 $new_price = $old_regular_price + ( round( $old_regular_price * $percent, absint( get_option( 'woocommerce_price_num_decimals' ) ) ) );
968 } else {
969 $new_price = $old_regular_price + $regular_price;
970 }
971 break;
972 case 3 :
973 if ( strstr( $regular_price, '%' ) ) {
974 $percent = str_replace( '%', '', $regular_price ) / 100;
975 $new_price = $old_regular_price - ( round ( $old_regular_price * $percent, absint( get_option( 'woocommerce_price_num_decimals' ) ) ) );
976 } else {
977 $new_price = $old_regular_price - $regular_price;
978 }
979 break;
980
981 default :
982 break;
983 }
984
985 if ( isset( $new_price ) && $new_price != $old_regular_price ) {
986 $price_changed = true;
987 $new_price = round( $new_price, absint( get_option( 'woocommerce_price_num_decimals' ) ) );
988 update_post_meta( $post_id, '_regular_price', $new_price );
989 $product->regular_price = $new_price;
990 }
991 }
992
993 if ( ! empty( $_REQUEST['change_sale_price'] ) ) {
994
995 $change_sale_price = absint( $_REQUEST['change_sale_price'] );
996 $sale_price = esc_attr( stripslashes( $_REQUEST['_sale_price'] ) );
997
998 switch ( $change_sale_price ) {
999 case 1 :
1000 $new_price = $sale_price;
1001 break;
1002 case 2 :
1003 if ( strstr( $sale_price, '%' ) ) {
1004 $percent = str_replace( '%', '', $sale_price ) / 100;
1005 $new_price = $old_sale_price + ( $old_sale_price * $percent );
1006 } else {
1007 $new_price = $old_sale_price + $sale_price;
1008 }
1009 break;
1010 case 3 :
1011 if ( strstr( $sale_price, '%' ) ) {
1012 $percent = str_replace( '%', '', $sale_price ) / 100;
1013 $new_price = $old_sale_price - ( $old_sale_price * $percent );
1014 } else {
1015 $new_price = $old_sale_price - $sale_price;
1016 }
1017 break;
1018 case 4 :
1019 if ( strstr( $sale_price, '%' ) ) {
1020 $percent = str_replace( '%', '', $sale_price ) / 100;
1021 $new_price = $product->regular_price - ( $product->regular_price * $percent );
1022 } else {
1023 $new_price = $product->regular_price - $sale_price;
1024 }
1025 break;
1026
1027 default :
1028 break;
1029 }
1030
1031 if ( isset( $new_price ) && $new_price != $old_sale_price ) {
1032 $price_changed = true;
1033 $new_price = round( $new_price, absint( get_option( 'woocommerce_price_num_decimals' ) ) );
1034 update_post_meta( $post_id, '_sale_price', $new_price );
1035 $product->sale_price = $new_price;
1036 }
1037 }
1038
1039 if ( $price_changed ) {
1040 update_post_meta( $post_id, '_sale_price_dates_from', '' );
1041 update_post_meta( $post_id, '_sale_price_dates_to', '' );
1042
1043 if ( $product->regular_price < $product->sale_price ) {
1044 $product->sale_price = '';
1045 update_post_meta( $post_id, '_sale_price', '' );
1046 }
1047
1048 if ( $product->sale_price ) {
1049 update_post_meta( $post_id, '_price', $product->sale_price );
1050 } else {
1051 update_post_meta( $post_id, '_price', $product->regular_price );
1052 }
1053 }
1054 }
1055
1056
1057 if ( ! $product->is_type( 'grouped' ) ) {
1058
1059 if ( ! empty( $_REQUEST['change_stock'] ) ) {
1060 update_post_meta( $post_id, '_manage_stock', 'yes' );
1061 wc_update_product_stock( $post_id, intval( $_REQUEST['_stock'] ) );
1062 }
1063
1064 if ( ! empty( $_REQUEST['_manage_stock'] ) ) {
1065
1066 if ( $_REQUEST['_manage_stock'] == 'yes' ) {
1067 update_post_meta( $post_id, '_manage_stock', 'yes' );
1068 } else {
1069 update_post_meta( $post_id, '_manage_stock', 'no' );
1070 wc_update_product_stock( $post_id, 0 );
1071 }
1072 }
1073
1074 if ( ! empty( $_REQUEST['_backorders'] ) ) {
1075 update_post_meta( $post_id, '_backorders', wc_clean( $_REQUEST['_backorders'] ) );
1076 }
1077
1078 }
1079
1080 do_action( 'woocommerce_product_bulk_edit_save', $product );
1081 }
1082
1083 1084 1085 1086 1087 1088
1089 public function upload_dir( $pathdata ) {
1090
1091 if ( isset( $_POST['type'] ) && 'downloadable_product' == $_POST['type'] ) {
1092 if ( empty( $pathdata['subdir'] ) ) {
1093 $pathdata['path'] = $pathdata['path'] . '/woocommerce_uploads';
1094 $pathdata['url'] = $pathdata['url']. '/woocommerce_uploads';
1095 $pathdata['subdir'] = '/woocommerce_uploads';
1096 } else {
1097 $new_subdir = '/woocommerce_uploads' . $pathdata['subdir'];
1098
1099 $pathdata['path'] = str_replace( $pathdata['subdir'], $new_subdir, $pathdata['path'] );
1100 $pathdata['url'] = str_replace( $pathdata['subdir'], $new_subdir, $pathdata['url'] );
1101 $pathdata['subdir'] = str_replace( $pathdata['subdir'], $new_subdir, $pathdata['subdir'] );
1102 }
1103 }
1104
1105 return $pathdata;
1106 }
1107
1108 1109 1110
1111 public function woocommerce_media_upload_downloadable_product() {
1112 do_action( 'media_upload_file' );
1113 }
1114
1115 1116 1117 1118 1119 1120
1121 public function ms_protect_download_rewite_rules( $rewrite ) {
1122 global $wp_rewrite;
1123
1124 if ( ! is_multisite() || 'redirect' == get_option( 'woocommerce_file_download_method' ) ) {
1125 return $rewrite;
1126 }
1127
1128 $rule = "\n# WooCommerce Rules - Protect Files from ms-files.php\n\n";
1129 $rule .= "<IfModule mod_rewrite.c>\n";
1130 $rule .= "RewriteEngine On\n";
1131 $rule .= "RewriteCond %{QUERY_STRING} file=woocommerce_uploads/ [NC]\n";
1132 $rule .= "RewriteRule /ms-files.php$ - [F]\n";
1133 $rule .= "</IfModule>\n\n";
1134
1135 return $rule . $rewrite;
1136 }
1137
1138 1139 1140 1141 1142 1143 1144 1145
1146 public function process_product_file_download_paths( $product_id, $variation_id, $downloadable_files ) {
1147 global $wpdb;
1148
1149 if ( $variation_id ) {
1150 $product_id = $variation_id;
1151 }
1152
1153 $product = get_product( $product_id );
1154 $existing_download_ids = array_keys( (array) $product->get_files() );
1155 $updated_download_ids = array_keys( (array) $downloadable_files );
1156
1157 $new_download_ids = array_filter( array_diff( $updated_download_ids, $existing_download_ids ) );
1158 $removed_download_ids = array_filter( array_diff( $existing_download_ids, $updated_download_ids ) );
1159
1160 if ( $new_download_ids || $removed_download_ids ) {
1161
1162 $existing_permissions = $wpdb->get_results( $wpdb->prepare( "SELECT * from {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE product_id = %d GROUP BY order_id", $product_id ) );
1163
1164 foreach ( $existing_permissions as $existing_permission ) {
1165 $order = new WC_Order( $existing_permission->order_id );
1166
1167 if ( $order->id ) {
1168
1169 if ( $removed_download_ids ) {
1170 foreach ( $removed_download_ids as $download_id ) {
1171 if ( apply_filters( 'woocommerce_process_product_file_download_paths_remove_access_to_old_file', true, $download_id, $product_id, $order ) ) {
1172 $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE order_id = %d AND product_id = %d AND download_id = %s", $order->id, $product_id, $download_id ) );
1173 }
1174 }
1175 }
1176
1177 if ( $new_download_ids ) {
1178 foreach ( $new_download_ids as $download_id ) {
1179 if ( apply_filters( 'woocommerce_process_product_file_download_paths_grant_access_to_new_file', true, $download_id, $product_id, $order ) ) {
1180
1181 if ( ! $wpdb->get_var( $wpdb->prepare( "SELECT 1 FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE order_id = %d AND product_id = %d AND download_id = %s", $order->id, $product_id, $download_id ) ) ) {
1182 wc_downloadable_file_permission( $download_id, $product_id, $order );
1183 }
1184 }
1185 }
1186 }
1187 }
1188 }
1189 }
1190 }
1191 }
1192
1193 endif;
1194
1195 return new WC_Admin_CPT_Product();
1196