· 6 years ago · Feb 13, 2020, 04:56 PM
1<?php
2
3if ( ! defined( 'ABSPATH' ) ) {
4 exit; // Exit if accessed directly
5}
6
7class WPF_Woocommerce extends WPF_Integrations_Base {
8
9 /**
10 * Woo 3.x compatibility check
11 */
12
13 public $is_v3;
14
15 /**
16 * Get things started
17 *
18 * @access public
19 * @return void
20 */
21
22 public function init() {
23
24 $this->slug = 'woocommerce';
25 $this->is_v3 = true;
26
27 add_filter( 'wpf_user_register', array( $this, 'user_register' ) );
28 add_filter( 'wpf_user_update', array( $this, 'user_update' ) );
29 add_filter( 'wpf_meta_box_post_types', array( $this, 'unset_wpf_meta_boxes' ) );
30 add_filter( 'wpf_meta_field_groups', array( $this, 'add_meta_field_group' ), 10 );
31 add_filter( 'wpf_meta_fields', array( $this, 'prepare_meta_fields' ) );
32 add_filter( 'wpf_configure_settings', array( $this, 'register_settings' ), 15, 2 );
33 add_filter( 'wpf_configure_sections', array( $this, 'configure_sections' ), 10, 2 );
34 add_filter( 'wpf_skip_auto_login', array( $this, 'skip_auto_login' ) );
35 add_filter( 'wpf_woocommerce_customer_data', array( $this, 'merge_fields_data' ), 10, 2 );
36
37 // Login redirect
38 add_filter( 'woocommerce_login_redirect', array( $this, 'maybe_bypass_login_redirect' ), 10, 2 );
39
40 // Account info update
41 add_filter( 'woocommerce_save_account_details', array( $this, 'save_account_details' ) );
42
43 // Taxonomy settings
44 add_action( 'admin_init', array( $this, 'register_taxonomy_form_fields' ) );
45
46 // Order status changes
47 add_action( 'woocommerce_order_status_processing', array( $this, 'woocommerce_apply_tags_checkout' ), 10, 1 );
48 add_action( 'woocommerce_order_status_completed', array( $this, 'woocommerce_apply_tags_checkout' ), 10, 1 );
49 add_action( 'woocommerce_order_status_failed', array( $this, 'woocommerce_apply_tags_checkout' ), 10, 1 );
50 add_action( 'wpf_woocommerce_async_checkout', array( $this, 'woocommerce_apply_tags_checkout' ), 10, 2 );
51 add_action( 'woocommerce_order_status_changed', array( $this, 'order_status_changed' ), 10, 4 );
52
53 // Save auto generated passwords
54 add_action( 'woocommerce_created_customer', array( $this, 'push_autogen_password' ), 10, 3 );
55
56 // Cancelled / refunded orderes
57 add_action( 'woocommerce_order_status_refunded', array( $this, 'woocommerce_order_refunded' ), 10 );
58
59 // Remove add to cart buttons on Shop pages for restricted products
60 add_action( 'woocommerce_loop_add_to_cart_link', array( $this, 'add_to_cart_buttons' ), 10, 2 );
61
62 // Remove restricted products from shop loop & prevent adding to cart
63 add_action( 'the_posts', array( $this, 'exclude_restricted_products' ), 10, 2 );
64 add_action( 'woocommerce_add_to_cart_validation', array( $this, 'prevent_restricted_add_to_cart' ), 10, 3 );
65
66 // Hide restricted variations
67 add_filter( 'woocommerce_variation_is_purchasable', array( $this, 'variation_is_purchaseable' ), 10, 2 );
68 add_filter( 'woocommerce_variation_is_active', array( $this, 'variation_is_purchaseable' ), 10, 2 );
69 add_action( 'wp_print_styles', array( $this, 'variation_styles' ) );
70
71 // Add meta boxes to Woo product editor
72 add_action( 'woocommerce_product_data_panels', array( $this, 'woocommerce_write_panels' ) );
73 add_action( 'woocommerce_product_write_panel_tabs', array( $this, 'woocommerce_write_panel_tabs' ) );
74 add_action( 'wpf_woocommerce_panel', array( $this, 'panel_content' ), 5 );
75
76 // Add order action
77 add_filter( 'woocommerce_order_actions', array( $this, 'order_actions' ) );
78 add_action( 'woocommerce_order_action_wpf_process', array( $this, 'process_order_action' ) );
79
80 // Variations fields
81 add_action( 'woocommerce_product_after_variable_attributes', array( $this, 'variable_fields' ), 15, 3 );
82 add_action( 'woocommerce_save_product_variation', array( $this, 'save_variable_fields' ), 10, 2 );
83
84 // Save changes to Woo meta box data
85 add_action( 'save_post', array( $this, 'save_meta_box_data' ) );
86
87 // Export functions
88 add_filter( 'wpf_export_options', array( $this, 'export_options' ) );
89 add_action( 'wpf_batch_woocommerce_init', array( $this, 'batch_init' ) );
90 add_action( 'wpf_batch_woocommerce', array( $this, 'batch_step' ) );
91
92 // Coupons settings
93 add_filter( 'woocommerce_coupon_data_tabs', array( $this, 'coupon_tabs' ) );
94 add_action( 'woocommerce_coupon_data_panels', array( $this, 'coupon_data_panel' ) );
95 add_action( 'woocommerce_coupon_options_usage_restriction', array( $this, 'coupon_usage_restriction' ), 10, 2 );
96 add_action( 'save_post_shop_coupon', array( $this, 'save_meta_box_data_coupon' ) );
97 add_filter( 'woocommerce_coupon_is_valid', array( $this, 'coupon_is_valid' ), 10, 3 );
98
99 // Apply coupons
100 add_action( 'woocommerce_add_to_cart', array( $this, 'add_to_cart_apply_coupon' ), 30 ); // 50 so the cart totals have time to recalculate
101 add_action( 'woocommerce_after_cart_item_quantity_update', array( $this, 'add_to_cart_apply_coupon' ) );
102 add_action( 'wpf_tags_modified', array( $this, 'maybe_apply_coupons' ), 10, 2 );
103
104 // Coupon labels
105 add_filter( 'woocommerce_cart_totals_coupon_label', array( $this, 'rename_coupon_label' ), 10, 2 );
106 add_filter( 'woocommerce_coupon_message', array( $this, 'coupon_success_message' ), 10, 3 );
107
108 // Restrict access to shop page
109 add_action( 'template_redirect', array( $this, 'restrict_access_to_shop' ) );
110
111 // Maybe hide coupon field
112 add_filter( 'woocommerce_coupons_enabled', array( $this, 'hide_coupon_field_on_cart' ) );
113
114 // Woo 3.x compatibility check
115 add_action( 'init', array( $this, 'compatibility_test' ) );
116
117 // Super secret admin / debugging tools
118 add_action( 'wpf_settings_page_init', array( $this, 'settings_page_init' ) );
119 add_action( 'admin_init', array( $this, 'clear_cron' ) );
120
121 }
122
123 /**
124 * Formats field data updated via the Update Account form
125 *
126 * @access public
127 * @return array User Meta
128 */
129
130 public function save_account_details( $user_id ) {
131
132 $user_meta = $_POST;
133
134 if ( isset( $user_meta['account_first_name'] ) ) {
135 $user_meta['first_name'] = $user_meta['account_first_name'];
136 }
137
138 if ( isset( $user_meta['account_email'] ) ) {
139 $user_meta['user_email'] = $user_meta['account_email'];
140 }
141
142 if ( isset( $user_meta['account_last_name'] ) ) {
143 $user_meta['last_name'] = $user_meta['account_last_name'];
144 }
145
146 if ( isset( $user_meta['password_1'] ) && ! empty( $user_meta['password_1'] ) ) {
147 $user_meta['user_pass'] = $user_meta['password_1'];
148 }
149
150 wp_fusion()->user->push_user_meta( $user_id, $user_meta );
151
152 }
153
154 /**
155 * Adds Integrations tab if not already present
156 *
157 * @access public
158 * @return void
159 */
160
161 public function configure_sections( $page, $options ) {
162
163 if ( ! isset( $page['sections']['integrations'] ) ) {
164 $page['sections'] = wp_fusion()->settings->insert_setting_after( 'contact-fields', $page['sections'], array( 'integrations' => __( 'Integrations', 'wp-fusion' ) ) );
165 }
166
167 return $page;
168
169 }
170
171 /**
172 * Skips auto login on checkout pages
173 *
174 * @access public
175 * @return bool Skip
176 */
177
178 public function skip_auto_login( $skip ) {
179
180 if ( defined( 'WC_DOING_AJAX' ) ) {
181 $skip = true;
182 }
183
184 $request_uris = array(
185 'checkout',
186 );
187
188 foreach ( $request_uris as $uri ) {
189
190 if ( strpos( $_SERVER['REQUEST_URI'], $uri ) !== false ) {
191 $skip = true;
192 }
193 }
194
195 return $skip;
196
197 }
198
199 /**
200 * Stop WooCommerce from redirecting to the My Account page if the wpf_return_to cookie is set
201 *
202 * @access public
203 * @return string Redirect
204 */
205
206 public function maybe_bypass_login_redirect( $redirect, $user ) {
207
208 if ( isset( $_COOKIE['wpf_return_to'] ) ) {
209
210 wp_fusion()->access->return_after_login( $user->user_login, $user );
211
212 }
213
214 return $redirect;
215
216 }
217
218 /**
219 * Merge WCFF data into the checkout meta data
220 *
221 * @access public
222 * @return array Customer data
223 */
224
225 public function merge_fields_data( $customer_data, $order ) {
226
227 foreach ( $order->get_items() as $item ) {
228
229 $item_meta = $item->get_meta_data();
230
231 if ( ! empty( $item_meta ) ) {
232
233 foreach ( $item_meta as $meta ) {
234
235 if ( is_a( $meta, 'WC_Meta_Data' ) ) {
236
237 $data = $meta->get_data();
238
239 $key = strtolower( str_replace( ' ', '_', $data['key'] ) );
240 $customer_data[ $key ] = $data['value'];
241
242 }
243 }
244 }
245 }
246
247 return $customer_data;
248
249 }
250
251 /**
252 * Registers additional Woocommerce settings
253 *
254 * @access public
255 * @return array Settings
256 */
257
258 public function register_settings( $settings, $options ) {
259
260 $settings['woo_header'] = array(
261 'title' => __( 'WooCommerce Integration', 'wp-fusion' ),
262 'std' => 0,
263 'type' => 'heading',
264 'section' => 'integrations',
265 );
266
267 $settings['woo_tags'] = array(
268 'title' => __( 'Apply Tags to Customers', 'wp-fusion' ),
269 'desc' => __( 'These tags will be applied to all WooCommerce customers.', 'wp-fusion' ),
270 'std' => array(),
271 'type' => 'assign_tags',
272 'section' => 'integrations',
273 );
274
275 $settings['woo_hide'] = array(
276 'title' => __( 'Hide Restricted Products', 'wp-fusion' ),
277 'desc' => __( 'If a user can\'t access a product, hide it from the Shop page.', 'wp-fusion' ),
278 'std' => 0,
279 'type' => 'checkbox',
280 'section' => 'integrations',
281 );
282
283 $settings['woo_error_message'] = array(
284 'title' => __( 'Restricted Product Error Message', 'wp-fusion' ),
285 'desc' => __( 'This message will be displayed if a customer attempts to add a restricted product to their cart.', 'wp-fusion' ),
286 'std' => 'You do not have sufficient privileges to purchase this product. Please contact support.',
287 'type' => 'text',
288 'format' => 'html',
289 'section' => 'integrations',
290 );
291
292 $settings['woo_async'] = array(
293 'title' => __( 'Asynchronous Checkout', 'wp-fusion' ),
294 'desc' => __( 'Runs WP Fusion post-checkout actions asynchronously to speed up load times.', 'wp-fusion' ),
295 'std' => 1,
296 'type' => 'checkbox',
297 'section' => 'integrations',
298 );
299
300 $settings['woo_async'] = array(
301 'title' => __( 'Asynchronous Checkout', 'wp-fusion' ),
302 'desc' => __( 'Runs WP Fusion post-checkout actions asynchronously to speed up load times.', 'wp-fusion' ),
303 'std' => 1,
304 'type' => 'checkbox',
305 'section' => 'integrations',
306 );
307
308 $settings['woo_hide_coupon_field'] = array(
309 'title' => __( 'Hide Coupon Field', 'wp-fusion' ),
310 'desc' => __( 'Hide the coupon input field on the checkout / cart screen (used with auto-applied coupons).', 'wp-fusion' ),
311 'std' => 0,
312 'type' => 'checkbox',
313 'section' => 'integrations',
314 );
315
316 if ( is_array( wp_fusion()->crm->supports ) && in_array( 'add_tags', wp_fusion()->crm->supports ) ) {
317
318 $settings['woo_header_2'] = array(
319 'title' => __( 'WooCommerce Automatic Tagging', 'wp-fusion' ),
320 'std' => 0,
321 'type' => 'heading',
322 'section' => 'integrations',
323 );
324
325 $settings['woo_category_tagging'] = array(
326 'title' => __( 'Product Category Tagging', 'wp-fusion' ),
327 'desc' => __( 'Generate and apply tags based on the category of every product purchased.', 'wp-fusion' ),
328 'std' => 0,
329 'type' => 'checkbox',
330 'section' => 'integrations',
331 );
332
333 $settings['woo_name_tagging'] = array(
334 'title' => __( 'Product Name Tagging', 'wp-fusion' ),
335 'desc' => __( 'Generate and apply tags based on the name of every product purchased.', 'wp-fusion' ),
336 'std' => 0,
337 'type' => 'checkbox',
338 'section' => 'integrations',
339 );
340
341 $settings['woo_sku_tagging'] = array(
342 'title' => __( 'Product SKU Tagging', 'wp-fusion' ),
343 'desc' => __( 'Generate and apply tags based on the SKU of every product purchased.', 'wp-fusion' ),
344 'std' => 0,
345 'type' => 'checkbox',
346 'section' => 'integrations',
347 );
348
349 $settings['woo_tagging_prefix'] = array(
350 'title' => __( 'Tag Prefix', 'wp-fusion' ),
351 'desc' => __( 'Enter a prefix (i.e. "Purchased") for any automatically-generated tags. Use shortcode [status] to dynamically insert the order status.', 'wp-fusion' ),
352 'type' => 'text',
353 'section' => 'integrations',
354 );
355
356 }
357
358 $settings['woo_header_3'] = array(
359 'title' => __( 'WooCommerce Order Status Tagging', 'wp-fusion' ),
360 'std' => 0,
361 'desc' => __( '<p>The settings here let you apply tags to a contact when an order status is changed in WooCommerce.</p><p>This is useful if you\'re manually changing order statuses, for example marking an order Completed after it\'s been shipped.</p>', 'wp-fusion' ),
362 'type' => 'heading',
363 'section' => 'integrations',
364 );
365
366 $statuses = wc_get_order_statuses();
367
368 foreach ( $statuses as $key => $label ) {
369
370 $settings[ 'woo_status_tagging_' . $key ] = array(
371 'title' => $label,
372 'type' => 'assign_tags',
373 'section' => 'integrations',
374 );
375
376 }
377
378 return $settings;
379
380 }
381
382 /**
383 * Adds WooCommerce field group to meta fields list
384 *
385 * @access public
386 * @return array Field groups
387 */
388
389 public function add_meta_field_group( $field_groups ) {
390
391 $field_groups['woocommerce'] = array(
392 'title' => 'WooCommerce',
393 'fields' => array(),
394 );
395
396 $field_groups['woocommerce_variations'] = array(
397 'title' => 'WooCommerce Attributes',
398 'fields' => array(),
399 );
400
401 return $field_groups;
402
403 }
404
405 /**
406 * Sets field labels and types for WooCommerce custom fields
407 *
408 * @access public
409 * @return array Meta fields
410 */
411
412 public function prepare_meta_fields( $meta_fields ) {
413
414 $shipping_fields = WC()->countries->get_address_fields( '', 'shipping_' );
415 $billing_fields = WC()->countries->get_address_fields( '', 'billing_' );
416
417 $woocommerce_fields = array_merge( $shipping_fields, $billing_fields );
418
419 // Support for WooCommerce Checkout Field Editor
420 $additional_fields = get_option( 'wc_fields_additional' );
421
422 if ( ! empty( $additional_fields ) ) {
423 $woocommerce_fields = array_merge( $woocommerce_fields, $additional_fields );
424 }
425
426 foreach ( $woocommerce_fields as $key => $data ) {
427
428 if ( ! isset( $meta_fields[ $key ] ) ) {
429 $meta_fields[ $key ] = array();
430 }
431
432 if ( isset( $data['label'] ) ) {
433 $woo_field_data = array( 'label' => $data['label'] );
434 } else {
435 $woo_field_data = array( 'label' => '' );
436 }
437
438 if ( isset( $data['type'] ) ) {
439 $woo_field_data['type'] = $data['type'];
440 } else {
441 $woo_field_data['type'] = 'text';
442 }
443
444 $meta_fields[ $key ] = array_merge( $meta_fields[ $key ], $woo_field_data );
445
446 $meta_fields[ $key ]['group'] = 'woocommerce';
447
448 }
449
450 // Support for WooCommerce Checkout Field Editor Pro
451
452 if ( class_exists( 'WCFE_Checkout_Section' ) ) {
453
454 $additional_fields = get_option( 'thwcfe_sections' );
455
456 if ( ! empty( $additional_fields ) ) {
457
458 foreach ( $additional_fields as $section ) {
459
460 if ( ! empty( $section->fields ) ) {
461
462 foreach ( $section->fields as $field ) {
463
464 if ( ! isset( $meta_fields[ $field->id ] ) ) {
465
466 $meta_fields[ $field->id ] = array(
467 'label' => $field->title,
468 'type' => $field->type,
469 'group' => 'woocommerce',
470 );
471
472 }
473 }
474 }
475 }
476 }
477 }
478
479 $meta_fields['order_notes'] = array(
480 'label' => 'Order Notes',
481 'type' => 'text',
482 'group' => 'woocommerce',
483 );
484
485 $meta_fields['order_date'] = array(
486 'label' => 'Last Order Date',
487 'type' => 'date',
488 'group' => 'woocommerce',
489 );
490
491 $meta_fields['coupon_code'] = array(
492 'label' => 'Last Coupon Used',
493 'type' => 'text',
494 'group' => 'woocommerce',
495 );
496
497 $meta_fields['billing_vat_nr'] = array(
498 'label' => 'Billing VAT Number',
499 'type' => 'text',
500 'group' => 'woocommerce',
501 );
502
503 $meta_fields['billing_person_company'] = array(
504 'label' => 'Person or Company',
505 'type' => 'dropdown',
506 'group' => 'woocommerce',
507 );
508
509 $meta_fields['order_id'] = array(
510 'label' => 'Last Order ID',
511 'type' => 'int',
512 'group' => 'woocommerce',
513 );
514
515 // Get attributes
516
517 $args = array(
518 'limit' => 100,
519 'post_type' => 'product',
520 'fields' => 'ids',
521 'meta_query' => array(
522 array(
523 'key' => '_product_attributes',
524 'compare' => 'EXISTS',
525 ),
526 ),
527 );
528
529 $products = get_posts( $args );
530
531 if ( ! empty( $products ) ) {
532
533 foreach ( $products as $product_id ) {
534
535 $attributes = get_post_meta( $product_id, '_product_attributes', true );
536
537 if ( ! empty( $attributes ) ) {
538
539 foreach ( $attributes as $key => $attribute ) {
540
541 $meta_fields[ $key ] = array(
542 'label' => $attribute['name'],
543 'type' => 'text',
544 'group' => 'woocommerce_variations',
545 );
546
547 }
548 }
549 }
550 }
551
552 return $meta_fields;
553
554 }
555
556
557 /**
558 * Removes standard WPF meta boxes from Woo admin pages
559 *
560 * @access public
561 * @return array Post Types
562 */
563
564 public function unset_wpf_meta_boxes( $post_types ) {
565
566 unset( $post_types['shop_order'] );
567 unset( $post_types['shop_coupon'] );
568
569 return $post_types;
570
571 }
572
573
574 /**
575 * Removes restricted products from shop archives
576 *
577 * @access public
578 * @return string Link
579 */
580
581 public function exclude_restricted_products( $posts, $query ) {
582
583 if ( is_admin() || ! is_archive() || wp_fusion()->settings->get( 'woo_hide' ) != true ) {
584 return $posts;
585 }
586
587 if ( $query->query_vars['post_type'] != 'product' && ! isset( $query->query_vars['product_cat'] ) ) {
588 return $posts;
589 }
590
591 foreach ( $posts as $index => $product ) {
592
593 if ( ! wp_fusion()->access->user_can_access( $product->ID ) ) {
594 unset( $posts[ $index ] );
595 }
596 }
597
598 return array_values( $posts );
599
600 }
601
602 /**
603 * Prevents restricted products from being added to the cart
604 *
605 * @access public
606 * @return bool Passed
607 */
608
609 public function prevent_restricted_add_to_cart( $passed, $product_id, $quantity ) {
610
611 if ( $quantity == 0 || wp_fusion()->access->user_can_access( $product_id ) ) {
612 return $passed;
613 }
614
615 wc_add_notice( wp_fusion()->settings->get( 'woo_error_message' ), 'error' );
616
617 return false;
618
619 }
620
621 /**
622 * Blocks restricted variations from purchase
623 *
624 * @access public
625 * @return bool Is purchaseable
626 */
627
628 public function variation_is_purchaseable( $is_purchaseable, $variation ) {
629
630 if ( $this->is_v3 ) {
631 $id = $variation->get_id();
632 } else {
633 $id = $variation->id;
634 }
635
636 if ( ! wp_fusion()->access->user_can_access( $id ) ) {
637 return false;
638 }
639
640 return $is_purchaseable;
641
642 }
643
644 /**
645 * Hide restricted variations
646 *
647 * @access public
648 */
649
650 public function variation_styles() {
651
652 echo '<!-- WP Fusion -->';
653 echo '<style type="text/css">.woocommerce .product .variations option:disabled { display: none; } </style>';
654
655 }
656
657
658 /**
659 * Removes Add to Cart buttons in Store page for restricted products
660 *
661 * @access public
662 * @return string Link
663 */
664
665 public function add_to_cart_buttons( $link, $product ) {
666
667 if ( $this->is_v3 ) {
668 $id = $product->get_id();
669 } else {
670 $id = $product->id;
671 }
672
673 if ( ! wp_fusion()->access->user_can_access( $id ) ) {
674 $link = '';
675 }
676
677 return $link;
678
679 }
680
681 /**
682 * Adapt WooCommerce checkout fields to IS fields for creating customers at checkout
683 *
684 * @access public
685 * @return array Post Data
686 */
687
688 public function user_register( $post_data ) {
689
690 $field_map = array(
691 'account_password' => 'user_pass',
692 'password' => 'user_pass',
693 'billing_email' => 'user_email',
694 'user_login' => 'account_username',
695 'billing_first_name' => 'first_name',
696 'billing_last_name' => 'last_name',
697 'billing_vat_nr' => 'vat_number',
698 'billing_person_company' => 'person_or_company',
699 );
700
701 $post_data = $this->map_meta_fields( $post_data, $field_map );
702
703 // Get the username if autogenerated by Woo
704 if ( empty( $post_data['user_login'] ) ) {
705 $user = get_user_by( 'email', $post_data['user_email'] );
706 $post_data['user_login'] = $user->user_login;
707 }
708
709 return $post_data;
710
711 }
712
713 /**
714 * Format WooCommerce account update fields
715 *
716 * @access public
717 * @return array User Meta
718 */
719
720 public function user_update( $user_meta ) {
721
722 $contact_fields = wp_fusion()->settings->get( 'contact_fields', array() );
723
724 if ( ! empty( $user_meta['billing_country'] ) && isset( $contact_fields['billing_country']['type'] ) && $contact_fields['billing_country']['type'] == 'text' ) {
725
726 // Allow sending full country name instead of abbreviation
727
728 $user_meta['billing_country'] = WC()->countries->countries[ $user_meta['billing_country'] ];
729
730 }
731
732 if ( ! empty( $user_meta['shipping_country'] ) && isset( $contact_fields['shipping_country']['type'] ) && $contact_fields['shipping_country']['type'] == 'text' ) {
733
734 // Allow sending full country name instead of abbreviation
735
736 $user_meta['shipping_country'] = WC()->countries->countries[ $user_meta['shipping_country'] ];
737
738 }
739
740 return $user_meta;
741
742 }
743
744 /**
745 * Gets customer details from the WooCommerce order when customer isn't a registered user
746 *
747 * @access public
748 * @return array Contact Data
749 */
750
751 public function woocommerce_get_customer_data( $order ) {
752
753 $order_data = $order->get_data();
754 $customer_data = array();
755
756 foreach ( $order_data as $key => $value ) {
757
758 if ( is_array( $value ) ) {
759
760 // Nested params like Billing and Shipping info
761 foreach ( $value as $sub_key => $sub_value ) {
762
763 if ( is_object( $sub_value ) ) {
764 continue;
765 }
766
767 $customer_data[ $key . '_' . $sub_key ] = $sub_value;
768
769 }
770 } elseif ( ! is_object( $value ) && ! is_a( $value, 'WC_DateTime' ) ) {
771
772 // Regular params
773 $customer_data[ $key ] = $value;
774
775 }
776 }
777
778 // Meta data
779 foreach ( $order_data['meta_data'] as $meta ) {
780
781 if ( is_a( $meta, 'WC_Meta_Data' ) ) {
782
783 $data = $meta->get_data();
784
785 if ( ! is_array( $data['value'] ) ) {
786
787 $customer_data[ $data['key'] ] = $data['value'];
788
789 }
790 }
791 }
792
793 $contact_fields = wp_fusion()->settings->get( 'contact_fields' );
794
795 $user_id = $order->get_user_id();
796
797 $user = get_userdata( $user_id );
798
799 // Map some common additional fields
800 foreach ( $customer_data as $key => $value ) {
801
802 if ( $key == 'billing_email' ) {
803
804 if ( ! empty( $user_id ) ) {
805
806 $customer_data['user_email'] = $user->user_email;
807
808 } else {
809
810 $customer_data['user_email'] = $value;
811
812 }
813 } elseif ( $key == 'billing_first_name' ) {
814
815 if ( $contact_fields['billing_first_name']['active'] == false || $contact_fields['billing_first_name']['crm_field'] == $contact_fields['first_name']['crm_field'] || empty( $user_id ) ) {
816
817 $customer_data['first_name'] = $value;
818
819 } else {
820
821 $customer_data['first_name'] = $user->first_name;
822
823 }
824 } elseif ( $key == 'billing_vat_nr' ) {
825
826 if ( $contact_fields['billing_vat_nr']['active'] == false || $contact_fields['billing_vat_nr']['crm_field'] == $contact_fields['vat_number']['crm_field'] || empty( $user_id ) ) {
827
828 $customer_data['vat_number'] = $value;
829
830 } else {
831
832 $customer_data['vat_number'] = $user->vat_number;
833
834 }
835 } elseif ( $key == 'billing_person_company' ) {
836
837 if ( $contact_fields['billing_person_company']['active'] == false || $contact_fields['billing_person_company']['crm_field'] == $contact_fields['person_or_company']['crm_field'] || empty( $user_id ) ) {
838
839 $customer_data['person_or_company'] = $value;
840
841 } else {
842
843 $customer_data['person_or_company'] = $user->vat_number;
844
845 }
846 } elseif ( $key == 'billing_last_name' ) {
847
848 if ( $contact_fields['billing_last_name']['active'] == false || $contact_fields['billing_last_name']['crm_field'] == $contact_fields['last_name']['crm_field'] || empty( $user_id ) ) {
849
850 $customer_data['last_name'] = $value;
851
852 } else {
853
854 $customer_data['last_name'] = $user->last_name;
855
856 }
857 } elseif ( $key == 'billing_state' || $key == 'shipping_state' && ! empty( $value ) && isset( WC()->countries->states[ $customer_data['billing_country'] ][ $value ] ) ) {
858
859 $customer_data[ $key ] = WC()->countries->states[ $customer_data['billing_country'] ][ $value ];
860
861 } elseif ( $key == 'billing_country' && ! empty( $value ) && isset( $contact_fields['billing_country']['type'] ) && $contact_fields['billing_country']['type'] == 'text' ) {
862
863 // Allow sending full country name instead of abbreviation
864
865 $customer_data[ $key ] = WC()->countries->countries[ $value ];
866
867 } elseif ( $key == 'shipping_country '&& ! empty( $value ) && isset( $contact_fields['shipping_country']['type'] ) && $contact_fields['shipping_country']['type'] == 'text' ) {
868
869 // Allow sending full country name instead of abbreviation
870
871 $customer_data[ $key ] = WC()->countries->countries[ $value ];
872
873 }
874 }
875
876 $order_date = $order->get_date_paid();
877
878 if ( is_object( $order_date ) && isset( $order_date->date ) ) {
879 $order_date = $order_date->date;
880 } else {
881 $order_date = get_the_date( '', $order->get_id() );
882 }
883
884 $customer_data['order_date'] = $order_date;
885 $customer_data['order_id'] = $order->get_order_number();
886 $customer_data['order_notes'] = $order->get_customer_note();
887
888 // Coupons
889
890 if ( method_exists( $order, 'get_coupon_codes' ) ) {
891
892 $coupons = $order->get_coupon_codes();
893
894 if ( ! empty( $coupons ) ) {
895 $update_data['coupon_code'] = $coupons[0];
896 }
897
898 }
899
900 return apply_filters( 'wpf_woocommerce_customer_data', $customer_data, $order );
901
902 }
903
904 /**
905 * Gets customer details from the WooCommerce order when customer isn't a registered user (pre Woo v3.x)
906 *
907 * @access public
908 * @return array Contact Data
909 */
910
911 public function woocommerce_get_customer_data_deprecated( $order ) {
912
913 $order_data = array();
914
915 foreach ( wp_fusion()->settings->get( 'contact_fields' ) as $field_id => $field_data ) {
916
917 $field = $order->__get( $field_id );
918
919 if ( $field_id == 'user_email' ) {
920
921 // Billing email is technically separate from user_email but we'll simplify that
922 $order_data[ $field_id ] = $order->__get( 'billing_email' );
923
924 } elseif ( $field_id == 'first_name' ) {
925
926 $order_data[ $field_id ] = $order->__get( 'billing_first_name' );
927
928 } elseif ( $field_id == 'vat_number' ) {
929
930 $order_data[ $field_id ] = $order->__get( 'vat_number' );
931
932 } elseif ( $field_id == 'person_or_company' ) {
933
934 $order_data[ $field_id ] = $order->__get( 'person_or_company' );
935
936 } elseif ( $field_id == 'last_name' ) {
937
938 $order_data[ $field_id ] = $order->__get( 'billing_last_name' );
939
940 } elseif ( $field_data['active'] == true && ! empty( $field ) ) {
941
942 // If the field is enabled for sync and the field exists in the order
943 $order_data[ $field_id ] = $order->__get( $field_id );
944
945 }
946 }
947
948 return $order_data;
949
950 }
951
952 /*
953 * Apply tags when a product is purchased in WooCommerce
954 *
955 * @access public
956 * @return void
957 */
958
959 public function woocommerce_apply_tags_checkout( $order_id, $doing_async = false ) {
960
961 // Send async request if async enabled
962 if ( ! is_admin() && wp_fusion()->settings->get( 'woo_async' ) == true && $doing_async == false ) {
963
964 wp_fusion()->batch->quick_add( 'wpf_woocommerce_async_checkout', array( $order_id, true ) );
965 return;
966
967 }
968
969 // Prevents the API calls being sent multiple times for the same order
970
971 if ( get_post_meta( $order_id, 'wpf_complete', true ) ) {
972 return true;
973 }
974
975 // See if checkout process is already running
976 $started = get_transient( 'wpf_woo_started_' . $order_id );
977
978 if ( ! empty( $started ) ) {
979 return true;
980 } else {
981 set_transient( 'wpf_woo_started_' . $order_id, true, HOUR_IN_SECONDS );
982 }
983
984 if ( $this->is_v3 ) {
985 $order = wc_get_order( $order_id );
986 $email = $order->get_billing_email();
987 $user_id = $order->get_user_id();
988 $status = $order->get_status();
989 } else {
990 $order = new WC_Order( $order_id );
991 $email = $order->billing_email;
992 $user_id = $order->customer_user;
993 $status = $order->status;
994 }
995
996 $doing_renewal = false;
997
998 // No need to update meta during a renewal order
999 if ( function_exists( 'wcs_order_contains_renewal' ) && wcs_order_contains_renewal( $order ) ) {
1000
1001 $doing_renewal = true;
1002
1003 }
1004
1005 // Sometimes the status may have changed between when the function was called and when get_status() is run during an automated renewal
1006 if ( 'woocommerce_order_status_failed' == current_filter() ) {
1007 $status = 'failed';
1008 }
1009
1010 // Logger
1011 wp_fusion()->logger->handle( 'info', $user_id, 'New WooCommerce order <a href="' . admin_url( 'post.php?post=' . $order_id . '&action=edit' ) . '" target="_blank">#' . $order_id . '</a>', array( 'source' => 'woocommerce' ) );
1012
1013 if ( empty( $email ) && empty( $user_id ) ) {
1014
1015 wp_fusion()->logger->handle( 'error', 0, 'No email address specified for WooCommerce order <a href="' . admin_url( 'post.php?post=' . $order_id . '&action=edit' ) . '" target="_blank">#' . $order_id . '</a>. Aborting', array( 'source' => 'woocommerce' ) );
1016
1017 delete_transient( 'wpf_woo_started_' . $order_id );
1018
1019 // Denotes that the WPF actions have already run for this order
1020 update_post_meta( $order_id, 'wpf_complete', true );
1021
1022 return false;
1023
1024 }
1025
1026 if ( ! empty( $user_id ) ) {
1027
1028 // If user is found, lookup the contact ID
1029 $contact_id = wp_fusion()->user->get_contact_id( $user_id );
1030
1031 if ( empty( $contact_id ) ) {
1032 // If not found, check in the CRM and update locally
1033 $contact_id = wp_fusion()->user->get_contact_id( $user_id, true );
1034 }
1035 } else {
1036
1037 // Try seeing if an existing contact ID exists
1038 $contact_id = wp_fusion()->crm->get_contact_id( $email );
1039
1040 if ( is_wp_error( $contact_id ) ) {
1041
1042 wp_fusion()->logger->handle( $contact_id->get_error_code(), $user_id, 'Error getting contact ID for <strong>' . $email . '</strong>: ' . $contact_id->get_error_message() );
1043 delete_transient( 'wpf_woo_started_' . $order_id );
1044 return false;
1045
1046 }
1047 }
1048
1049 // Format order data
1050 if ( $this->is_v3 ) {
1051 $order_data = $this->woocommerce_get_customer_data( $order );
1052 } else {
1053 $order_data = $this->woocommerce_get_customer_data_deprecated( $order );
1054 }
1055
1056 // Allow for early exit
1057 if ( empty( $order_data ) ) {
1058 wp_fusion()->logger->handle(
1059 'notice', $user_id, 'Aborted checkout for <a href="' . admin_url( 'post.php?post=' . $order_id . '&action=edit' ) . '" target="_blank">#' . $order_id . '</a>', array(
1060 'source' => 'woocommerce',
1061 'meta_array' => $order_data,
1062 )
1063 );
1064 }
1065
1066 // Don't run during renewals
1067
1068 if( false === $doing_renewal ) {
1069
1070 // If contact doesn't exist in CRM
1071 if ( $contact_id == false ) {
1072
1073 // Logger
1074 wp_fusion()->logger->handle(
1075 'info', 0, 'Processing guest checkout for order <a href="' . admin_url( 'post.php?post=' . $order_id . '&action=edit' ) . '" target="_blank">#' . $order_id . '</a>', array(
1076 'source' => 'woocommerce',
1077 'meta_array' => $order_data,
1078 )
1079 );
1080
1081 $contact_id = wp_fusion()->crm->add_contact( $order_data );
1082
1083 if ( is_wp_error( $contact_id ) ) {
1084
1085 wp_fusion()->logger->handle( 'error', $user_id, 'Error while adding contact: ' . $contact_id->get_error_message(), array( 'source' => wp_fusion()->crm->slug ) );
1086 delete_transient( 'wpf_woo_started_' . $order_id );
1087 return false;
1088
1089 }
1090
1091 $order->add_order_note( wp_fusion()->crm->name . ' contact ID ' . $contact_id . ' created via guest-checkout.' );
1092
1093 // Set contact ID locally
1094 if ( ! empty( $user_id ) ) {
1095 update_user_meta( $user_id, wp_fusion()->crm->slug . '_contact_id', $contact_id );
1096 }
1097
1098 update_post_meta( $order_id, wp_fusion()->crm->slug . '_contact_id', $contact_id );
1099
1100 do_action( 'wpf_guest_contact_created', $contact_id, $order_data['user_email'] );
1101
1102 } else {
1103
1104 if ( empty( $user_id ) ) {
1105
1106 wp_fusion()->logger->handle(
1107 'info', 0, 'Processing guest checkout for order <a href="' . admin_url( 'post.php?post=' . $order_id . '&action=edit' ) . '" target="_blank">#' . $order_id . '</a>, for existing contact ID ' . $contact_id, array(
1108 'source' => 'woocommerce',
1109 'meta_array' => $order_data,
1110 )
1111 );
1112
1113 $result = wp_fusion()->crm->update_contact( $contact_id, $order_data );
1114
1115 if ( is_wp_error( $result ) ) {
1116 wp_fusion()->logger->handle( 'error', $user_id, 'Error while updating contact: ' . $result->get_error_message(), array( 'source' => wp_fusion()->crm->slug ) );
1117 delete_transient( 'wpf_woo_started_' . $order_id );
1118 return false;
1119 }
1120
1121 update_post_meta( $order_id, wp_fusion()->crm->slug . '_contact_id', $contact_id );
1122
1123 do_action( 'wpf_guest_contact_updated', $contact_id, $order_data['user_email'] );
1124
1125 } else {
1126
1127 wp_fusion()->user->push_user_meta( $user_id, $order_data );
1128
1129 }
1130
1131 }
1132
1133 $apply_tags = array();
1134 $remove_tags = array();
1135
1136 // Possibly apply tags for any configured coupons
1137
1138 if ( method_exists( $order, 'get_coupon_codes' ) ) {
1139
1140 $coupons = $order->get_coupon_codes();
1141
1142 if ( ! empty( $coupons ) ) {
1143
1144 foreach ( $coupons as $coupon_code ) {
1145
1146 if ( $this->is_v3 ) {
1147 $coupon_id = wc_get_coupon_id_by_code( $coupon_code );
1148 } else {
1149 $coupon = new WC_Coupon( $coupon_code );
1150 $coupon_id = $coupon->id;
1151 }
1152
1153 $settings = get_post_meta( $coupon_id, 'wpf-settings-woo', true );
1154
1155 if ( ! empty( $settings ) && ! empty( $settings['apply_tags'] ) ) {
1156 $apply_tags = array_merge( $apply_tags, $settings['apply_tags'] );
1157 }
1158
1159 }
1160 }
1161
1162 }
1163
1164 if ( $status != 'failed' && $status != 'pending' ) {
1165
1166 // Get global tags
1167 $global_tags = wp_fusion()->settings->get( 'woo_tags', array() );
1168
1169 if ( is_array( $global_tags ) && ! empty( $global_tags ) ) {
1170 $apply_tags = array_merge( $apply_tags, $global_tags );
1171 }
1172
1173 // Prepare for term stuff
1174 $product_taxonomies = get_object_taxonomies( 'product' );
1175
1176 foreach ( $order->get_items() as $item ) {
1177
1178 if ( $this->is_v3 ) {
1179 $product_id = $item->get_product_id();
1180 } else {
1181 $product_id = $item['product_id'];
1182 }
1183
1184 $settings = get_post_meta( $product_id, 'wpf-settings-woo', true );
1185
1186 // Apply tags for products
1187 if ( ! empty( $settings['apply_tags'] ) ) {
1188 $apply_tags = array_merge( $apply_tags, $settings['apply_tags'] );
1189 }
1190
1191 // Remove transaction failed tags
1192 if ( ! empty( $settings['apply_tags_failed'] ) ) {
1193 $remove_tags = array_merge( $remove_tags, $settings['apply_tags_failed'] );
1194 }
1195
1196 $product = $item->get_product();
1197
1198 $auto_tagging_prefix = wp_fusion()->settings->get( 'woo_tagging_prefix', false );
1199
1200 // Maybe insert the order status
1201 $auto_tagging_prefix = str_replace( '[status]', wc_get_order_status_name( $status ), $auto_tagging_prefix );
1202
1203 if ( ! empty( $auto_tagging_prefix ) ) {
1204 $auto_tagging_prefix = trim( $auto_tagging_prefix ) . ' ';
1205 }
1206
1207 // Handling for deleted products
1208
1209 if ( ! empty( $product ) ) {
1210
1211 // Apply the tags for variations
1212
1213 if ( $product->is_type( 'variation' ) ) {
1214
1215 if ( isset( $settings['apply_tags_variation'] ) && ! empty( $settings['apply_tags_variation'][ $item['variation_id'] ] ) ) {
1216
1217 // Old method where variation settings were stored on the product
1218 $apply_tags = array_merge( $apply_tags, $settings['apply_tags_variation'][ $item['variation_id'] ] );
1219
1220 } else {
1221
1222 $variation_settings = get_post_meta( $item['variation_id'], 'wpf-settings-woo', true );
1223
1224 if ( is_array( $variation_settings ) && isset( $variation_settings['apply_tags_variation'][ $item['variation_id'] ] ) ) {
1225
1226 $apply_tags = array_merge( $apply_tags, $variation_settings['apply_tags_variation'][ $item['variation_id'] ] );
1227
1228 }
1229 }
1230
1231 // For taxonomy tagging we need to exclude attributes
1232
1233 $variation_attributes = $product->get_variation_attributes();
1234
1235 }
1236
1237 // Auto tagging based on name
1238 if ( wp_fusion()->settings->get( 'woo_name_tagging' ) == true ) {
1239
1240 if ( ! in_array( $auto_tagging_prefix . $product->get_title(), $apply_tags ) ) {
1241
1242 $apply_tags[] = $auto_tagging_prefix . $product->get_title();
1243
1244 }
1245 }
1246
1247 // Auto tagging based on SKU
1248 if ( wp_fusion()->settings->get( 'woo_sku_tagging' ) == true ) {
1249
1250 if ( ! in_array( $auto_tagging_prefix . $product->get_sku(), $apply_tags ) ) {
1251
1252 $apply_tags[] = $auto_tagging_prefix . $product->get_sku();
1253
1254 }
1255 }
1256 }
1257
1258 // Term stuff
1259 foreach ( $product_taxonomies as $product_taxonomy ) {
1260
1261 $product_terms = get_the_terms( $product_id, $product_taxonomy );
1262
1263 if ( ! empty( $product_terms ) ) {
1264
1265 foreach ( $product_terms as $term ) {
1266
1267 // For taxonomy tagging we need to exclude attributes
1268
1269 if ( isset( $variation_attributes ) ) {
1270
1271 foreach ( $variation_attributes as $key => $value ) {
1272
1273 $key = str_replace( 'attribute_', '', $key );
1274
1275 if ( $term->taxonomy == $key && $term->slug != $value ) {
1276 continue 2;
1277 }
1278 }
1279 }
1280
1281 $term_tags = get_term_meta( $term->term_id, 'wpf-settings-woo', true );
1282
1283 if ( ! empty( $term_tags ) && ! empty( $term_tags['apply_tags'] ) ) {
1284
1285 $apply_tags = array_merge( $apply_tags, $term_tags['apply_tags'] );
1286
1287 }
1288
1289 if ( $product_taxonomy == 'product_cat' && wp_fusion()->settings->get( 'woo_category_tagging' ) == true ) {
1290
1291 if ( ! in_array( $auto_tagging_prefix . $term->name, $apply_tags ) ) {
1292 $apply_tags[] = $auto_tagging_prefix . $term->name;
1293 }
1294 }
1295 }
1296 }
1297 }
1298 }
1299 } elseif ( $status == 'failed' ) {
1300
1301 foreach ( $order->get_items() as $item ) {
1302
1303 if ( $this->is_v3 ) {
1304 $product_id = $item->get_product_id();
1305 } else {
1306 $product_id = $item['product_id'];
1307 }
1308
1309 $settings = get_post_meta( $product_id, 'wpf-settings-woo', true );
1310
1311 // Apply tags for products
1312 if ( ! empty( $settings['apply_tags_failed'] ) ) {
1313 $apply_tags = array_merge( $apply_tags, $settings['apply_tags_failed'] );
1314 }
1315 }
1316
1317 $order->add_order_note( 'WP Fusion order actions completed for failed payment.' );
1318
1319 }
1320
1321 // Get global status tags
1322
1323 $status_tags = wp_fusion()->settings->get( 'woo_status_tagging_wc-' . $status, array() );
1324
1325 if ( ! empty( $status_tags ) ) {
1326 $apply_tags = array_merge( $apply_tags, $status_tags );
1327 }
1328
1329 // Remove duplicates
1330 $apply_tags = array_unique( $apply_tags );
1331 $remove_tags = array_unique( $remove_tags );
1332
1333 // Remove transaction failed tags
1334 if ( ! empty( $remove_tags ) ) {
1335
1336 if ( empty( $user_id ) ) {
1337
1338 wp_fusion()->crm->remove_tags( $remove_tags, $contact_id );
1339
1340 } else {
1341
1342 // Registered users
1343 wp_fusion()->user->remove_tags( $remove_tags, $user_id );
1344
1345 }
1346 }
1347
1348 // Apply the tags
1349 if ( ! empty( $apply_tags ) ) {
1350
1351 if ( empty( $user_id ) ) {
1352
1353 // Guest checkout
1354 wp_fusion()->logger->handle( 'info', 0, 'Applying tags to guest checkout for contact ID ' . $contact_id . ': ', array( 'tag_array' => $apply_tags ) );
1355 $result = wp_fusion()->crm->apply_tags( $apply_tags, $contact_id );
1356
1357 } else {
1358
1359 // Registered users
1360 $result = wp_fusion()->user->apply_tags( $apply_tags, $user_id );
1361
1362 }
1363
1364 if ( is_wp_error( $result ) ) {
1365 $order->add_order_note( 'Error applying tags for order ID: ' . $order_id );
1366 wp_fusion()->logger->handle( 'error', 0, 'Error <strong>' . $result->get_error_message() . '</strong> while applying tags: ', array( 'tag_array' => $apply_tags ) );
1367 return false;
1368 }
1369 }
1370
1371 } // End check for is_renewal
1372
1373 if ( $status != 'failed' && $status != 'pending' ) {
1374
1375 // Denotes that the WPF actions have already run for this order
1376 update_post_meta( $order_id, 'wpf_complete', true );
1377
1378 // Run payment complete action
1379 do_action( 'wpf_woocommerce_payment_complete', $order_id, $contact_id );
1380
1381 $order->add_order_note( 'WP Fusion order actions completed.' );
1382
1383 }
1384
1385 // Order is finished, remove locking
1386 delete_transient( 'wpf_woo_started_' . $order_id );
1387
1388 }
1389
1390 /*
1391 * Pushes password fields for when Woo is set to auto generate password
1392 *
1393 * @access public
1394 * @return void
1395 */
1396
1397 public function push_autogen_password( $customer_id, $new_customer_data, $password_generated ) {
1398
1399 if ( $password_generated == false ) {
1400 return;
1401 }
1402
1403 wp_fusion()->user->push_user_meta( $customer_id, array( 'user_pass' => $new_customer_data['user_pass'] ) );
1404
1405 }
1406
1407 /**
1408 * Triggered when an order is refunded / cancelled
1409 *
1410 * @access public
1411 * @return void
1412 */
1413
1414 public function woocommerce_order_refunded( $order_id ) {
1415
1416 if ( $this->is_v3 ) {
1417 $order = wc_get_order( $order_id );
1418 $email = $order->get_billing_email();
1419 $user_id = $order->get_user_id();
1420 } else {
1421 $order = new WC_Order( $order_id );
1422 $email = $order->billing_email;
1423 $user_id = $order->customer_user;
1424 }
1425
1426 if ( empty( $user_id ) ) {
1427 $contact_id = wp_fusion()->crm->get_contact_id( $email );
1428 }
1429
1430 if ( empty( $user_id ) && empty( $contact_id ) ) {
1431 wp_fusion()->logger->handle( 'error', 0, 'Unable to process refund actions for order #' . $order_id . '. No user or contact record found.', array( 'source' => 'woocommerce' ) );
1432 }
1433
1434 $items = $order->get_items();
1435
1436 $remove_tags = array();
1437
1438 foreach ( $items as $item ) {
1439
1440 $product_id = $item->get_product_id();
1441
1442 $settings = get_post_meta( $product_id, 'wpf-settings-woo', true );
1443
1444 if ( ! empty( $settings['apply_tags'] ) ) {
1445 $remove_tags = array_merge( $remove_tags, $settings['apply_tags'] );
1446 }
1447
1448 $product = $item->get_product();
1449
1450 if ( ! empty( $product ) ) {
1451
1452 // Auto tagging based on name
1453 if ( wp_fusion()->settings->get( 'woo_name_tagging' ) == true ) {
1454
1455 $remove_tags[] = $product->get_title();
1456
1457 }
1458
1459 // Auto tagging based on SKU
1460 if ( wp_fusion()->settings->get( 'woo_sku_tagging' ) == true ) {
1461
1462 $remove_tags[] = $product->get_sku();
1463
1464 }
1465
1466 }
1467
1468 // Variations
1469 if ( isset( $item['variation_id'] ) && $item['variation_id'] != 0 ) {
1470
1471 if ( isset( $settings['apply_tags_variation'] ) && ! empty( $settings['apply_tags_variation'][ $item['variation_id'] ] ) ) {
1472
1473 $variation_tags = $settings['apply_tags_variation'][ $item['variation_id'] ];
1474
1475 } else {
1476
1477 $variation_settings = get_post_meta( $item['variation_id'], 'wpf-settings-woo', true );
1478
1479 if ( is_array( $variation_settings ) && isset( $variation_settings['apply_tags_variation'][ $item['variation_id'] ] ) ) {
1480
1481 $variation_tags = $variation_settings['apply_tags_variation'][ $item['variation_id'] ];
1482
1483 }
1484 }
1485
1486 if ( ! empty( $variation_tags ) ) {
1487
1488 $remove_tags = array_merge( $remove_tags, $variation_tags );
1489 }
1490 }
1491
1492 if ( ! empty( $settings['apply_tags_refunded'] ) && $order->has_status( 'refunded' ) ) {
1493
1494 if ( ! empty( $user_id ) ) {
1495 wp_fusion()->user->apply_tags( $settings['apply_tags_refunded'], $user_id );
1496 } else {
1497 wp_fusion()->crm->apply_tags( $settings['apply_tags_refunded'], $contact_id );
1498 }
1499 }
1500 }
1501
1502 if ( ! empty( $remove_tags ) ) {
1503
1504 if ( ! empty( $user_id ) ) {
1505 wp_fusion()->user->remove_tags( $remove_tags, $user_id );
1506 } else {
1507 wp_fusion()->crm->remove_tags( $remove_tags, $contact_id );
1508 }
1509 }
1510
1511 }
1512
1513 /**
1514 * Triggered when an order status is changed
1515 *
1516 * @access public
1517 * @return void
1518 */
1519
1520 public function order_status_changed( $order_id, $old_status, $new_status, $order ) {
1521
1522 $status_tags = wp_fusion()->settings->get( 'woo_status_tagging_wc-' . $new_status );
1523
1524 if ( empty( $status_tags ) ) {
1525 return;
1526 }
1527
1528 $user_id = $order->get_user_id();
1529
1530 if ( ! empty( $user_id ) ) {
1531
1532 // Registered users
1533 wp_fusion()->user->apply_tags( $status_tags, $user_id );
1534
1535 } else {
1536
1537 $contact_id = get_post_meta( $order_id, wp_fusion()->crm->slug . '_contact_id', true );
1538
1539 if ( empty( $contact_id ) ) {
1540
1541 $contact_id = wp_fusion()->crm->get_contact_id( $order->get_billing_email() );
1542
1543 }
1544
1545 if ( ! empty( $contact_id ) ) {
1546
1547 wp_fusion()->logger->handle( 'info', 0, 'Order status changed to ' . $new_status . '. Applying tags to ' . $order->get_billing_email() . ':' , array( 'tag_array' => $status_tags, 'source' => 'woocommerce' ) );
1548
1549 wp_fusion()->crm->apply_tags( $status_tags, $contact_id );
1550
1551 }
1552
1553 }
1554
1555 }
1556
1557 /**
1558 * Outputs custom panels to WooCommerce product config screen
1559 *
1560 * @access public
1561 * @return mixed
1562 */
1563
1564 public function woocommerce_write_panels() {
1565
1566 // Add an nonce field so we can check for it later.
1567 wp_nonce_field( 'wpf_meta_box_woo', 'wpf_meta_box_woo_nonce' );
1568
1569 echo '<div id="wp_fusion_tab" class="panel woocommerce_options_panel">';
1570
1571 // Writes the panel content
1572 do_action( 'wpf_woocommerce_panel' );
1573
1574 echo '</div>';
1575
1576 }
1577
1578 /**
1579 * Displays "apply tags" field on the WPF product configuration panel
1580 *
1581 * @access public
1582 * @return mixed
1583 */
1584
1585 public function panel_content() {
1586
1587 global $post;
1588 $settings = array(
1589 'apply_tags' => array(),
1590 'apply_tags_refunded' => array(),
1591 'apply_tags_failed' => array(),
1592 );
1593
1594 if ( get_post_meta( $post->ID, 'wpf-settings-woo', true ) ) {
1595 $settings = array_merge( $settings, get_post_meta( $post->ID, 'wpf-settings-woo', true ) );
1596 }
1597
1598 echo '<div class="options_group wpf-product">';
1599
1600 echo '<p class="form-field"><label><strong>Product</strong></label></p>';
1601
1602 echo '<p class="form-field"><label for="wpf-apply-tags-woo">' . __( 'Apply tags when<br />purchased', 'wp-fusion' ) . '</label>';
1603 wpf_render_tag_multiselect(
1604 array(
1605 'setting' => $settings['apply_tags'],
1606 'meta_name' => 'wpf-settings-woo',
1607 'field_id' => 'apply_tags',
1608 )
1609 );
1610
1611 echo '<br /><span style="margin-left: 0px;" class="description show_if_variable">Tags for product variations can be configured within the Variations tab.</span>';
1612
1613 echo '</p>';
1614
1615 echo '<p class="form-field"><label for="wpf-apply-tags-woo">' . __( 'Apply tags when<br />refunded', 'wp-fusion' );
1616 echo ' <span class="dashicons dashicons-editor-help wpf-tip bottom" data-tip="' . __( 'The tags specified above for \'Apply tags when purchased\' will automatically be removed if an order is refunded.', 'wp-fusion' ) . '"></span>';
1617 echo '</label>';
1618
1619 wpf_render_tag_multiselect(
1620 array(
1621 'setting' => $settings['apply_tags_refunded'],
1622 'meta_name' => 'wpf-settings-woo',
1623 'field_id' => 'apply_tags_refunded',
1624 )
1625 );
1626
1627 echo '</p>';
1628
1629 echo '<p class="form-field"><label for="wpf-apply-tags-woo">' . __( 'Apply tags when transaction failed', 'wp-fusion' ) . '</label>';
1630
1631 wpf_render_tag_multiselect(
1632 array(
1633 'setting' => $settings['apply_tags_failed'],
1634 'meta_name' => 'wpf-settings-woo',
1635 'field_id' => 'apply_tags_failed',
1636 )
1637 );
1638
1639 echo '</p>';
1640
1641 echo '</div>';
1642
1643 }
1644
1645
1646 /**
1647 * Adds tabs to left side of Woo product editor panel
1648 *
1649 * @access public
1650 * @return mixed
1651 */
1652
1653 public function woocommerce_write_panel_tabs() {
1654
1655 echo '<li class="custom_tab linked_product_options hide_if_grouped"><a href="#wp_fusion_tab"><span>WP Fusion</span></a></li>';
1656
1657 }
1658
1659
1660 /**
1661 * Adds tag multiselect to variation fields
1662 *
1663 * @access public
1664 * @return mixed
1665 */
1666
1667 public function variable_fields( $loop, $variation_data, $variation ) {
1668
1669 $defaults = array(
1670 'apply_tags_variation' => array( $variation->ID => array() ),
1671 'allow_tags_variation' => array( $variation->ID => array() ),
1672 );
1673
1674 if ( ! isset( $variation_data['wpf-settings-woo'] ) ) {
1675 $settings = array();
1676 } else {
1677 $settings = maybe_unserialize( $variation_data['wpf-settings-woo'][0] );
1678 }
1679
1680 $settings = array_merge( $defaults, $settings );
1681
1682 echo '<div><p class="form-row form-row-full"><label for="wpf-apply-tags-woo">Apply these tags in ' . wp_fusion()->crm->name . ' when purchased:</label>';
1683
1684 wpf_render_tag_multiselect(
1685 array(
1686 'setting' => $settings['apply_tags_variation'],
1687 'meta_name' => 'wpf-settings-woo-variation',
1688 'field_id' => 'apply_tags_variation',
1689 'field_sub_id' => $variation->ID,
1690 )
1691 );
1692
1693 echo '</p></div>';
1694
1695 // Restrict access to variation
1696 echo '<div><p class="form-row form-row-full"><label for="wpf-allow-tags-woo">Restrict access tags. If the user doesn\'t have <em>any</em> of these tags, the variation will not show as an option for purchase:</label>';
1697
1698 wpf_render_tag_multiselect(
1699 array(
1700 'setting' => $settings['allow_tags_variation'],
1701 'meta_name' => 'wpf-settings-woo-variation',
1702 'field_id' => 'allow_tags_variation',
1703 'field_sub_id' => $variation->ID,
1704 )
1705 );
1706
1707 echo '</p></div>';
1708
1709 }
1710
1711 /**
1712 * Saves variable field data to product
1713 *
1714 * @access public
1715 * @return mixed
1716 */
1717
1718 public function save_variable_fields( $variation_id, $i ) {
1719
1720 if ( isset( $_POST['wpf-settings-woo-variation'] ) ) {
1721 $data = $_POST['wpf-settings-woo-variation'];
1722 } else {
1723 $data = array();
1724 }
1725
1726 // Clean up settings from other variations getting stored with this one
1727
1728 foreach ( $data as $setting_type => $setting ) {
1729
1730 if ( ! empty( $setting ) ) {
1731
1732 foreach ( $setting as $posted_variation_id => $tags ) {
1733
1734 if ( $posted_variation_id != $variation_id ) {
1735
1736 unset( $data[ $setting_type ][ $posted_variation_id ] );
1737
1738 }
1739 }
1740 }
1741 }
1742
1743 // Variation restriction tags (saved as postmeta to the variation ID now that WooCommerce isn't as shitty as it used to be)
1744
1745 update_post_meta( $variation_id, 'wpf-settings-woo', $data );
1746
1747 // Save the normal access restrictions as well so WPF_Access_Control can do its thing
1748
1749 if ( isset( $data['allow_tags_variation'] ) && ! empty( $data['allow_tags_variation'][ $variation_id ] ) ) {
1750
1751 update_post_meta(
1752 $variation_id, 'wpf-settings', array(
1753 'lock_content' => true,
1754 'allow_tags' => $data['allow_tags_variation'][ $variation_id ],
1755 )
1756 );
1757
1758 } else {
1759
1760 delete_post_meta( $variation_id, 'wpf-settings' );
1761
1762 }
1763
1764 // Clean up old data storage
1765
1766 $post_id = $_POST['product_id'];
1767
1768 $post_meta = get_post_meta( $post_id, 'wpf-settings-woo', true );
1769
1770 if ( isset( $post_meta['apply_tags_variation'] ) ) {
1771
1772 unset( $post_meta['apply_tags_variation'] );
1773 update_post_meta( $post_id, 'wpf-settings-woo', $post_meta );
1774
1775 }
1776
1777 }
1778
1779
1780 /**
1781 * Saves WPF configuration to product
1782 *
1783 * @access public
1784 * @return mixed
1785 */
1786
1787 public function save_meta_box_data( $post_id ) {
1788
1789 // Check if our nonce is set.
1790 if ( ! isset( $_POST['wpf_meta_box_woo_nonce'] ) ) {
1791 return;
1792 }
1793
1794 // Verify that the nonce is valid.
1795 if ( ! wp_verify_nonce( $_POST['wpf_meta_box_woo_nonce'], 'wpf_meta_box_woo' ) ) {
1796 return;
1797 }
1798
1799 // If this is an autosave, our form has not been submitted, so we don't want to do anything.
1800 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
1801 return;
1802 }
1803
1804 // Don't update on revisions
1805 if ( $_POST['post_type'] != 'product' ) {
1806 return;
1807 }
1808
1809 if ( isset( $_POST['wpf-settings-woo'] ) ) {
1810 $data = $_POST['wpf-settings-woo'];
1811 } else {
1812 $data = array();
1813 }
1814
1815 // Update the meta field in the database.
1816 update_post_meta( $post_id, 'wpf-settings-woo', $data );
1817
1818 }
1819
1820 /**
1821 * //
1822 * // Order Actions
1823 * //
1824 **/
1825
1826 /**
1827 * Adds WP Fusion option to Order Actions dropdown
1828 *
1829 * @access public
1830 * @return array Actions
1831 */
1832
1833 public function order_actions( $actions ) {
1834
1835 $actions['wpf_process'] = __( 'Process WP Fusion actions again', 'wp-fusion' );
1836 return $actions;
1837
1838 }
1839
1840 /**
1841 * Processes order action
1842 *
1843 * @access public
1844 * @return void
1845 */
1846
1847 public function process_order_action( $order ) {
1848
1849 delete_post_meta( $order->get_id(), 'wpf_complete' );
1850 delete_post_meta( $order->get_id(), 'wpf_ec_complete' );
1851
1852 $this->woocommerce_apply_tags_checkout( $order->get_id() );
1853
1854 }
1855
1856 /**
1857 * //
1858 * // Coupons
1859 * //
1860 **/
1861
1862 /**
1863 * Adds WP Fusion settings tab to coupon config
1864 *
1865 * @access public
1866 * @return array Tabs
1867 */
1868
1869 public function coupon_tabs( $tabs ) {
1870
1871 $tabs['wp_fusion'] = array(
1872 'label' => 'WP Fusion',
1873 'target' => 'wp_fusion_tab',
1874 'class' => '',
1875 );
1876
1877 return $tabs;
1878
1879 }
1880
1881 /**
1882 * Output for coupon data panel
1883 *
1884 * @access public
1885 * @return mixed
1886 */
1887
1888 public function coupon_data_panel() {
1889
1890 echo '<div id="wp_fusion_tab" class="panel woocommerce_options_panel">';
1891
1892 echo '<div class="options_group">';
1893
1894 global $post;
1895
1896 $settings = array(
1897 'apply_tags' => array(),
1898 'auto_apply_tags' => array(),
1899 'coupon_label' => false,
1900 'coupon_applied_msg' => false,
1901 );
1902
1903 if ( get_post_meta( $post->ID, 'wpf-settings-woo', true ) ) {
1904 $settings = array_merge( $settings, get_post_meta( $post->ID, 'wpf-settings-woo', true ) );
1905 }
1906
1907 echo '<p class="form-field"><label><strong>Coupon Settings</strong></label></p>';
1908
1909 echo '<p class="form-field"><label for="wpf-apply-tags-woo">' . __( 'Apply tags when used', 'wp-fusion' ) . '</label>';
1910
1911 wpf_render_tag_multiselect(
1912 array(
1913 'setting' => $settings['apply_tags'],
1914 'meta_name' => 'wpf-settings-woo',
1915 'field_id' => 'apply_tags',
1916 )
1917 );
1918
1919 echo '</p>';
1920
1921 echo '</div>';
1922 echo '<div class="options_group">';
1923
1924 echo '<p class="form-field"><label><strong>Auto-apply Discounts</strong></label></p>';
1925
1926 echo '<p class="form-field"><label>' . __( 'Auto-apply tags', 'wp-fusion' ) . '</label>';
1927
1928 wpf_render_tag_multiselect(
1929 array(
1930 'setting' => $settings['auto_apply_tags'],
1931 'meta_name' => 'wpf-settings-woo',
1932 'field_id' => 'auto_apply_tags',
1933 )
1934 );
1935
1936 echo '<span class="description"><small>' . __( 'If the user has any of the tags specified here, the coupon will automatically be applied to their cart.', 'wp-fusion' ) . '</small></span>';
1937
1938 echo '</p>';
1939
1940 echo '<p class="form-field"><label>' . __( 'Discount label', 'wp-fusion' ) . '</label>';
1941
1942 echo '<input type="text" class="short" style="" name="wpf-settings-woo[coupon_label]" value="' . $settings['coupon_label'] . '" placeholder="Coupon">';
1943
1944 echo '<span class="description" style="display: block; clear: both; margin-left: 0px;"><small>' . __( 'Use this setting to override the coupon label at checkout when a coupon has been auto-applied.<br />For example "Discount" or "Promo". (Leave blank for default)', 'wp-fusion' ) . '</small></span>';
1945
1946 echo '</p>';
1947
1948 echo '<p class="form-field"><label>' . __( 'Discount message', 'wp-fusion' ) . '</label>';
1949
1950 echo '<input type="text" class="short" style="" name="wpf-settings-woo[coupon_applied_msg]" value="' . $settings['coupon_applied_msg'] . '" placeholder="Coupon code applied successfully.">';
1951
1952 echo '<span class="description" style="display: block; clear: both; margin-left: 0px;"><small>' . __( 'Use this setting to override the message at checkout when a coupon has been auto-applied.<br />For example "You received a discount!". (Leave blank for default)', 'wp-fusion' ) . '</small></span>';
1953
1954 echo '</p>';
1955
1956 echo '<br />';
1957
1958 do_action( 'wpf_woocommerce_coupon_panel', $post->ID, $settings );
1959
1960 echo '</div>';
1961
1962 echo '</div>';
1963
1964 }
1965
1966 /**
1967 * Output for coupon usage restriction settings
1968 *
1969 * @access public
1970 * @return mixed
1971 */
1972
1973 public function coupon_usage_restriction( $coupon_id, $coupon ) {
1974
1975 $settings = array(
1976 'allow_tags' => array(),
1977 );
1978
1979 if ( get_post_meta( $coupon_id, 'wpf-settings', true ) ) {
1980 $settings = array_merge( $settings, get_post_meta( $coupon_id, 'wpf-settings', true ) );
1981 }
1982
1983 echo '<div class="options_group">';
1984
1985 echo '<p class="form-field"><label>' . __( 'Required tags', 'wp-fusion' ) . '</label>';
1986
1987 wpf_render_tag_multiselect(
1988 array(
1989 'setting' => $settings['allow_tags'],
1990 'meta_name' => 'wpf-settings',
1991 'field_id' => 'allow_tags',
1992 )
1993 );
1994
1995 echo '<span class="description"><small>' . __( 'The user must be logged in and have one of the specified tags to use the coupon.', 'wp-fusion' ) . '</small></span>';
1996
1997 echo '</p>';
1998
1999 echo '</div>';
2000
2001 }
2002
2003 /**
2004 * Saves WPF configuration to product
2005 *
2006 * @access public
2007 * @return mixed
2008 */
2009
2010 public function save_meta_box_data_coupon( $post_id ) {
2011
2012 // Don't update on revisions
2013 if ( $_POST['post_type'] == 'revision' ) {
2014 return;
2015 }
2016
2017 if ( isset( $_POST['wpf-settings-woo'] ) ) {
2018
2019 $data = $_POST['wpf-settings-woo'];
2020
2021 } else {
2022 $data = array();
2023 }
2024
2025 // Update coupon-specific stuff
2026
2027 update_post_meta( $post_id, 'wpf-settings-woo', $data );
2028
2029 // Update coupon restrictions
2030
2031 if ( isset( $_POST['wpf-settings'] ) ) {
2032
2033 $_POST['wpf-settings']['lock_content'] = true;
2034
2035 $data = $_POST['wpf-settings'];
2036
2037 update_post_meta( $post_id, 'wpf-settings', $data );
2038
2039 } else {
2040 delete_post_meta( $post_id, 'wpf-settings' );
2041 }
2042
2043 }
2044
2045 /**
2046 * Check if coupon is valid before applying
2047 *
2048 * @access public
2049 * @return bool Valid
2050 */
2051
2052 public function coupon_is_valid( $valid, $coupon, $discount ) {
2053
2054 if ( ! wp_fusion()->access->user_can_access( $coupon->get_id() ) ) {
2055 $valid = false;
2056 }
2057
2058 return $valid;
2059
2060 }
2061
2062 /**
2063 * Applies any linked coupons when a product is added to the cart
2064 *
2065 * @access public
2066 * @return void
2067 */
2068
2069 public function add_to_cart_apply_coupon() {
2070
2071 if ( ! is_user_logged_in() ) {
2072 return;
2073 }
2074
2075 $args = array(
2076 'numberposts' => 100,
2077 'post_type' => 'shop_coupon',
2078 'fields' => 'ids',
2079 'meta_query' => array(
2080 array(
2081 'key' => 'wpf-settings-woo',
2082 'compare' => 'EXISTS',
2083 ),
2084 ),
2085 );
2086
2087 $coupons = get_posts( $args );
2088
2089 if ( empty( $coupons ) ) {
2090 return;
2091 }
2092
2093 $user_tags = wp_fusion()->user->get_tags();
2094
2095 if ( empty( $user_tags ) ) {
2096 return;
2097 }
2098
2099 foreach ( $coupons as $coupon_id ) {
2100
2101 $settings = get_post_meta( $coupon_id, 'wpf-settings-woo', true );
2102
2103 if ( empty( $settings['auto_apply_tags'] ) ) {
2104 continue;
2105 }
2106
2107 if ( ! empty( array_intersect( $settings['auto_apply_tags'], $user_tags ) ) ) {
2108
2109 $coupon = new WC_Coupon( $coupon_id );
2110
2111 if ( ! WC()->cart->has_discount( $coupon->get_code() ) ) {
2112
2113 WC()->cart->apply_coupon( $coupon->get_code() );
2114
2115 }
2116 }
2117 }
2118
2119 }
2120
2121 /**
2122 * Applies any linked coupons when tags are modified
2123 *
2124 * @access public
2125 * @return void
2126 */
2127
2128 public function maybe_apply_coupons( $user_id, $user_tags ) {
2129
2130 if ( is_admin() || empty( WC()->cart ) || ! did_action( 'wp_loaded' ) ) {
2131 return;
2132 }
2133
2134 $args = array(
2135 'numberposts' => 200,
2136 'post_type' => 'shop_coupon',
2137 'fields' => 'ids',
2138 'meta_query' => array(
2139 array(
2140 'key' => 'wpf-settings-woo',
2141 'compare' => 'EXISTS',
2142 ),
2143 ),
2144 );
2145
2146 $coupons = get_posts( $args );
2147
2148 if ( empty( $coupons ) ) {
2149 return;
2150 }
2151
2152 foreach ( $coupons as $coupon_id ) {
2153
2154 $settings = get_post_meta( $coupon_id, 'wpf-settings-woo', true );
2155
2156 if ( empty( $settings['auto_apply_tags'] ) ) {
2157 continue;
2158 }
2159
2160 if ( ! empty( array_intersect( $settings['auto_apply_tags'], $user_tags ) ) ) {
2161
2162 $coupon = new WC_Coupon( $coupon_id );
2163
2164 if ( ! WC()->cart->has_discount( $coupon->get_code() ) ) {
2165
2166 WC()->cart->apply_coupon( $coupon->get_code() );
2167
2168 }
2169 }
2170 }
2171
2172 }
2173
2174 /**
2175 * Renames coupon fields for auto-applied coupons
2176 *
2177 * @access public
2178 * @return void
2179 */
2180
2181 public function rename_coupon_label( $label, $coupon ) {
2182
2183 $settings = get_post_meta( $coupon->get_id(), 'wpf-settings-woo', true );
2184
2185 if ( ! empty( $settings ) && ! empty( $settings['coupon_label'] ) ) {
2186
2187 return $settings['coupon_label'];
2188
2189 }
2190
2191 return $label;
2192
2193 }
2194
2195 /**
2196 * Allows overriding the coupon success message
2197 *
2198 * @access public
2199 * @return string Coupon success message
2200 */
2201
2202 public function coupon_success_message( $msg, $msg_code, $coupon ) {
2203
2204 $settings = get_post_meta( $coupon->get_id(), 'wpf-settings-woo', true );
2205
2206 if ( ! empty( $settings ) && ! empty( $settings['coupon_applied_msg'] ) ) {
2207
2208 return $settings['coupon_applied_msg'];
2209
2210 }
2211
2212 return $msg;
2213
2214 }
2215
2216
2217 /**
2218 * Allow access control rules to do redirects on the Shop page
2219 *
2220 * @access public
2221 * @return void
2222 */
2223
2224 public function restrict_access_to_shop() {
2225
2226 if ( is_shop() ) {
2227
2228 $post_id = get_option( 'woocommerce_shop_page_id' );
2229
2230 // If user can access, return without doing anything
2231 if ( wp_fusion()->access->user_can_access( $post_id ) == true ) {
2232 return;
2233 }
2234
2235 // Get redirect URL for the post
2236 $redirect = wp_fusion()->access->get_redirect( $post_id );
2237
2238 $redirect = apply_filters( 'wpf_redirect_url', $redirect, $post_id );
2239
2240 if ( ! empty( $redirect ) ) {
2241
2242 wp_redirect( $redirect );
2243 exit();
2244
2245 }
2246 }
2247
2248 }
2249
2250
2251 /**
2252 * Hides the coupon fields on cart / checkout if enabled
2253 *
2254 * @access public
2255 * @return bool
2256 */
2257
2258 public function hide_coupon_field_on_cart( $enabled ) {
2259
2260 if ( wp_fusion()->settings->get( 'woo_hide_coupon_field' ) == true ) {
2261
2262 if ( is_cart() || is_checkout() ) {
2263 $enabled = false;
2264 }
2265 }
2266
2267 return $enabled;
2268
2269 }
2270
2271
2272 /**
2273 * //
2274 * // TAXONOMIES
2275 * //
2276 **/
2277
2278 /**
2279 * Add settings to taxonomies
2280 *
2281 * @access public
2282 * @return void
2283 */
2284
2285 public function register_taxonomy_form_fields() {
2286
2287 $product_taxonomies = get_object_taxonomies( 'product' );
2288
2289 foreach ( $product_taxonomies as $slug ) {
2290 add_action( $slug . '_edit_form_fields', array( $this, 'taxonomy_form_fields' ), 10, 2 );
2291 add_action( 'edited_' . $slug, array( $this, 'save_taxonomy_form_fields' ), 10, 2 );
2292 }
2293
2294 }
2295
2296 /**
2297 * Output settings to taxonomies
2298 *
2299 * @access public
2300 * @return mixed HTML Output
2301 */
2302
2303 public function taxonomy_form_fields( $term ) {
2304
2305 ?>
2306
2307 <tr class="form-field">
2308 <th style="padding-bottom: 0px;" colspan="2"><h3>WP Fusion - WooCommerce Settings</h3></th>
2309 </tr>
2310
2311 <tr class="form-field">
2312 <th scope="row" valign="top"><label for="wpf-apply-tag-product"><?php _e( 'Apply tags when a product with this term is purchased', 'wp-fusion' ); ?></label></th>
2313 <td style="max-width: 400px;">
2314 <?php
2315
2316 // retrieve values for tags to be applied
2317 $settings = get_term_meta( $term->term_id, 'wpf-settings-woo', true );
2318
2319 if ( empty( $settings ) ) {
2320 $settings = array( 'apply_tags' => array() );
2321 }
2322
2323 $args = array(
2324 'setting' => $settings['apply_tags'],
2325 'meta_name' => 'wpf-settings-woo',
2326 'field_id' => 'apply_tags',
2327 );
2328
2329 wpf_render_tag_multiselect( $args );
2330 ?>
2331
2332 </td>
2333 </tr>
2334
2335 <?php
2336
2337 }
2338
2339 /**
2340 * Save taxonomy settings
2341 *
2342 * @access public
2343 * @return void
2344 */
2345
2346 public function save_taxonomy_form_fields( $term_id ) {
2347
2348 if ( ! empty( $_POST['wpf-settings-woo'] ) ) {
2349
2350 update_term_meta( $term_id, 'wpf-settings-woo', $_POST['wpf-settings-woo'] );
2351
2352 }
2353
2354 }
2355
2356
2357 /**
2358 * //
2359 * // BATCH TOOLS
2360 * //
2361 **/
2362
2363 /**
2364 * Adds WooCommerce checkbox to available export options
2365 *
2366 * @access public
2367 * @return array Options
2368 */
2369
2370 public function export_options( $options ) {
2371
2372 $options['woocommerce'] = array(
2373 'label' => 'WooCommerce orders',
2374 'title' => 'Orders',
2375 'tooltip' => 'Finds WooCommerce orders that have not been processed by WP Fusion, and adds/updates contacts while applying tags based on the products purchased',
2376 );
2377
2378 return $options;
2379
2380 }
2381
2382 /**
2383 * Counts total number of orders to be processed
2384 *
2385 * @access public
2386 * @return int Count
2387 */
2388
2389 public function batch_init() {
2390
2391 $args = array(
2392 'numberposts' => - 1,
2393 'post_type' => 'shop_order',
2394 'post_status' => array( 'wc-processing', 'wc-completed' ),
2395 'fields' => 'ids',
2396 'order' => 'ASC',
2397 'meta_query' => array(
2398 array(
2399 'key' => 'wpf_complete',
2400 'compare' => 'NOT EXISTS',
2401 ),
2402 ),
2403 );
2404
2405 $orders = get_posts( $args );
2406
2407 wp_fusion()->logger->handle( 'info', 0, 'Beginning <strong>WooCommerce Orders</strong> batch operation on ' . count( $orders ) . ' orders', array( 'source' => 'batch-process' ) );
2408
2409 return $orders;
2410
2411 }
2412
2413 /**
2414 * Processes order actions in batches
2415 *
2416 * @access public
2417 * @return void
2418 */
2419
2420 public function batch_step( $order_id ) {
2421
2422 $this->woocommerce_apply_tags_checkout( $order_id, true );
2423
2424 }
2425
2426 /**
2427 * Check for Woo < 3.x
2428 *
2429 * @access public
2430 * @return mixed
2431 */
2432
2433 public function compatibility_test() {
2434
2435 global $woocommerce;
2436
2437 if ( version_compare( $woocommerce->version, '3.0', '<' ) ) {
2438 $this->is_v3 = false;
2439 }
2440
2441 }
2442
2443 /**
2444 * Clear orphaned cron jobs
2445 *
2446 * @access public
2447 * @return void
2448 */
2449
2450 public function clear_cron() {
2451
2452 if ( isset( $_GET['wpf_clear_cron'] ) ) {
2453
2454 $cron = get_option( 'cron' );
2455
2456 foreach ( $cron as $key => $cron_data ) {
2457
2458 reset( $cron_data );
2459 $action = key( $cron_data );
2460
2461 if ( $action == 'wpf_subscription_status_hold' ) {
2462 unset( $cron[ $key ] );
2463 }
2464 }
2465
2466 update_option( 'cron', $cron );
2467
2468 }
2469 }
2470
2471 /**
2472 * Support utilities
2473 *
2474 * @access public
2475 * @return void
2476 */
2477
2478 public function settings_page_init() {
2479
2480 if ( isset( $_GET['woo_reset_wpf_complete'] ) ) {
2481
2482 $args = array(
2483 'numberposts' => - 1,
2484 'post_type' => 'shop_order',
2485 'post_status' => array( 'wc-processing', 'wc-completed' ),
2486 'fields' => 'ids',
2487 'meta_query' => array(
2488 array(
2489 'key' => 'wpf_complete',
2490 'compare' => 'EXISTS',
2491 ),
2492 ),
2493 );
2494
2495 $orders = get_posts( $args );
2496
2497 foreach ( $orders as $order_id ) {
2498 delete_post_meta( $order_id, 'wpf_complete' );
2499 }
2500
2501 echo '<div id="setting-error-settings_updated" class="updated settings-error"><p><strong>Success:</strong><code>wpf_complete</code> meta key removed from ' . count( $orders ) . ' orders.</p></div>';
2502
2503 }
2504
2505 }
2506
2507}
2508
2509new WPF_Woocommerce();