PluginProbe
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell / 3.10.9
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell v3.10.9
3.13.3 3.13.2 3.13.1 3.13.0 3.12.13 3.12.12 3.12.11 3.12.10 3.12.9 3.12.8 3.12.7 3.12.6 3.12.5 3.12.4 3.12.3 3.12.1 3.12.2 3.12.0 3.11.1 3.11.0 3.10.9 3.10.8 3.10.7 3.10.6 2.8.16 All 261 releases
wpfunnels / includes / utils / class-wpfnl-functions.php

class-wpfnl-functions.php in WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell 3.10.9, at includes/utils/class-wpfnl-functions.php

6,374 lines 220.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * This class is responsible for all the helper functions
4 *
5 * @package WPFunnels
6 */
7 namespace WPFunnels;
8
9 use ElementorPro\Modules\WpCli\Update;
10 use WPFunnels\Metas\Wpfnl_Step_Meta_keys;
11 use WPFunnels\Discount\WpfnlDiscount;
12
13 class Wpfnl_functions {
14
15 public static $installed_plugins;
16
17 /**
18 * Get all the steps of the funnel
19 *
20 * @param $funnel_id
21 *
22 * @return array|mixed
23 */
24 public static function get_steps($funnel_id) {
25 if (!is_int($funnel_id) && !is_string($funnel_id)) {
26 // Throw an error or handle this case as appropriate for your application
27 throw new \InvalidArgumentException('Funnel ID must be an integer or a string');
28 }
29
30 $steps = get_post_meta($funnel_id, '_steps_order', true);
31 if (!is_array($steps)) {
32 $steps = array();
33 }
34 return $steps;
35 }
36
37
38 /**
39 * Check if the associated order is from a funnel.
40 *
41 * This function checks if the given order is associated with a funnel.
42 * It returns true if the order is from a funnel, and false otherwise.
43 * Previously 'get_funnel_id_from_order' function parameter was order id but from 2.8.0 version it changed to order object
44 *
45 * @param \WC_Order $order The WooCommerce order object.
46 * @return bool True if the order is from a funnel, false otherwise.
47 * @since 2.8.0
48 */
49 public static function check_if_funnel_order( $order ) {
50 if ( false === is_a( $order, 'WC_Order' ) ) {
51 return false;
52 }
53
54 $funnel_id = self::get_funnel_id_from_order( $order );
55 if ( ! $funnel_id ) {
56 return false;
57 }
58 return true;
59 }
60
61
62 /**
63 * Get the associated funnel ID from the order ID.
64 *
65 * This function retrieves the ID of the associated funnel for a given order.
66 * Previously data was retrieved by post meta table but from 2.8.0 version user get_meta function to retrieve meta
67 *
68 * @param \WC_Order|Int $order The WooCommerce order object or Order ID of WooCommerce order.
69 * @return int|false The ID of the associated funnel, or false if not found.
70 * @since 2.8.0
71 */
72 public static function get_funnel_id_from_order( $order ) {
73 if ( ! $order ) {
74 return false;
75 }
76
77 if ( false === is_a( $order, 'WC_Order' ) ) {
78 $order_id = intval( $order );
79 $order = wc_get_order( $order_id );
80 if ( false === is_a( $order, 'WC_Order' ) ) {
81 return false;
82 }
83 }
84
85 $funnel_id = $order->get_meta( '_wpfunnels_funnel_id' ) ? $order->get_meta( '_wpfunnels_funnel_id' ) : $order->get_meta( '_wpfunnels_parent_funnel_id' );
86 if ( ! $funnel_id ) {
87 return false;
88 }
89 return intval( $funnel_id );
90 }
91
92 /**
93 * Check if the given string is a date or not
94 *
95 * @param $date
96 *
97 * @return bool
98 * @since 1.0.0
99 */
100 public static function validate_date( $date ) {
101 return (bool) strtotime( $date );
102 }
103
104 /**
105 * Define constant if it is not set yet
106 *
107 * @param $name
108 * @param $value
109 *
110 * @since 2.0.3
111 */
112 public static function maybe_define_constant( $name, $value ) {
113 if ( ! defined( $name ) ) {
114 define( $name, $value );
115 }
116 }
117
118 /**
119 * Set do not cache constants
120 */
121 public static function do_not_cache() {
122 global $post;
123
124 if ( ! apply_filters( 'wpfunnels/do_not_cache', true, $post->ID ) ) {
125 return;
126 }
127 self::maybe_define_constant( 'DONOTCACHEPAGE', true );
128 self::maybe_define_constant( 'DONOTCACHEOBJECT', true );
129 self::maybe_define_constant( 'DONOTCACHEDB', true );
130 nocache_headers();
131 }
132
133 /**
134 * Return formatted date from the
135 * given date object
136 *
137 * @param $date
138 *
139 * @return false|string
140 * @since 1.0.0
141 */
142 public static function get_formatted_date( $date ) {
143 return date( 'Y-m-d h:i A', strtotime( $date ) );
144 }
145
146
147 /**
148 * Get checkout ID
149 *
150 * @return bool|int
151 */
152 public static function get_checkout_id_from_post_data() {
153 $checkout_id = ! empty( $_POST['_wpfunnels_checkout_id'] ) ? filter_var( wp_unslash( $_POST['_wpfunnels_checkout_id'] ), FILTER_SANITIZE_NUMBER_INT ) : false;
154 return $checkout_id ? intval( $checkout_id ) : false;
155 }
156
157
158 /**
159 * Get checkout id from post
160 *
161 * @return bool|int
162 */
163 public static function get_checkout_id_from_post( $post = null ) {
164 if ( is_array( $post ) && ! empty( $post['_wpfunnels_checkout_id'] ) ) {
165 $checkout_id = filter_var( wp_unslash( $post['_wpfunnels_checkout_id'] ), FILTER_SANITIZE_NUMBER_INT );
166 return $checkout_id ? intval( $checkout_id ) : false;
167 }
168
169 if ( is_array( $post ) && isset( $post['post_data'] ) ) {
170 $post_data = array();
171 wp_parse_str( wp_unslash( $post['post_data'] ), $post_data );
172 if ( ! empty( $post_data['_wpfunnels_checkout_id'] ) ) {
173 $checkout_id = filter_var( $post_data['_wpfunnels_checkout_id'], FILTER_SANITIZE_NUMBER_INT );
174 return $checkout_id ? intval( $checkout_id ) : false;
175 }
176 }
177 return false;
178 }
179
180
181 /**
182 * Check order bump clicked or not from post data
183 *
184 * @return bool True|False
185 * @since 2.8.0
186 */
187 public static function is_orderbump_clicked_from_post_data() {
188 if ( ! empty( $_POST['post_data'] ) ) {
189 wp_parse_str( $_POST['post_data'], $post_data );
190 return ! empty( $post_data['_wpfunnels_order_bump_clicked'] ) && 'yes' === $post_data['_wpfunnels_order_bump_clicked'];
191 }
192 return ! empty( $_POST['_wpfunnels_order_bump_clicked'] ) && 'yes' === $_POST['_wpfunnels_order_bump_clicked'];
193 }
194
195
196 /**
197 * Check checkoutify order bump clicked or not from post data
198 *
199 * @return bool True|False
200 * @since 2.8.0
201 */
202 public static function is_checkoutify_orderbump_clicked_from_post_data() {
203 if ( ! empty( $_POST['post_data'] ) ) {
204 wp_parse_str( $_POST['post_data'], $post_data );
205 return ! empty( $post_data['checkoutify_orderbump_clicked'] ) && 'yes' === $post_data['checkoutify_orderbump_clicked'];
206 }
207 return ! empty( $_POST['checkoutify_orderbump_clicked'] ) && 'yes' === $_POST['checkoutify_orderbump_clicked'];
208 }
209
210
211 /**
212 * Check qunatity select or not from post data
213 *
214 * @return bool True|False
215 * @since 2.8.0
216 */
217 public static function maybe_select_quantity_from_post_data() {
218 if ( ! empty( $_POST['post_data'] ) ) {
219 $post_data = array();
220 wp_parse_str( $_POST['post_data'], $post_data );
221 return ! empty( $post_data['_wpfunnels_select_quantity'] ) && 'yes' === $post_data['_wpfunnels_select_quantity'];
222 }
223 return ! empty( $_POST['_wpfunnels_select_quantity'] ) && 'yes' === $_POST['_wpfunnels_select_quantity'];
224 }
225
226
227
228 /**
229 * Check variation is selected or not from post data
230 *
231 * @return bool True|False
232 * @since 2.8.0
233 */
234 public static function is_variation_selected_from_post_data() {
235 if ( ! empty( $_POST['post_data'] ) ) {
236 wp_parse_str( $_POST['post_data'], $post_data );
237 return ! empty( $post_data['_wpfunnels_variable_product'] ) && 'selected' === $post_data['_wpfunnels_variable_product'];
238 }
239 return ! empty( $_POST['_wpfunnels_variable_product'] ) && 'selected' === $_POST['_wpfunnels_variable_product'];
240 }
241
242
243 /**
244 * Check product option is selected or not from post data
245 *
246 * @return bool True|False
247 * @since 2.8.0
248 */
249 public static function is_product_option_from_post_data() {
250 if ( ! empty( $_POST['post_data'] ) ) {
251 wp_parse_str( $_POST['post_data'], $post_data );
252 return ! empty( $post_data['_wpfunnels_product_option'] ) && 'selected' === $post_data['_wpfunnels_product_option'];
253 }
254 return ! empty( $_POST['_wpfunnels_product_option'] ) && 'selected' === $_POST['_wpfunnels_product_option'];
255 }
256
257
258 /**
259 * Check variation is selected or not from post data
260 *
261 * @return bool True|False
262 * @since 2.8.0
263 */
264 public static function is_coupon_applied_from_post_data() {
265 if ( ! empty( $_POST['post_data'] ) ) {
266 wp_parse_str( $_POST['post_data'], $post_data );
267 return ! empty( $post_data['_wpfunnels_auto_coupon'] ) && 'yes' === $post_data['_wpfunnels_auto_coupon'];
268 }
269 return ! empty( $_POST['_wpfunnels_auto_coupon'] ) && 'yes' === $_POST['_wpfunnels_auto_coupon'];
270 }
271
272
273 /**
274 * Get funnel id
275 *
276 * @param $step_id
277 *
278 * @return mixed
279 */
280 public static function get_funnel_id_from_step( $step_id ) {
281 $funnel_id = get_post_meta( $step_id, '_funnel_id', true );
282 return intval( $funnel_id );
283 }
284
285 /**
286 * Get order id from funnel post data
287 *
288 * @return false|int
289 * @since 2.8.2
290 */
291 public static function get_order_id_from_post_data() {
292 if ( ! empty( $_POST['_wpfunnels_order_unique_identifier'] ) ) {
293 global $wpdb;
294 $identifier = wp_unslash( $_POST['_wpfunnels_order_unique_identifier'] );
295 $prepare_guery = $wpdb->prepare( "SELECT `post_id` FROM {$wpdb->postmeta} WHERE meta_key ='_wpfunnels_order_unique_identifier' and meta_value like '%s'", $identifier );
296 $get_value = $wpdb->get_row( $prepare_guery );
297 return $get_value ? intval( $get_value->post_id ) : false;
298 }
299 return false;
300 }
301
302
303 /**
304 * Get checkout id from order
305 *
306 * @param $order_id
307 *
308 * @return int
309 */
310 public static function get_checkout_id_from_order( $order_id ) {
311 if ( !self::is_wc_active() ) {
312 return false;
313 }
314
315 $order = wc_get_order( $order_id );
316
317 if ( false === is_a( $order, 'WC_Order' ) ) {
318 return false;
319 }
320
321 $checkout_id = $order->get_meta( '_wpfunnels_checkout_id' );
322 return $checkout_id ? intval( $checkout_id ) : false;
323 }
324
325
326 /**
327 * Get funnel from post data
328 *
329 * @return bool|int
330 */
331 public static function get_funnel_id_from_post_data() {
332 if ( ! empty( $_POST['_wpfunnels_funnel_id'] ) ) {
333 $funnel_id = filter_var( wp_unslash( $_POST['_wpfunnels_funnel_id'] ), FILTER_SANITIZE_NUMBER_INT );
334 return $funnel_id ? intval( $funnel_id ) : false;
335 }
336 return false;
337 }
338
339
340 /**
341 * Get funnel id from step page
342 *
343 * @return false|mixed
344 */
345 public static function get_funnel_id() {
346 global $post;
347 if ( $post ) {
348 $funnel_id = get_post_meta( $post->ID, '_funnel_id', true );
349 return $funnel_id ? intval( $funnel_id ) : false;
350 }
351 return false;
352 }
353
354 /**
355 * Unserialize data
356 *
357 * @param $data
358 *
359 * @return mixed
360 * @since 1.0.0
361 */
362 public static function unserialize_array_data( $data ) {
363 return maybe_unserialize( $data );
364 }
365
366
367 /**
368 * Get formatted string with phrase
369 * e.g: 1 item if singular or
370 * 2 items if plural
371 *
372 * @param Int $number
373 * @param String $singular
374 * @param String $plural
375 *
376 * @return String
377 * @since 1.0.0
378 */
379 public static function get_formatted_data_with_phrase( $number, $singular = '', $plural = 's' ) {
380 return ( is_numeric( $number ) && 0 <= $number ) ? ( 1 < $number ? $plural : $singular ) : null;
381 }
382
383
384 /**
385 * Get formatted string from funnel status
386 *
387 * @param $status
388 *
389 * @return string
390 * @since 1.0.0
391 */
392 public static function get_formatted_status( $status ) {
393 switch ( $status ) {
394 case 'publish':
395 return 'Published';
396 case 'draft':
397 return 'Draft';
398 default:
399 return $status;
400 }
401 }
402
403
404 /**
405 * Generate active class for funnel menus
406 *
407 * @param $key
408 *
409 * @return bool
410 * @since 1.0.0
411 */
412 public static function define_active_class($key)
413 {
414 $page = filter_input(INPUT_GET, 'page', FILTER_SANITIZE_SPECIAL_CHARS);
415 if ($page === WPFNL_FUNNEL_PAGE_SLUG && $key === 'overview') {
416 return true;
417 }
418
419 if ( $page === 'create_funnel' && $key === 'create_funnel' ) {
420 return true;
421 }
422
423 if ( $page === 'wpfnl_automations' && $key === 'automations' ) {
424 return true;
425 }
426
427 if ( $page === 'wpfnl_settings' && $key === 'settings' ) {
428 return true;
429 }
430
431 if ( $page === WPFNL_ADDONS_SLUG && $key === 'addons' ) {
432 return true;
433 }
434
435 if ( $page === 'wpfunnels_integrations' && $key === 'integrations' ) {
436 return true;
437 }
438
439 if ( $page === WPFNL_TEMPLATE_PAGE_SLUG && $key === 'templates' ) {
440 return true;
441 }
442
443 if ( $page === WPFNL_STORE_CHECKOUT_SLUG && $key === 'store_checkout' ) {
444 return true;
445 }
446
447 return false;
448 }
449
450
451 /**
452 * Check If module exists or not
453 *
454 * @param $id
455 *
456 * @return bool
457 * @since 1.0.0
458 */
459 public static function check_if_module_exists( $id ) {
460 return 'publish' === get_post_status( $id ) || 'draft' === get_post_status( $id ) || 'trash' === get_post_status( $id );
461 }
462
463
464 /**
465 * Check if the cpt is step or not
466 *
467 * @param $step_id
468 * @param string $type
469 *
470 * @return bool
471 */
472 public static function check_if_this_is_step_type_by_id( $step_id, $type = 'landing' ) {
473 $post_type = get_post_type( $step_id );
474 if ( WPFNL_STEPS_POST_TYPE === $post_type ) {
475 if ( $type === get_post_meta( $step_id, '_step_type', true ) ) {
476 return true;
477 }
478 }
479 return false;
480 }
481
482
483 /**
484 * Get thankyou page id
485 *
486 * @param $funnel_id
487 *
488 * @return bool|mixed
489 *
490 * @since 2.2.6
491 */
492 public static function get_thankyou_page_id( $funnel_id ) {
493 $steps = self::get_steps( $funnel_id );
494 if ( is_array( $steps ) ) {
495 foreach ( $steps as $step ) {
496 if ( 'thankyou' === $step['step_type'] ) {
497 return $step['id'];
498 }
499 }
500 }
501 return false;
502 }
503
504
505 /**
506 * Check if the current post type is step or not
507 *
508 * @return bool
509 * @since 2.0.3
510 */
511 public static function is_funnel_step_page( $post_type = '' ) {
512 if ( self::get_current_post_type( $post_type ) === WPFNL_STEPS_POST_TYPE ) {
513 return true;
514 }
515
516 $post_id = null;
517 if ( wp_doing_ajax() || isset( $_GET['wc-ajax'] ) ) {
518 $post_id = self::get_checkout_id_from_post( $_POST );
519 }
520 global $post;
521
522 if ( ! $post_id ) {
523 $post_id = get_the_ID();
524 }
525 $post = $post_id ? get_post( $post_id ) : $post;
526
527 $post_type = $post->post_type ?? '';
528 if ( self::get_current_post_type( $post_type ) === WPFNL_STEPS_POST_TYPE ) {
529 return true;
530 }
531
532 return false;
533 }
534
535
536 /**
537 * Get current post type
538 *
539 * @param $post_type
540 *
541 * @return string
542 *
543 * @since 2.3.5
544 */
545 public static function get_current_post_type( $post_type ) {
546 global $post;
547 if ( '' === $post_type && is_object( $post ) ) {
548 $post_type = $post->post_type;
549 } else {
550 $post_id = '';
551 if ( wp_doing_ajax() || isset( $_GET['wc-ajax'] ) ) {
552 $post_id = self::get_checkout_id_from_post( $_POST );
553 }
554
555 if ( $post_id ) {
556 $post = get_post( $post_id );
557 $post_type = $post->post_type;
558 }
559 }
560 return $post_type;
561 }
562
563
564 /**
565 * Check if funnel checkout page
566 *
567 * @param $funnel_id
568 *
569 * @return bool
570 */
571 public static function is_funnel_checkout_page() {
572 if ( isset( $_POST['post_data'] ) ) {
573 parse_str( $_POST['post_data'], $post_data );
574 if ( isset( $post_data['_wpfunnels_checkout_id'] ) ) {
575 return array(
576 'status' => true,
577 'id' => $post_data['_wpfunnels_checkout_id'],
578 );
579 }
580 }
581 return array(
582 'status' => false,
583 'id' => '',
584 );
585 }
586
587
588 /**
589 * Check if funnel exists
590 *
591 * @param $funnel_id
592 *
593 * @return bool
594 */
595 public static function is_funnel_exists( $funnel_id ) {
596 if (!is_int($funnel_id) && !is_string($funnel_id)) {
597 // Throw an error or handle this case as appropriate for your application
598 throw new \InvalidArgumentException('Funnel ID must be an integer or a string');
599 }
600
601 if ( ! $funnel_id ) {
602 return false;
603 }
604
605 if ( false === get_post_status( $funnel_id ) ) {
606 return true;
607 }
608 return false;
609 }
610
611
612 /**
613 * Function to check if the current page is a post edit page
614 *
615 * @return bool
616 *
617 * @since 2.0.3
618 */
619 public static function is_step_edit_page() {
620
621 $step_id = -1;
622 if ( is_admin() && isset( $_REQUEST['action'] ) ) {
623 if ( 'edit' === $_REQUEST['action'] && isset( $_GET['post'] ) ) {
624 $step_id = isset( $_GET['post'] ) ? $_GET['post'] : - 1;
625 } elseif ( isset( $_REQUEST['wpfunnels_gb'] ) && isset( $_POST['post_id'] ) ){ //phpcs:ignore
626 $step_id = intval( $_POST['post_id'] ); //phpcs:ignore
627 }
628 if ( $step_id === - 1 ) {
629
630 return false;
631 }
632 $get_post_type = get_post_type( $step_id );
633 if ( WPFNL_STEPS_POST_TYPE === $get_post_type ) {
634 return true;
635 }
636 }
637 return false;
638 }
639
640
641 /**
642 * Check if the cpt is step or not
643 *
644 * @param string $type
645 *
646 * @return bool
647 * @since 1.0.0
648 */
649 public static function check_if_this_is_step_type( $type = 'landing' ) {
650 $post_type = get_post_type();
651
652 if ( WPFNL_STEPS_POST_TYPE === $post_type ) {
653 global $post;
654 if ( $type === get_post_meta( $post->ID, '_step_type', true ) ) {
655 return true;
656 }
657 }
658 return false;
659 }
660
661
662 /**
663 * Check if the cpt is step or not
664 *
665 * @param string $type
666 *
667 * @return bool
668 * @since 1.0.0
669 */
670 public static function check_if_this_is_lms_step() {
671 global $post;
672 if( ! $post ) {
673 return false;
674 }
675 $funnel_id = get_post_meta( $post->ID, '_funnel_id', true );
676
677 if (! $funnel_id ) {
678 return false;
679 }
680
681 $funnel_type = get_post_meta( $funnel_id, '_wpfnl_funnel_type', true );
682
683 return $funnel_type === 'lms';
684 }
685
686
687 /**
688 * Hooks for start and end the journey
689 * of a funnel
690 */
691 public static function start_journey() {
692 $post_type = get_post_type();
693 if ( WPFNL_STEPS_POST_TYPE === $post_type ) {
694 global $post;
695 $step_id = $post->ID;
696 $funnel_id = self::get_funnel_id_from_step( $step_id );
697 $steps = self::get_steps( $funnel_id );
698 $funnel_data = self::get_funnel_data( $funnel_id );
699 // start the journey
700 if ( $steps && is_array( $steps ) ) {
701 if ( $steps[0]['id'] === $step_id ) {
702 do_action( 'wpfunnels/funnel_journey_starts', $step_id, $funnel_id );
703 }
704 }
705
706 // end the journey
707 if ( $funnel_data && isset( $funnel_data['drawflow']['Home']['data'] ) ) {
708 $funnel_data = $funnel_data['drawflow']['Home']['data'];
709 foreach ( $funnel_data as $data ) {
710 $info = $data['data'];
711 $step_type = $info['step_type'];
712
713 if ( 'conditional' !== $step_type ) {
714 $_step_id = isset( $info['step_id'] ) ? $info['step_id'] : '';
715 $output_con = $data['outputs'];
716
717 if ( empty( $output_con ) ) {
718 if ( $_step_id === $step_id ) {
719 do_action( 'wpfunnels/funnel_journey_end', $step_id, $funnel_id );
720 delete_option( 'optin_data' );
721 break;
722 }
723 }
724 }
725 }
726 }
727 }
728 }
729
730
731 /**
732 * Conditional node logic check
733 *
734 * @param $funnel_id
735 * @param $order
736 * @param $condition_identifier
737 * @param $current_page_id
738 * @param $checker
739 *
740 * @return bool
741 *
742 * @since 2.0.2
743 */
744 public static function check_condition( $funnel_id, $order, $condition_identifier, $current_page_id, $checker = 'accept' ) {
745 $group_conditions = get_post_meta( $funnel_id, $condition_identifier, true );
746
747 if ( $group_conditions ) {
748 // Loop through group condition.
749 foreach ( $group_conditions as $group ) {
750 if ( empty( $group ) ) {
751 continue;
752 }
753
754 $match_group = true;
755 // Loop over rules and determine if all rules match.
756 foreach ( $group as $rule ) {
757 if ( ! self::match_rule( $funnel_id, $rule, $order, $current_page_id, $checker ) ) {
758 $match_group = false;
759 break;
760 }
761 }
762
763 // If this group matches, show the field group.
764 if ( $match_group ) {
765 return true;
766 } else {
767 return false;
768 }
769 }
770 }
771 if ( $checker == 'accept' ) {
772 return true;
773 }
774 // Return default.
775 return false;
776 }
777
778
779 /**
780 * Check if rule is matched
781 *
782 * @param $rule
783 * @param $order
784 * @param $current_page_id
785 * @param $checker
786 *
787 * @return mixed
788 *
789 * @since 2.0.2
790 */
791 public static function match_rule( $funnel_id, $rule, $order, $current_page_id, $checker ) {
792 if ( isset( $rule['field'] ) && $rule['field'] == 'downsell' ) {
793 $rule['field'] = 'upsell';
794 }
795 $condition = $rule['field'];
796 if ( strpos( $rule['field'], 'optin' ) ) {
797 $condition = 'optin';
798 }
799 $checker_function = $condition . '_condition_checker';
800 return self::$checker_function( $funnel_id, $rule, $order, $current_page_id, $checker );
801 }
802
803
804 /**
805 * Upsell condition checker for conditional step
806 *
807 * @param Integer $funnel_id
808 * @param Array $data
809 * @param Object $order
810 * @param Integer $current_page_id
811 * @param String $checker
812 *
813 * @return Boolean
814 *
815 * @since 2.5.7
816 */
817 public static function upsell_condition_checker( $funnel_id, $data, $order, $current_page_id, $checker ) {
818
819 if ( $data['value'] == 'yes' ) {
820 if ( $checker == 'accept' ) {
821 return true;
822 } else {
823 return false;
824 }
825 } elseif ( $data['value'] == 'no' ) {
826
827 if ( $checker == 'reject' ) {
828 return true;
829 } else {
830 return false;
831 }
832 }
833 return false;
834 }
835
836
837 /**
838 * Optin condition checker for conditional step
839 *
840 * @param Integer $funnel_id
841 * @param Array $data
842 * @param Object $order
843 * @param Integer $current_page_id
844 * @param String $checker
845 *
846 * @return Boolean
847 *
848 * @since 2.5.7
849 */
850 public function optin_condition_checker( $funnel_id, $rule, $data, $current_page_id, $checker = 'accept' ) {
851
852 if ( isset( $data['step_id'] ) ) {
853 $step_id = str_replace( 'optin_', '', $data['step_id'] );
854 $optin_steps = get_option( 'optin_data' );
855 if ( isset( $optin_steps['optin_data'] ) ) {
856 $key = array_search( $step_id, array_column( $optin_steps['optin_data'], 'step_id' ) );
857 if ( false !== $key ) {
858 unset( $optin_steps[ $key ] );
859 update_option( 'optin_data', $optin_steps );
860 return true;
861 }
862 }
863 } elseif ( ! empty( $data['cta'] ) ) {
864 return false;
865 }
866
867 if ( isset( $rule['field'] ) ) {
868 $step_id = str_replace( 'optin_', '', $rule['field'] );
869 $optin_steps = get_option( 'optin_data' );
870 if ( isset( $optin_steps['optin_data'] ) ) {
871 $key = array_search( $step_id, array_column( $optin_steps['optin_data'], 'step_id' ) );
872 if ( false !== $key ) {
873 unset( $optin_steps[ $key ] );
874 update_option( 'optin_data', $optin_steps );
875 return true;
876 }
877 }
878 }
879
880 return false;
881 }
882
883
884 /**
885 * Order bump condition checker
886 *
887 * @param $data
888 * @param $order
889 * @param $current_page_id
890 *
891 * @return bool
892 */
893 public static function orderbump_condition_checker( $funnel_id, $data, $order, $current_page_id, $checker = 'accept' ) {
894 $order_bump_accepted = '';
895 if ( self::is_wc_active() ) {
896 $order_bump_accepted = WC()->session->get( 'order_bump_accepted' );
897 }
898 return $data['value'] == $order_bump_accepted;
899 }
900
901
902 /**
903 * Check cart total condition in conditional node
904 *
905 * @param $data
906 * @param $order
907 * @param $current_page_id
908 *
909 * @return bool
910 */
911 public static function carttotal_condition_checker( $funnel_id, $data, $order, $current_page_id, $checker = 'accept' ) {
912 $cart_total = $order->get_total();
913
914 $checker = false;
915 if ( $data['condition'] == 'greater' ) {
916 if ( $cart_total > $data['value'] ) {
917 $checker = true;
918 }
919 } elseif ( $data['condition'] == 'equal' ) {
920 if ( $cart_total == $data['value'] ) {
921 $checker = true;
922 }
923 } elseif ( $data['condition'] == 'less' ) {
924 if ( $cart_total < $data['value'] ) {
925 $checker = true;
926 }
927 }
928 return $checker;
929 }
930
931
932 /**
933 * Billing country condition checker
934 *
935 * @param Array
936 * @param Object
937 * @param String
938 * @param String
939 *
940 * @return Bool
941 * @since 2.4.18
942 */
943 public static function billing_condition_checker( $funnel_id, $data, $order, $current_page_id, $checker ) {
944 if ( $order ) {
945 $billing_country = $order->get_billing_country();
946 if ( isset( $data['field'] ) && 'billing' === $data['field'] && isset( $data['value'] ) && $billing_country === $data['value'] ) {
947 return true;
948 }
949 }
950 return false;
951 }
952
953
954 /**
955 * Shipping country condition checker
956 *
957 * @param Array
958 * @param Object
959 * @param String
960 * @param String
961 *
962 * @return Bool
963 * @since 2.4.18
964 */
965 public static function shipping_condition_checker( $funnel_id, $data, $order, $current_page_id, $checker ) {
966 if ( $order ) {
967 $shipping_country = $order->get_shipping_country();
968 if ( isset( $data['field'] ) && 'shipping' === $data['field'] && isset( $data['value'] ) && $shipping_country === isset( $data['value'] ) ) {
969 return true;
970 }
971 }
972 return false;
973 }
974
975
976 /**
977 * Get next step of the
978 * funnel
979 *
980 * @param $funnel_id
981 * @param $step_id
982 * @param bool $condition
983 *
984 * @return Mix
985 *
986 * @since 1.0.0
987 */
988 public static function get_next_step( $funnel_id, $step_id, $condition = true ) {
989 if ( ! $funnel_id || ! $step_id ) {
990 return false;
991 }
992 $parent_step_id = get_post_meta( $step_id, '_parent_step_id', true );
993 if ( $parent_step_id ) {
994 $step_id = $parent_step_id;
995 }
996
997 $funnel_data = self::get_funnel_data( $funnel_id );
998
999 if ( ! $funnel_data || ! isset( $funnel_data['drawflow']['Home']['data'] ) ) {
1000 return false;
1001 }
1002
1003 $node_id = self::get_node_id( $funnel_id, $step_id );
1004 $node_data = $funnel_data['drawflow']['Home']['data'];
1005
1006 if ( ! is_array( $node_data ) || empty( $node_data ) ) {
1007 return false;
1008 }
1009
1010 $next_node_id = '';
1011
1012 foreach ( $node_data as $node_key => $node_value ) {
1013 if ( $node_value['id'] != $node_id ) {
1014 continue;
1015 }
1016
1017 if ( $condition ) {
1018 $next_node_id = isset( $node_value['outputs']['output_1']['connections'][0]['node'] ) ? $node_value['outputs']['output_1']['connections'][0]['node'] : '';
1019 } else {
1020 $next_node_id = isset( $node_value['outputs']['output_2']['connections'][0]['node'] ) ? $node_value['outputs']['output_2']['connections'][0]['node'] : '';
1021 }
1022
1023 if ( ! $next_node_id ) {
1024 self::redirect_to_deafult_thankyou();
1025 }
1026
1027 $next_step_id = self::get_step_by_node( $funnel_id, $next_node_id );
1028 $next_step_type = self::get_node_type( $node_data, $next_node_id );
1029
1030 return apply_filters(
1031 'wpfunnels/next_step_data',
1032 array(
1033 'step_id' => $next_step_id,
1034 'step_type' => $next_step_type,
1035 )
1036 );
1037
1038 }
1039
1040 return false;
1041 }
1042
1043
1044 /**
1045 * Redirect deafult thank you page
1046 */
1047 public static function redirect_to_deafult_thankyou() {
1048
1049 if ( isset( $_POST['order_id'] ) && $_POST['order_id'] ) {
1050 $url = home_url() . '/checkout/order-received/' . $_POST['order_id'] . '/?key=' . $_POST['order_key'];
1051 return $url;
1052 } else {
1053 add_action(
1054 'template_redirect',
1055 function( $order_id ) {
1056 if ( isset( $_GET['order-received'] ) && $_GET['order-received'] ) {
1057 $url = '';
1058 $url = add_query_arg( 'id', $_GET['order-received'], $url );
1059 wp_safe_redirect( wp_sanitize_redirect( esc_url_raw( $url ) ) );
1060 exit;
1061 } elseif ( isset( $_POST['order_id'] ) && $_POST['order_id'] ) {
1062 $url = '';
1063 $url = add_query_arg( 'id', $_POST['order_id'], $url );
1064 wp_safe_redirect( wp_sanitize_redirect( esc_url_raw( $url ) ) );
1065 exit;
1066 }
1067 }
1068 );
1069 }
1070 }
1071
1072
1073 /**
1074 * Get previous step of the
1075 * funnel
1076 *
1077 * @param $funnel_id
1078 * @param $step_id
1079 * @param bool $condition
1080 *
1081 * @return Mix
1082 *
1083 * @since 1.0.0
1084 */
1085 public static function get_prev_step( $funnel_id, $step_id, $condition = true ) {
1086 if ( $funnel_id && ! $step_id ) {
1087 return false;
1088 }
1089 $funnel_data = self::get_funnel_data( $funnel_id );
1090 if ( $funnel_data ) {
1091 $node_id = self::get_node_id( $funnel_id, $step_id );
1092 $node_data = $funnel_data['drawflow']['Home']['data'];
1093
1094 foreach ( $node_data as $node_key => $node_value ) {
1095 if ( $node_value['id'] == $node_id ) {
1096 if ( $condition ) {
1097 if ( ! empty( $node_value['inputs'] ) ) {
1098 $prev_node_id = $node_value['inputs']['input_1']['connections'][0]['node'];
1099 } else {
1100 $prev_node_id = '';
1101 }
1102 } else {
1103 if ( ! empty( $node_value['inputs'] ) ) {
1104 $prev_node_id = $node_value['inputs']['input_2']['connections'][0]['node'];
1105 } else {
1106 $prev_node_id = '';
1107 }
1108 }
1109 $prev_step_id = self::get_step_by_node( $funnel_id, $prev_node_id );
1110 $prev_step_type = self::get_node_type( $node_data, $prev_node_id );
1111 if ( $prev_step_type == 'conditional' ) {
1112 return self::get_prev_step( $funnel_id, $prev_step_id );
1113
1114 } else {
1115
1116 return array(
1117 'step_id' => $prev_step_id,
1118 'step_type' => $prev_step_type,
1119 );
1120 }
1121 }
1122 }
1123 }
1124 return false;
1125 }
1126
1127 /**
1128 * Get node type
1129 */
1130 public static function get_node_type( $node_data, $node_id ) {
1131 foreach ( $node_data as $node_key => $node_value ) {
1132 if ( $node_value['id'] == $node_id ) {
1133 return $node_value['data']['step_type'];
1134 }
1135 }
1136 }
1137
1138 /**
1139 * Get step by node
1140 */
1141 public static function get_step_by_node( $funnel_id, $node_id ) {
1142 if ( ! $funnel_id && ! $node_id ) {
1143 return false;
1144 }
1145
1146 $funnel_data = self::get_funnel_data( $funnel_id );
1147
1148 if ( ! $funnel_data || ! isset( $funnel_data['drawflow']['Home']['data'] ) || ! is_array( $funnel_data['drawflow']['Home']['data'] ) ) {
1149 return false;
1150 }
1151
1152 foreach ( $funnel_data['drawflow']['Home']['data'] as $key => $data ) {
1153 if ( isset( $data['id'] ) && isset( $data['data']['step_id'] ) && $node_id == $data['id'] ) {
1154 return $data['data']['step_id'];
1155 }
1156 }
1157 return false;
1158 }
1159
1160
1161 /**
1162 * Get node by step
1163 *
1164 * @param $funnel_id
1165 * @param $step_id
1166 *
1167 * @return bool|int|string
1168 */
1169 public static function get_node_id( $funnel_id, $step_id ) {
1170 if ( ! $funnel_id && ! $step_id ) {
1171 return false;
1172 }
1173
1174 $funnel_data = self::get_funnel_data( $funnel_id );
1175
1176 if ( ! $funnel_data || ! isset( $funnel_data['drawflow']['Home']['data'] ) || ! is_array( $funnel_data['drawflow']['Home']['data'] ) ) {
1177 return false;
1178 }
1179
1180 foreach ( $funnel_data['drawflow']['Home']['data'] as $key => $data ) {
1181 if ( isset( $data['id'] ) && isset( $data['data']['step_id'] ) && $step_id == $data['data']['step_id'] ) {
1182 return $data['id'];
1183 }
1184 }
1185 return false;
1186 }
1187
1188
1189 /**
1190 * Get funnel data
1191 *
1192 * @param $funnel_id
1193 *
1194 * @return mixed
1195 *
1196 * @since 2.0.5
1197 */
1198 public static function get_funnel_data( $funnel_id ) {
1199 return get_post_meta( $funnel_id, '_funnel_data', true );
1200 }
1201
1202
1203 /**
1204 * Update settings option
1205 *
1206 * @param $key
1207 * @param $value
1208 * @param bool $network
1209 *
1210 * @since 1.0.0
1211 */
1212 public static function update_admin_settings( $key, $value, $network = false ) {
1213 if ( $network && is_multisite() ) {
1214 update_site_option( $key, $value );
1215 } else {
1216 update_option( $key, $value );
1217 }
1218 }
1219
1220
1221 /**
1222 * Get admin settings option
1223 * by key
1224 *
1225 * @param $key
1226 * @param bool $default
1227 * @param bool $network
1228 *
1229 * @return mixed|void
1230 * @since 1.0.0
1231 */
1232 public static function get_admin_settings( $key, $default = false, $network = false ) {
1233 if ( $network && is_multisite() ) {
1234 $value = get_site_option( $key, $default );
1235 } else {
1236 $value = get_option( $key, $default );
1237 }
1238 return $value;
1239 }
1240
1241
1242 /**
1243 * Get general settings data
1244 *
1245 * @return array
1246 * @since 1.0.0
1247 */
1248 public static function get_general_settings() {
1249 $default_settings = apply_filters(
1250 'wpfunnels_general_settings',
1251 array(
1252 'builder' => 'gutenberg',
1253 'paypal_reference' => 'off',
1254 'order_bump' => 'off',
1255 'ab_testing' => 'off',
1256 'allow_funnels' => array( 'administrator' => 'true' ),
1257 'funnel_type' => 'sales',
1258 'create_child_order' => 'off',
1259 'disable_theme_style' => 'off',
1260 'enable_log_status' => 'off',
1261 'enable_skip_cart' => 'off',
1262 'skip_cart_for' => 'whole',
1263 'uninstall_cleanup' => 'off',
1264 )
1265 );
1266 $saved_settings = self::get_admin_settings( '_wpfunnels_general_settings', $default_settings );
1267 return wp_parse_args( $saved_settings, $default_settings );
1268 }
1269
1270
1271 /**
1272 * Get permalink settings data
1273 *
1274 * @return array
1275 * @since 1.0.0
1276 */
1277 public static function get_permalink_settings() {
1278 $default_settings = apply_filters(
1279 'wpfunnels_permalink_settings',
1280 array(
1281 'structure' => 'default',
1282 'step_base' => WPFNL_STEPS_POST_TYPE,
1283 'funnel_base' => WPFNL_FUNNELS_POST_TYPE,
1284 )
1285 );
1286 $saved_settings = self::get_admin_settings( '_wpfunnels_permalink_settings' );
1287 return wp_parse_args( $saved_settings, $default_settings );
1288 }
1289
1290 /**
1291 * Get optin settings data
1292 *
1293 * @return array|string
1294 * @since 1.0.0
1295 */
1296 public static function get_optin_settings( $handler = '' ) {
1297 $default_settings = apply_filters(
1298 'wpfunnels_optin_settings',
1299 array(
1300 'sender_name' => get_bloginfo('name'),
1301 'sender_email' => wp_get_current_user()->user_email,
1302 'email_subject' => 'New Form Submission',
1303 )
1304 );
1305 $saved_settings = self::get_admin_settings( '_wpfunnels_optin_settings' );
1306 $settings = wp_parse_args( $saved_settings, $default_settings );
1307 return $handler && isset($settings[$handler]) ? $settings[$handler] : $settings;
1308 }
1309
1310
1311 /**
1312 * Get offer settings data
1313 *
1314 * @return array
1315 * @since 1.0.0
1316 */
1317 public static function get_offer_settings() {
1318 $default_settings = apply_filters(
1319 'wpfunnels/get_offer_settings',
1320 array(
1321 'offer_orders' => 'main-order',
1322 'show_supported_payment_gateway' => 'off',
1323 'skip_offer_step' => 'off',
1324 'skip_offer_step_for_free' => 'off',
1325 'enable_global_thankyou' => 'off',
1326 )
1327 );
1328 $saved_settings = self::get_admin_settings( '_wpfunnels_offer_settings' );
1329 return wp_parse_args( $saved_settings, $default_settings );
1330 }
1331
1332 /**
1333 * Get GTM events
1334 *
1335 * @return array
1336 */
1337 public static function get_gtm_events() {
1338 $default_gtm_events = array(
1339 'add_to_cart' => 'Add to cart',
1340 'begin_checkout' => 'Begin checkout',
1341 'add_payment_info' => 'Add Payment Info',
1342 'add_shipping_info' => 'Add Shipping Info',
1343 'purchase' => 'Purchase',
1344 'orderbump_accept' => 'Order Bump',
1345 'upsell' => 'Upsell',
1346 'downsell' => 'Downsell',
1347 );
1348 return $default_gtm_events;
1349 }
1350
1351 public static function get_gtm_settings() {
1352 $default_enable_settings = array(
1353 'gtm_enable' => 'off',
1354 'gtm_container_id' => '',
1355 'gtm_events' => array(
1356 'add_to_cart' => 'true',
1357 'begin_checkout' => 'true',
1358 'add_payment_info' => 'true',
1359 'add_shipping_info' => 'true',
1360 'purchase' => 'true',
1361 'orderbump_accept' => 'true',
1362 'upsell' => 'true',
1363 'downsell' => 'true',
1364 ),
1365 );
1366 $gtm_settings = self::get_admin_settings( '_wpfunnels_gtm' );
1367 return wp_parse_args( $gtm_settings, $default_enable_settings );
1368 }
1369 /**
1370 * Get facebook pixel events
1371 *
1372 * @return array
1373 */
1374 public static function get_facebook_events() {
1375 $default_fb_events = array(
1376 'AddPaymentInfo' => 'Add payment info',
1377 'AddToCart' => 'Add to cart',
1378 'InitiateCheckout' => 'Initiate checkout',
1379 // 'Lead' => 'Lead',
1380 'Purchase' => 'Purchase',
1381 'ViewContent' => 'View content',
1382 );
1383 return $default_fb_events;
1384 }
1385
1386 public static function get_facebook_pixel_settings() {
1387 $default_enable_settings = array(
1388 'enable_fb_pixel' => 'off',
1389 'facebook_pixel_id' => '',
1390 'facebook_tracking_events' => array(
1391 'AddPaymentInfo' => 'true',
1392 'AddToCart' => 'true',
1393 'InitiateCheckout' => 'true',
1394 'Lead' => 'true',
1395 'Purchase' => 'true',
1396 'ViewContent' => 'true',
1397 ),
1398 );
1399 $facebook_pixel_setting = self::get_admin_settings( '_wpfunnels_facebook_pixel' );
1400 return wp_parse_args( $facebook_pixel_setting, $default_enable_settings );
1401 }
1402
1403
1404 public static function get_recaptcha_settings() {
1405 $default_enable_settings = array(
1406 'enable_recaptcha' => 'no',
1407 'recaptcha_site_key' => '',
1408 'recaptcha_site_secret' => '',
1409 );
1410 $recaptcha_setting = self::get_admin_settings( '_wpfunnels_recaptcha_setting' );
1411 return wp_parse_args( $recaptcha_setting, $default_enable_settings );
1412 }
1413
1414
1415 /**
1416 * Get user role management settings
1417 *
1418 * @return array|mixed|void
1419 *
1420 * @since 3.1.3
1421 */
1422 public static function get_user_role_settings() {
1423 global $wp_roles;
1424
1425 $user_role_names = array_keys( $wp_roles->get_names() );
1426 $user_role_names = array_diff( $user_role_names, array( 'administrator' ) );
1427
1428 $default_settings = array();
1429
1430 foreach ( $user_role_names as $user_role_name ) {
1431 if( 'subscriber' === $user_role_name || 'customer' === $user_role_name ) {
1432 continue;
1433 }
1434 $default_settings[ $user_role_name ] = 'no';
1435 }
1436
1437 $user_role_manager = self::get_admin_settings( '_wpfunnels_user_roles' );
1438 $user_role_manager = wp_parse_args( $user_role_manager, $default_settings );
1439 return $user_role_manager;
1440 }
1441
1442
1443 /*
1444 * Get google place API key
1445 *
1446 * @return mixed|void
1447 * @since 3.1.3
1448 */
1449 public static function get_google_map_api_key() {
1450 return self::get_admin_settings( '_wpfunnels_google_map_api_key', '' );
1451 }
1452
1453
1454 /**
1455 * Get notification settings
1456 *
1457 * @return array
1458 * @since 3.2.0
1459 */
1460 public static function get_notification_settings() {
1461 $default_notification_settings = array(
1462 'enable_revenue_report' => 'no',
1463 'revenue_report_frequency' => 'weekly',
1464 'revenue_report_recipient' => get_option('admin_email'),
1465 'revenue_report_subject' => 'Store Revenue Report - {period}',
1466 'send_time' => '10:00',
1467 );
1468
1469 $notification_settings = self::get_admin_settings( '_wpfunnels_notification_settings' );
1470 return wp_parse_args( $notification_settings, $default_notification_settings );
1471 }
1472
1473
1474 /**
1475 * Get advanced settings
1476 */
1477 public static function get_advanced_settings() {
1478 $default_enable_settings = array(
1479 'show_supported_payment_gateway' => 'off',
1480 );
1481
1482 $advanced_settings = self::get_admin_settings( '_wpfunnels_advanced_settings' );
1483 return wp_parse_args( $advanced_settings, $default_enable_settings );
1484 }
1485
1486 /**
1487 * Get UTM Parameters
1488 *
1489 * @return array
1490 */
1491 public static function get_utm_params() {
1492 $default_utm_params = array(
1493 'utm_source' => 'UTM Source',
1494 'utm_medium' => 'UTM Medium',
1495 'utm_campaign' => 'UTM Campaign',
1496 'utm_content' => 'UTM Content',
1497 );
1498 return $default_utm_params;
1499 }
1500
1501 public static function get_utm_settings() {
1502 $default_enable_settings = array(
1503 'utm_enable' => 'off',
1504 'utm_source' => '',
1505 'utm_medium' => '',
1506 'utm_campaign' => '',
1507 'utm_content' => '',
1508 );
1509 $utm_settings = self::get_admin_settings( '_wpfunnels_utm_params' );
1510 return wp_parse_args( $utm_settings, $default_enable_settings );
1511 }
1512
1513 /**
1514 * Get user roles
1515 *
1516 * @return array
1517 * @since 2.1.7
1518 */
1519 public static function get_user_roles() {
1520 global $wp_roles;
1521 $all_roles = $wp_roles->roles;
1522 return array_keys( $all_roles );
1523 }
1524
1525
1526 /**
1527 * Get the saved builder type
1528 *
1529 * @return mixed|void
1530 * @since 1.0.0
1531 */
1532 public static function get_builder_type() {
1533 $general_settings = self::get_general_settings();
1534 return $general_settings['builder'];
1535 }
1536
1537
1538 /**
1539 * Check if wc is installed
1540 *
1541 * @return bool
1542 * @since 1.0.0
1543 */
1544 public static function is_wc_active() {
1545 if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
1546 return true;
1547 } elseif ( function_exists( 'is_plugin_active' ) ) {
1548 if ( is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
1549 return true;
1550 }
1551 }
1552 return false;
1553 }
1554
1555 /**
1556 * Check if woocommerce payment is activated or not
1557 *
1558 * @return bool
1559 * @since 1.9.0
1560 */
1561 public static function is_wc_payment_active() {
1562 if ( defined( 'WCPAY_PLUGIN_FILE' ) ) {
1563 return true;
1564 }
1565 return false;
1566 }
1567
1568
1569 /**
1570 * Check if elementor is installed
1571 *
1572 * @return bool
1573 * @since 1.0.0
1574 */
1575 public static function is_elementor_active() {
1576 if ( in_array( 'elementor/elementor.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
1577 return true;
1578 } elseif ( function_exists( 'is_plugin_active' ) ) {
1579 if ( is_plugin_active( 'elementor/elementor.php' ) ) {
1580 return true;
1581 }
1582 }
1583 return false;
1584 }
1585
1586
1587 /**
1588 * Check if funnel step or not
1589 *
1590 * @return bool
1591 * @since 3.1.0
1592 */
1593 public static function maybe_funnel_step( $step_id = null ) {
1594 if ( ! $step_id ) {
1595 $step_id = get_the_ID();
1596 }
1597 $post_type = get_post_type( $step_id );
1598 if ( WPFNL_STEPS_POST_TYPE === $post_type ) {
1599 return true;
1600 }
1601 return false;
1602 }
1603
1604
1605 /**
1606 * Check if saved builder is activated
1607 * or not
1608 *
1609 * @param $builder
1610 *
1611 * @return bool
1612 * @since 1.0.0
1613 */
1614 public static function is_builder_active( $builder ) {
1615 switch ( $builder ) {
1616 case 'elementor':
1617 return self::is_elementor_active();
1618 break;
1619 default:
1620 return false;
1621 break;
1622 }
1623 }
1624
1625
1626 /**
1627 * Check if the global funnel addon is activated or not
1628 *
1629 * @return bool
1630 * @since 2.0.4
1631 */
1632 public static function is_global_funnel_activated() {
1633 return apply_filters( 'wpfunnels/is_global_funnel_activated', false );
1634 }
1635
1636
1637 /**
1638 * Check if the funnel is global funnel
1639 *
1640 * @param $funnel_id
1641 *
1642 * @return bool
1643 */
1644 public static function is_global_funnel( $funnel_id ) {
1645 if ( ! $funnel_id ) {
1646 return false;
1647 }
1648 return apply_filters( 'wpfunnels/is_global_funnel', false, $funnel_id );
1649 }
1650
1651
1652 /**
1653 * Check if pro is activated/deactivated
1654 *
1655 * @return bool
1656 * @since 1.0.0
1657 */
1658 public static function is_wpfnl_pro_activated() {
1659 return apply_filters( 'wpfunnels/is_wpfnl_pro_active', false ) || apply_filters( 'is_wpfnl_pro_active', false );
1660 }
1661
1662
1663 /**
1664 * Check if pro is activated/deactivated
1665 *
1666 * @return bool
1667 * @since 1.0.0
1668 */
1669 public static function is_pro_license_activated() {
1670 return apply_filters( 'wpfunnels/is_pro_license_activated', false );
1671 }
1672
1673
1674 /**
1675 * Count funnels that are NOT store checkout type.
1676 *
1677 * Used to enforce the free-plan 3-funnel limit without counting
1678 * store checkout funnels against that quota.
1679 *
1680 * @param array $statuses Post statuses to include. Defaults to publish + draft.
1681 * @return int
1682 * @since 3.6.0
1683 */
1684 public static function count_non_store_checkout_funnels( $statuses = array( 'publish', 'draft' ) ) {
1685 $args = array(
1686 'post_type' => WPFNL_FUNNELS_POST_TYPE,
1687 'post_status' => $statuses,
1688 'posts_per_page' => -1,
1689 'suppress_filters' => true,
1690 'fields' => 'ids',
1691 'meta_query' => array(
1692 'relation' => 'OR',
1693 array(
1694 'key' => '_wpfnl_funnel_type',
1695 'compare' => 'NOT EXISTS',
1696 ),
1697 array(
1698 'key' => '_wpfnl_funnel_type',
1699 'value' => 'store_checkout',
1700 'compare' => '!=',
1701 ),
1702 ),
1703 );
1704 return count( get_posts( $args ) );
1705 }
1706
1707
1708 /**
1709 * Count store checkout funnels.
1710 *
1711 * Used to enforce the free-plan 3-store-checkout limit.
1712 *
1713 * @param array $statuses Post statuses to include. Defaults to publish + draft.
1714 * @return int
1715 * @since 3.6.0
1716 */
1717 public static function count_store_checkout_funnels( $statuses = array( 'publish', 'draft' ) ) {
1718 $args = array(
1719 'post_type' => WPFNL_FUNNELS_POST_TYPE,
1720 'post_status' => $statuses,
1721 'posts_per_page' => -1,
1722 'suppress_filters' => true,
1723 'fields' => 'ids',
1724 'meta_query' => array(
1725 array(
1726 'key' => '_wpfnl_funnel_type',
1727 'value' => 'store_checkout',
1728 'compare' => '=',
1729 ),
1730 ),
1731 );
1732 return count( get_posts( $args ) );
1733 }
1734
1735 /**
1736 * Check if the module is pro or
1737 * not
1738 *
1739 * @param $module
1740 *
1741 * @return bool
1742 * @since 1.0.0
1743 */
1744 public static function is_pro_module( $module ) {
1745 $pro_modules = apply_filters( 'wpfnl_pro_modules', array() );
1746 return in_array( $module, $pro_modules );
1747 }
1748
1749
1750 /**
1751 * Check if the module is exists or not
1752 *
1753 * @param $module_name
1754 * @param string $type
1755 * @param bool $step
1756 * @param bool $pro
1757 *
1758 * @return bool
1759 * @since 1.0.0
1760 */
1761 public static function is_module_registered( $module_name, $type = 'admin', $step = false, $pro = false ) {
1762 if ( empty( $module_name ) ) {
1763 return false;
1764 }
1765 $class_name = str_replace( '-', ' ', $module_name );
1766 $class_name = str_replace( ' ', '', ucwords( $class_name ) );
1767 if ( $pro ) {
1768 if ( $type === 'steps' ) {
1769 $class_name = 'WPFunnelsPro\\Admin\\Modules\\Steps\\' . $class_name . '\Module';
1770 }
1771 } else {
1772 if ( $type === 'admin' ) {
1773 $class_name = 'WPFunnels\\Admin\\Modules\\' . $class_name . '\Module';
1774 } elseif ( $type === 'steps' ) {
1775 $class_name = 'WPFunnels\\Admin\\Modules\\Steps\\' . $class_name . '\Module';
1776 } else {
1777 $class_name = 'WPFunnels\\Modules\\Frontend\\' . $class_name . '\Module';
1778 }
1779 }
1780 return class_exists( $class_name );
1781 }
1782
1783
1784 /**
1785 * Check manager permissions on REST API.
1786 *
1787 * @param string $object Object.
1788 * @param string $context Request context.
1789 *
1790 * @return bool
1791 * @since 2.6.0
1792 */
1793 public static function wpfnl_rest_check_manager_permissions( $object, $context = 'read' ) {
1794
1795 $objects = array(
1796 'funnels' => 'wpf_manage_funnels',
1797 'settings' => 'wpf_manage_funnels',
1798 'templates' => 'wpf_manage_funnels',
1799 'steps' => 'wpf_manage_funnels',
1800 'products' => 'wpf_manage_funnels',
1801 );
1802 if ( ! isset( $objects[ $object ] ) ) {
1803 return false;
1804 }
1805 return current_user_can( $objects[ $object ] );
1806 }
1807
1808
1809 /**
1810 * Check if the provided plugin ($path) is installed or not
1811 *
1812 * @param $path
1813 *
1814 * @return bool
1815 * @since 2.0.0
1816 */
1817 public static function is_plugin_installed( $path ) {
1818 $plugins = get_plugins();
1819 return isset( $plugins[ $path ] );
1820 }
1821
1822
1823
1824 /**
1825 * Check if the provided plugin ($path) is installed or not
1826 *
1827 * @param $path
1828 *
1829 * @return bool
1830 * @since 2.0.0
1831 */
1832 public static function is_plugin_activated( $path ) {
1833 include_once ABSPATH . 'wp-admin/includes/plugin.php';
1834 if ( is_plugin_active( $path ) ) {
1835 return true;
1836 }
1837 return false;
1838 }
1839
1840
1841
1842 /**
1843 * Check plugin status by path
1844 *
1845 * @param $path
1846 * @param $slug
1847 *
1848 * @return string
1849 *
1850 * @since 2.0.1
1851 */
1852 public static function get_plugin_action( $path, $slug ) {
1853 if ( 'divi-builder' === $slug ) {
1854 $is_divi_theme_active = self::wpfnl_is_theme_active( 'Divi' );
1855 if ( $is_divi_theme_active ) {
1856 return 'nothing';
1857 }
1858 }
1859
1860 if ( 'bricks' === $slug ) {
1861 $maybe_bricks_theme = self::maybe_bricks_theme();
1862 if ( $maybe_bricks_theme ) {
1863 return 'nothing';
1864 } else {
1865 return 'install';
1866 }
1867 }
1868
1869 if ( null === self::$installed_plugins ) {
1870 self::$installed_plugins = get_plugins();
1871 }
1872
1873 if ( ! isset( self::$installed_plugins[ $path ] ) ) {
1874 return 'install';
1875 } elseif ( ! is_plugin_active( $path ) ) {
1876 return 'activate';
1877 } else {
1878 return 'nothing';
1879 }
1880 }
1881
1882 /**
1883 * Check theme is active or not
1884 *
1885 * @param string $theme_name
1886 *
1887 * @return Bool
1888 */
1889 public static function wpfnl_is_theme_active( $theme_name ) {
1890 $theme = wp_get_theme(); // gets the current theme
1891 if ( $theme_name === $theme->name || $theme_name === $theme->parent_theme ) {
1892 return true;
1893 }
1894 return false;
1895 }
1896
1897
1898 /**
1899 * Check plugin is installed or not
1900 *
1901 * @param $plugin_slug
1902 *
1903 * @return Bolean
1904 */
1905 public static function wpfnl_check_is_plugin_installed( $plugin ) {
1906 $installed_plugins = get_plugins();
1907 return array_key_exists( $plugin, $installed_plugins ) || in_array( $plugin, $installed_plugins, true );
1908 }
1909
1910
1911 /**
1912 * Get depenedency plugins status
1913 *
1914 * @return mixed|void
1915 *
1916 * @since 2.0.1
1917 */
1918 public static function get_dependency_plugins_status() {
1919 return apply_filters(
1920 'wpfunnels/dependency_plugin_list',
1921 array(
1922 'elementor' => array(
1923 'name' => 'Elementor',
1924 'plugin_file' => 'elementor/elementor.php',
1925 'slug' => 'elementor',
1926 'action' => self::get_plugin_action( 'elementor/elementor.php', 'elementor' ),
1927 ),
1928 'divi-builder' => array(
1929 'name' => 'Divi',
1930 'plugin_file' => 'divi-builder/divi-builder.php',
1931 'slug' => 'divi-builder',
1932 'action' => self::get_plugin_action( 'divi-builder/divi-builder.php', 'divi-builder' ),
1933 ),
1934 'oxygen' => array(
1935 'name' => 'Oxygen',
1936 'plugin_file' => 'oxygen/functions.php',
1937 'slug' => 'oxygen',
1938 'action' => self::get_plugin_action( 'oxygen/functions.php', 'oxygen' ),
1939 ),
1940 'bricks' => array(
1941 'name' => 'Bricks',
1942 'plugin_file' => 'bricks',
1943 'slug' => 'bricks',
1944 'action' => self::get_plugin_action( 'bricks', 'bricks' ),
1945 ),
1946 )
1947 );
1948 }
1949
1950
1951 /**
1952 * Is there any missing plugin for wpfunnels
1953 *
1954 * @return string
1955 *
1956 * @since 2.0.1
1957 */
1958 public static function is_any_plugin_missing() {
1959 if ( null === self::$installed_plugins ) {
1960 self::$installed_plugins = get_plugins();
1961 }
1962 $builder = self::get_builder_type();
1963 $dependency_plugins = self::get_dependency_plugins_status();
1964 $is_missing = 'no';
1965
1966 if ( isset( $dependency_plugins[ $builder ] ) ) {
1967 $plugin_data = $dependency_plugins[ $builder ];
1968 if ( 'activate' === $plugin_data['action'] || 'install' === $plugin_data['action'] ) {
1969 $is_missing = 'yes';
1970 }
1971 }
1972
1973 /**
1974 * For support extra theme with divi
1975 */
1976 $theme = wp_get_theme();
1977
1978 if ( 'divi-builder' === $builder && ( 'Extra' === $theme->name || 'Extra' === $theme->parent_theme ) ) {
1979 $is_missing = 'no';
1980 }
1981
1982 return $is_missing;
1983 }
1984
1985
1986 /**
1987 * Recursively traverses a multidimensional array in search of a specific value and returns the
1988 * array containing the value, or an
1989 * null on failure.
1990 *
1991 * @param $search_value
1992 * @param $array
1993 *
1994 * @return array
1995 * @since 2.0.0
1996 */
1997 public static function recursive_multidimensional_ob_array_search_by_value( $search_value, $array, $keys = array() ) {
1998 if ( is_array( $array ) && count( $array ) > 0 ) {
1999 foreach ( $array as $key => $value ) {
2000 $temp_keys = $keys;
2001
2002 // Adding current key to search path
2003 array_push( $temp_keys, $key );
2004
2005 // Check if this value is an array
2006 // with atleast one element
2007 if ( is_array( $value ) && count( $value ) > 0 ) {
2008 $widget_type = isset( $value['widgetType'] ) ? $value['widgetType'] : false;
2009 if ( $widget_type ) {
2010 if ( $widget_type === $search_value ) {
2011 $value['path'] = $temp_keys;
2012 return $value;
2013 } else {
2014 $res_path = self::recursive_multidimensional_ob_array_search_by_value(
2015 $search_value,
2016 $value['elements'],
2017 $temp_keys
2018 );
2019 }
2020 if ( $res_path != null ) {
2021 return $res_path;
2022 }
2023 } else {
2024 $res_path = self::recursive_multidimensional_ob_array_search_by_value(
2025 $search_value,
2026 $value['elements'],
2027 $temp_keys
2028 );
2029 }
2030 if ( $res_path != null ) {
2031 return $res_path;
2032 }
2033 }
2034 }
2035 }
2036
2037 return null;
2038 }
2039
2040
2041 /**
2042 * Check if checkout ajax or not
2043 *
2044 * @return bool
2045 */
2046 public static function is_checkout_ajax() {
2047 if ( wp_doing_ajax() || isset( $_GET['wc-ajax'] ) ) {
2048 if ( isset( $_GET['wc-ajax'] ) && //phpcs:ignore
2049 isset( $_POST['_wcf_checkout_id'] ) //phpcs:ignore
2050 ) {
2051 return true;
2052 }
2053 }
2054
2055 return false;
2056 }
2057
2058
2059 /**
2060 * Calculate discount price
2061 *
2062 * @param $discount_type
2063 * @param $discount_value
2064 * @param $product_price
2065 *
2066 * @deprecated deprecated since 2.7.6
2067 *
2068 * @return string
2069 */
2070 public static function calculate_discount_price( $discount_type, $discount_value, $product_price ) {
2071
2072 $custom_price = $product_price;
2073 if ( ! empty( $discount_type ) ) {
2074 if ( 'discount-percentage' === $discount_type ) {
2075 if ( $discount_value > 0 && $discount_value <= 100 ) {
2076 $custom_price = $product_price - ( ( $product_price * $discount_value ) / 100 );
2077 $custom_price = number_format( (float) $custom_price, 2, '.', '' );
2078 }
2079 } elseif ( 'discount-price' === $discount_type ) {
2080 if ( $discount_value > 0 ) {
2081 $custom_price = $product_price - $discount_value;
2082 }
2083 }
2084 }
2085 return $custom_price;
2086 }
2087
2088
2089 /**
2090 * Calculate discount price
2091 *
2092 * @param $discount_type
2093 * @param $discount_value
2094 * @param $product_price
2095 *
2096 * @return string
2097 */
2098 public static function calculate_discount_amount( $discount_type, $discount_value, $product_price ) {
2099
2100 if ( $discount_type !== 'original' && ! empty( $discount_type ) ) {
2101 $discount = '';
2102 if ( 'discount-percentage' === $discount_type ) {
2103 if ( $discount_value > 0 && $discount_value <= 100 ) {
2104 $discount = ( ( $product_price * $discount_value ) / 100 );
2105 }
2106 } elseif ( 'discount-price' === $discount_type ) {
2107 if ( $discount_value > 0 ) {
2108 $discount = $discount_value;
2109
2110 }
2111 }
2112 return number_format( $discount, 2 );
2113 }
2114
2115 return false;
2116 }
2117
2118
2119 /**
2120 * Get attributes for wpfunnels body wrapper
2121 *
2122 * @param string $template
2123 *
2124 * @return string
2125 */
2126 public static function get_template_container_atts( $template = '' ) {
2127 $attributes = apply_filters( 'wpfunnels/page_container_atts', array() );
2128 $atts_string = '';
2129 foreach ( $attributes as $key => $value ) {
2130 if ( ! $value ) {
2131 continue;
2132 }
2133 if ( true === $value ) {
2134 $atts_string .= esc_html( $key ) . ' ';
2135 } else {
2136 $atts_string .= sprintf( '%s="%s" ', esc_html( $key ), esc_attr( $value ) );
2137 }
2138 }
2139 return $atts_string;
2140 }
2141
2142
2143 /**
2144 * Get funnel link
2145 *
2146 * @param $funnel_id
2147 *
2148 * @return Mix
2149 */
2150 public static function get_funnel_link( $funnel_id ) {
2151 if ( ! $funnel_id ) {
2152 return;
2153 }
2154 $steps = self::get_steps( $funnel_id );
2155 if ( $steps && is_array( $steps ) ) {
2156 $first_step = reset( $steps );
2157 $first_step_id = $first_step['id'];
2158 return get_the_permalink( $first_step_id );
2159 }
2160 return home_url();
2161 }
2162
2163
2164 /**
2165 * Get wc fragment
2166 *
2167 * @param array $data
2168 *
2169 * @return array
2170 */
2171 public static function get_wc_fragments( $data = array() ) {
2172 ob_start();
2173 woocommerce_order_review();
2174 $woocommerce_order_review = ob_get_clean();
2175
2176 ob_start();
2177 woocommerce_checkout_payment();
2178 $woocommerce_checkout_payment = ob_get_clean();
2179
2180 $response = array(
2181 'cart_total' => WC()->cart->total,
2182 'cart_total_currency' => WC()->cart->get_cart_total(),
2183 'wc_custom_fragments' => 'yes',
2184 'fragments' => apply_filters(
2185 'woocommerce_update_order_review_fragments',
2186 array(
2187 '.woocommerce-checkout-review-order-table' => $woocommerce_order_review,
2188 /*'.woocommerce-checkout-payment' => $woocommerce_checkout_payment,*/
2189 )
2190 ),
2191 );
2192
2193 if ( ! empty( $data ) ) {
2194 $response['wpfunnels_data'] = $data;
2195 }
2196
2197 return $response;
2198 }
2199
2200
2201 /**
2202 * Get supported builders
2203 *
2204 * @return array
2205 */
2206 public static function get_supported_builders() {
2207 $builders = array(
2208 'gutenberg' => 'Gutenberg',
2209 'elementor' => 'Elementor',
2210 'divi-builder' => 'Divi builder',
2211 'oxygen' => 'Oxygen',
2212 'bricks' => 'Bricks',
2213 'other' => 'Other',
2214 );
2215 return apply_filters( 'wpfunnels/supported_builders', $builders );
2216 }
2217
2218 /**
2219 * Get custom url instead of deafult tahnkyou page
2220 *
2221 * @param mixed $step_id
2222 *
2223 * @return [type]
2224 */
2225 public static function custom_url_for_thankyou_page( $step_id ) {
2226
2227 $isThankyou = self::check_if_this_is_step_type_by_id( $step_id, 'thankyou' );
2228 $isCustomUrl = get_post_meta( $step_id, '_wpfnl_thankyou_is_custom_redirect', true );
2229 $isDirect = get_post_meta( $step_id, '_wpfnl_thankyou_is_direct_redirect', true );
2230
2231 if ( $isThankyou && $isCustomUrl === 'on' ) {
2232 $url = get_post_meta( $step_id, '_wpfnl_thankyou_custom_redirect_url', true );
2233 if ( $url ) {
2234
2235 if ( $isDirect === 'off' ) {
2236 $redirectAfterSec = get_post_meta( $step_id, '_wpfnl_thankyou_set_time', true ) ? get_post_meta( $step_id, '_wpfnl_thankyou_set_time', true ) : 5;
2237 header( 'refresh:' . $redirectAfterSec . ';url=' . $url );
2238 } else {
2239 // unsell 'wpfunnels_automation_data' cookie and trigger 'wpfunnels/trigger_automation' hook
2240 self::unset_site_cookie( $step_id, 'wpfunnels_automation_data', 'wpfunnels/trigger_automation' );
2241 return $url;
2242 }
2243 }
2244 return false;
2245 }
2246 return false;
2247 }
2248
2249 /**
2250 * Check product has perfect variation or not
2251 *
2252 * @param $variation_id
2253 *
2254 * @return Boolean
2255 */
2256 public static function is_perfect_variations( $variation_id ) {
2257
2258 $blank_attr = array();
2259 $response = array(
2260 'status' => true,
2261 'data' => array(),
2262 );
2263 $product = wc_get_product( $variation_id );
2264 if ( $product ) {
2265 $parent_id = $product->get_parent_id();
2266 $_product = wc_get_product( $parent_id );
2267 if ( $_product ) {
2268 $attrs = self::get_product_attr( $_product );
2269 $attributes = $product->get_attributes();
2270 if ( ! empty( $attributes ) ) {
2271 foreach ( $attributes as $attribute_key => $attribute_value ) {
2272
2273 if ( ! $attribute_value ) {
2274 $blank_attr[ $attribute_key ] = $attrs[ $attribute_key ];
2275 $response['status'] = false;
2276 }
2277 }
2278 }
2279 }
2280 }
2281 $response['data'] = $blank_attr;
2282 return $response;
2283 }
2284
2285
2286 /**
2287 * Get attributes of product
2288 *
2289 * @param Object $produt
2290 */
2291 public static function get_product_attr( $product ) {
2292 $attributes = $product->get_attributes();
2293 $attr_array = array();
2294 foreach ( $attributes as $attribute_key => $attribute_value ) {
2295
2296 $attribute_name = str_replace( 'attribute_', '', $attribute_key );
2297 $attr_value = $product->get_attribute( $attribute_name );
2298 $attr_value = strtolower( $attr_value );
2299
2300 if ( strpos( $attr_value, '|' ) ) {
2301 $attr_array[ $attribute_key ] = explode( '|', $attr_value );
2302 } else {
2303 $attr_array[ $attribute_key ] = explode( ',', $attr_value );
2304 }
2305 }
2306 return $attr_array;
2307
2308 }
2309
2310
2311
2312 /**
2313 * Remove site cookie
2314 *
2315 * @param $step_id, $cookie_name, $trigger_hook, $funnel_id
2316 */
2317 public static function unset_site_cookie( $step_id, $cookie_name, $trigger_hook = '', $funnel_id = '' ) {
2318
2319 if ( ! $funnel_id ) {
2320 $funnel_id = self::get_funnel_id_from_step( $step_id );
2321 }
2322
2323 if ( ! $funnel_id ) {
2324 return false;
2325 }
2326
2327 $cookie = isset( $_COOKIE[ $cookie_name ] ) ? json_decode( wp_unslash( $_COOKIE[ $cookie_name ] ), true ) : array();
2328 if ( ! isset( $cookie['funnel_id'] ) ) {
2329 $cookie['funnel_id'] = $funnel_id;
2330 }
2331 $cookie['funnel_status'] = 'successful';
2332
2333 if ( isset( $_COOKIE[ $cookie_name ] ) ) {
2334 if ( $trigger_hook ) {
2335 do_action( $trigger_hook, $cookie );
2336 }
2337 }
2338 // unset cookie
2339 ob_start();
2340 if ( isset( $_COOKIE[ $cookie_name ] ) ) {
2341 setcookie( $cookie_name, null, strtotime( '-1 days' ), '/', COOKIE_DOMAIN );
2342 }
2343 ob_end_flush();
2344 }
2345
2346
2347 /**
2348 * Get formated product name
2349 *
2350 * @param Object $product
2351 *
2352 * @return String
2353 */
2354 public static function get_formated_product_name( $product, $formatted_attr = array() ) {
2355 $_product = wc_get_product( $product );
2356 $each_child_attr = array();
2357 $_title = '';
2358 if ( $_product ) {
2359 if ( ! $formatted_attr ) {
2360 // get_attribute_summary() only exists on variation products, not variable products
2361 if ( 'variation' === $_product->get_type() || 'subscription_variation' === $_product->get_type() ) {
2362 $attr_summary = $_product->get_attribute_summary();
2363 $attr_array = explode( ',', $attr_summary );
2364
2365 foreach ( $attr_array as $ata ) {
2366 $attr = strpbrk( $ata, ':' );
2367 $each_child_attr[] = $attr;
2368 }
2369 }
2370 } else {
2371 foreach ( $formatted_attr as $attr ) {
2372 $each_child_attr[] = ucfirst( $attr );
2373 }
2374 }
2375 if ( $each_child_attr ) {
2376 $each_child_attr_two = array();
2377 foreach ( $each_child_attr as $eca ) {
2378 $each_child_attr_two[] = str_replace( ': ', ' ', $eca );
2379 }
2380 $_title = $_product->get_title() . ' - ';
2381 $_title = $_title . implode( ', ', $each_child_attr_two );
2382 } else {
2383 $_title = $_product->get_title();
2384 }
2385 }
2386
2387 return $_title;
2388 }
2389
2390
2391 /**
2392 * Get page builder of a specific funnel by step Id from postmeta
2393 *
2394 * @param $funnel_id
2395 *
2396 * @return String $builder_name
2397 *
2398 * @since 2.0.5
2399 */
2400 public static function get_page_builder_by_step_id( $funnel_id ) {
2401 $steps = self::get_steps( $funnel_id );
2402 $builder_name = '';
2403 if ( isset( $steps[0] ) ) {
2404 $first_step_id = $steps[0]['id'];
2405 // check builder is elementor or not
2406 $elementor_page = get_post_meta( $first_step_id, '_elementor_edit_mode', true );
2407
2408 // check builder is divi or not
2409 $divi_page = get_post_meta( $first_step_id, '_et_pb_use_builder', true );
2410
2411 // check Oxygen builder is not
2412 $oxygen_page = get_post_meta( $first_step_id, 'ct_builder_shortcodes', true );
2413
2414 // check builder is bricks or not
2415 $bricks_page = get_post_meta( $first_step_id, '_bricks_editor_mode', true );
2416
2417 if ( $elementor_page ) {
2418 $builder_name = 'elementor';
2419 } elseif ( 'on' === $divi_page ) {
2420 $builder_name = 'divi-builder';
2421 } elseif ( 'bricks' === $bricks_page ) {
2422 $builder_name = 'bricks';
2423 } elseif ( ! empty( $oxygen_page ) ) {
2424 $builder_name = 'oxygen';
2425 } else {
2426 $builder_name = 'gutenberg';
2427 }
2428
2429 if ( $builder_name ) {
2430 return $builder_name;
2431 }
2432 }
2433 return $builder_name;
2434 }
2435
2436
2437 /**
2438 * Get checkout section heading settings
2439 */
2440 public static function get_checkout_section_heading_settings( $type = '', $step_id = '' ) {
2441
2442 if ( self::is_pro_license_activated() ) {
2443 if ( $step_id ) {
2444 $get_settings = get_post_meta( $step_id, '_wpfunnels_edit_field_additional_settings', true );
2445 if ( ! empty( $get_settings ) ) {
2446 if ( $type === 'billing' ) {
2447
2448 $settings = array(
2449 'custom_heading' => $get_settings['custom_billing_heading'],
2450 );
2451 return $settings;
2452 }
2453 if ( $type === 'shipping' ) {
2454 $settings = array(
2455 'custom_heading' => $get_settings['custom_shipping_heading'],
2456 );
2457 return $settings;
2458 }
2459
2460 if ( $type === 'order' ) {
2461 $settings = array(
2462 'custom_heading' => $get_settings['custom_order_detail_heading'],
2463 );
2464 return $settings;
2465 }
2466 }
2467 }
2468 }
2469 return false;
2470 }
2471
2472 /**
2473 * Check webhook addon activated or not
2474 *
2475 * @return Boolean
2476 */
2477 public static function is_webhook_activated() {
2478 if ( is_plugin_active( 'wpfunnels-pro-webhook/wpfunnels-pro-webhook.php' ) ) {
2479 return true;
2480 }
2481 return false;
2482 }
2483
2484
2485 /**
2486 * Check webhook addon license activated or not
2487 *
2488 * @return Boolean
2489 */
2490 public static function is_webhook_license_activated() {
2491
2492 if ( is_plugin_active( 'wpfunnels-pro/wpfnl-pro.php' ) ) {
2493 return true;
2494 }
2495 return false;
2496 }
2497
2498
2499 /**
2500 * Get gbf supported addons
2501 */
2502 public static function get_supported_addons() {
2503
2504 $addons = array(
2505 'global_funnel' => array(
2506 'features' => array(
2507 'trigger_options' => array(
2508 '' => __( 'Please select type..', 'wpfnl' ),
2509 'category' => __( 'Product category is ..', 'wpfnl' ),
2510 'product' => __( 'Product is ..', 'wpfnl' ),
2511 ),
2512 ),
2513 ),
2514 );
2515
2516 // 'all_product' trigger is available when GBF is active (built into Pro) or via legacy addon >= 1.0.7.
2517 if ( self::is_global_funnel_activated() || ( defined( 'WPFNL_PRO_GB_VERSION' ) && version_compare( WPFNL_PRO_GB_VERSION, '1.0.7', '>=' ) ) ) {
2518 $addons['global_funnel']['features']['trigger_options']['all_product'] = __( 'Any product is selected', 'wpfnl' );
2519 }
2520 return apply_filters( 'wpfunnels/supported-addons', $addons );
2521 }
2522
2523 /**
2524 * Get supported GBF offer condition
2525 */
2526 public static function get_supported_gbf_offer_condition() {
2527 $conditions = array(
2528 'specificProduct' => 'Specific Product',
2529 );
2530 return apply_filters( 'wpfunnels/supported-gbf-offer-condition', $conditions );
2531 }
2532
2533
2534 /**
2535 * Get product categories for GBF offer condition
2536 */
2537 public static function get_categories_gbf_offer_condition() {
2538 $categories = array();
2539 if ( self::is_wc_active() ) {
2540 $orderby = 'name';
2541 $order = 'asc';
2542 $hide_empty = false;
2543 $cat_args = array(
2544 'orderby' => $orderby,
2545 'order' => $order,
2546 'hide_empty' => $hide_empty,
2547 );
2548 $product_categories = get_terms( 'product_cat', $cat_args );
2549 if ( ! empty( $product_categories ) ) {
2550 foreach ( $product_categories as $category ) {
2551
2552 $categories[ $category->slug ] = $category->name;
2553 }
2554 }
2555 }
2556
2557 return $categories;
2558 }
2559
2560
2561 public static function oxygen_builder_version_capability() {
2562 if ( defined( 'CT_VERSION' ) && version_compare( CT_VERSION, '3.2', '>=' ) ) {
2563 return true;
2564 }
2565 return false;
2566 }
2567
2568 public static function get_funnel_utm_settings( $funnel_id = null ) {
2569 if ( $funnel_id ) {
2570 $default_enable_settings = array(
2571 'utm_enable' => 'off',
2572 'utm_source' => '',
2573 'utm_medium' => '',
2574 'utm_campaign' => '',
2575 'utm_content' => '',
2576 );
2577
2578 $utm_settings = get_post_meta( $funnel_id, '_wpfunnels_utm_params', true );
2579 return wp_parse_args( $utm_settings, $default_enable_settings );
2580 }
2581 return false;
2582 }
2583
2584 public static function get_funnel_settings( $funnel_id = null ) {
2585
2586 if ( $funnel_id ) {
2587
2588 $utm_settings = self::get_funnel_utm_settings( $funnel_id );
2589 $is_fb_pixel = get_post_meta( $funnel_id, '_wpfunnels_disabled_fb_pixel', true ) ? get_post_meta( $funnel_id, '_wpfunnels_disabled_fb_pixel', true ) : 'no';
2590 $is_gtm = get_post_meta( $funnel_id, '_wpfunnels_disabled_gtm', true ) ? get_post_meta( $funnel_id, '_wpfunnels_disabled_gtm', true ) : 'no';
2591
2592 return array(
2593 'utm_settings' => $utm_settings,
2594 'is_fb_pixel' => $is_fb_pixel,
2595 'is_gtm' => $is_gtm,
2596 );
2597 }
2598 return false;
2599
2600 }
2601
2602
2603 /**
2604 * Check discount is applicable or not in checkout page
2605 */
2606 public static function discount_on_checkout( $step_id = null ) {
2607 if ( $step_id ) {
2608 $discount = get_post_meta( $step_id, '_wpfnl_checkout_discount_main_product', true );
2609 if ( $discount ) {
2610 return $discount;
2611 }
2612 }
2613 return false;
2614 }
2615
2616
2617 /**
2618 * Calculate main product total amount in checkout page
2619 *
2620 * @param Array $checkout_product
2621 * @param Object $cart_content
2622 * @param String $step_id
2623 *
2624 * @return Mix
2625 */
2626 public static function calculate_main_product_total( $checkout_product = null, $cart_content = null, $step_id = '' ) {
2627
2628 if ( $checkout_product && $cart_content ) {
2629 $total = 0;
2630
2631 foreach ( $cart_content as $key => $content ) {
2632 if ( isset( $content['wpfnl_order_bump'] ) && $content['wpfnl_order_bump'] ) {
2633 continue;
2634 }
2635 $product_id = '';
2636 if ( ! empty( $content['variation_id'] ) ) {
2637 $product_id = $content['variation_id'];
2638 }
2639
2640 if ( ! $product_id ) {
2641 $product_id = isset( $content['product_id'] ) ? $content['product_id'] : '';
2642 }
2643
2644 $checkout_product = maybe_unserialize( $checkout_product );
2645 $key = array_search( $product_id, array_column( $checkout_product, 'id' ) );
2646 if ( $key !== false ) {
2647 if ( wc_tax_enabled() ) {
2648 if ( ! wc_prices_include_tax() ) {
2649 $content['line_total'] = number_format( $content['line_total'], 2 );
2650 $content['line_total'] = filter_var( $content['line_total'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION );
2651 $total = $total + $content['line_total'];
2652 } else {
2653
2654 $content['line_total'] = number_format( $content['line_total'], 2 );
2655 $content['line_total'] = filter_var( $content['line_total'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION );
2656 $total = $total + $content['line_total'] + $content['line_tax'];
2657
2658 }
2659 } else {
2660 $content['line_total'] = number_format( $content['line_total'], 2 );
2661 $content['line_total'] = filter_var( $content['line_total'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION );
2662 $total = $total + $content['line_total'] + $content['line_tax'];
2663 }
2664 }
2665 }
2666
2667 $total = number_format( $total, 2 );
2668 $total = filter_var( $total, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION );
2669 return $total;
2670 }
2671 return false;
2672 }
2673
2674
2675
2676 /**
2677 * Calculate cart total amount in checkout page
2678 *
2679 * @param Array $checkout_product
2680 * @param Object $cart_content
2681 * @param String $step_id
2682 *
2683 * @return bool|int|float
2684 */
2685 public static function calculate_cart_total( $checkout_product = null, $cart_content = null, $step_id = '' ) {
2686
2687 if ( $checkout_product && $cart_content ) {
2688 $total = 0;
2689
2690 foreach ( $cart_content as $key => $content ) {
2691 $product_id = $content['variation_id'] ? $content['variation_id'] : $content['product_id'];
2692
2693 if ( wc_tax_enabled() ) {
2694 if ( ! wc_prices_include_tax() ) {
2695 $content['line_total'] = number_format( $content['line_total'], 2 );
2696 $content['line_total'] = filter_var( $content['line_total'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION );
2697 $total = $total + $content['line_total'];
2698 } else {
2699 $content['line_total'] = number_format( $content['line_total'], 2 );
2700 $content['line_total'] = filter_var( $content['line_total'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION );
2701 $total = $total + $content['line_total'] + $content['line_tax'];
2702
2703 }
2704 } else {
2705 $content['line_total'] = number_format( $content['line_total'], 2 );
2706 $content['line_total'] = filter_var( $content['line_total'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION );
2707 $total = $total + $content['line_total'] + $content['line_tax'];
2708
2709 }
2710 }
2711 $total = number_format( $total, 2 );
2712 $total = filter_var( $total, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION );
2713 return $total;
2714 }
2715 return false;
2716 }
2717
2718
2719
2720 /**
2721 * Check array type ( multi-dimentional or one dimentional )
2722 *
2723 * @param Array
2724 *
2725 * @return Bool
2726 */
2727 public static function check_array_is_multidimentional( $multi_array = null ) {
2728
2729 if ( $multi_array ) {
2730 foreach ( $multi_array as $array ) {
2731 if ( is_array( $array ) ) {
2732 return true;
2733 } else {
2734 return false;
2735 }
2736 }
2737 return true;
2738 }
2739 return false;
2740 }
2741
2742
2743 /**
2744 * Migrate old Order bump settings with multiple order bump
2745 */
2746 public static function migrate_order_bump( $prev_settings = null, $step_id = null ) {
2747 if ( $prev_settings && $step_id ) {
2748 $multi_settings = array();
2749 if ( ! self::check_array_is_multidimentional( $prev_settings ) ) {
2750 $multi_settings = array(
2751 $prev_settings,
2752 );
2753 update_post_meta( $step_id, 'order-bump-settings', $multi_settings );
2754 return $multi_settings;
2755 }
2756 }
2757 return false;
2758 }
2759
2760
2761 /**
2762 * N:B test case should be implemented
2763 * Get order bump settings by step id
2764 */
2765 public static function get_ob_settings( $step_id ) {
2766
2767 $all_settings = get_post_meta( $step_id, 'order-bump-settings', true ) ? get_post_meta( $step_id, 'order-bump-settings', true ) : array();
2768 $is_multiple = self::check_array_is_multidimentional( $all_settings );
2769
2770 if ( ! $is_multiple && $all_settings ) {
2771 $all_settings['name'] = 'Order bump';
2772 $all_settings = self::migrate_order_bump( $all_settings, $step_id );
2773 }
2774
2775 if ( is_array( $all_settings ) && count( $all_settings ) > 0 ) {
2776 foreach ( $all_settings as $key => $settings ) {
2777 if ( ! isset( $all_settings[ $key ]['discountOption'] ) && 'original' !== $all_settings[ $key ]['discountOption'] ) {
2778 $product = wc_get_product( $all_settings[ $key ]['product'] );
2779 if ( $product ) {
2780 if ( $product->is_on_sale() ) {
2781 $price = wc_format_sale_price( $product->get_regular_price() * $all_settings[ $key ]['quantity'], $product->get_sale_price() ? $product->get_sale_price() * $all_settings[ $key ]['quantity'] : $product->get_regular_price() * $all_settings[ $key ]['quantity'] );
2782 } else {
2783 $price = $product->get_regular_price();
2784 if ( is_plugin_active( 'woocommerce-subscriptions/woocommerce-subscriptions.php' ) ) {
2785 $signUpFee = \WC_Subscriptions_Product::get_sign_up_fee( $product );
2786 $price = $price + $signUpFee;
2787 }
2788 $price = wc_price( $price * $all_settings[ $key ]['quantity'] );
2789 }
2790 $all_settings[ $key ]['htmlPrice'] = $price ? $price : $all_settings[ $key ]['htmlPrice'];
2791 }
2792 }
2793 }
2794 return $all_settings;
2795 }
2796
2797 return array();
2798 }
2799
2800
2801 /**
2802 * Check if funnel canvas or not
2803 *
2804 * @return bool
2805 * @since 2.3.8
2806 */
2807 public static function is_funnel_canvas_window() {
2808 if ( is_admin() && isset( $_GET['page'] ) && 'edit_funnel' === $_GET['page'] ) {
2809 return true;
2810 }
2811 return false;
2812 }
2813
2814
2815 /**
2816 * Get all funnel from post
2817 *
2818 * @return $funnels
2819 * @since 2.4.4
2820 */
2821 public static function get_all_funnels( $status = 'publish' ) {
2822
2823 if ( 'all' == $status ) {
2824 $arg = array(
2825 'post_type' => WPFNL_FUNNELS_POST_TYPE,
2826 'fields' => 'ID',
2827 'orderby' => 'date',
2828 'order' => 'ASC',
2829 'numberposts' => -1,
2830 );
2831 } else {
2832 $arg = array(
2833 'post_type' => WPFNL_FUNNELS_POST_TYPE,
2834 'post_status' => $status,
2835 'fields' => 'ID',
2836 'orderby' => 'date',
2837 'order' => 'ASC',
2838 'numberposts' => -1,
2839 );
2840 }
2841
2842 $funnels = get_posts( $arg );
2843 return $funnels;
2844 }
2845
2846
2847 /**
2848 * Get all funnel from post
2849 *
2850 * @return $funnels
2851 * @since 2.4.4
2852 */
2853 public static function get_all_steps() {
2854
2855 $steps = get_posts(
2856 array(
2857 'post_type' => 'wpfunnel_steps',
2858 'post_status' => 'publish',
2859 'fields' => 'ID',
2860 'orderby' => 'date',
2861 'order' => 'ASC',
2862 )
2863 );
2864 return $steps;
2865 }
2866
2867
2868 /**
2869 * Add type meta for each funnel
2870 *
2871 * @since 2.4.4
2872 */
2873 public static function add_type_meta() {
2874
2875 $is_added = get_option( '_wpfnl_added_type_meta' );
2876 if ( ! $is_added ) {
2877 update_option( '_wpfnl_added_type_meta', 'yes' );
2878 $funnels = self::get_all_funnels();
2879 foreach ( $funnels as $funnel ) {
2880 $type = get_post_meta( $funnel->ID, '_wpfnl_funnel_type', true );
2881 if ( ! $type ) {
2882 update_post_meta( $funnel->ID, '_wpfnl_funnel_type', 'wc' );
2883 }
2884 }
2885 }
2886
2887 }
2888
2889
2890 /**
2891 * Enable lms settings
2892 *
2893 * @return Bool
2894 * @since 2.4.5
2895 */
2896 public static function is_enable_lms_settings() {
2897 $status = get_option( 'wpfunnels_pro_lms_license_status' );
2898 if ( $status === 'active' ) {
2899 return apply_filters( 'wpfunnels/is_enable_lms_settings', false );
2900 }
2901 return false;
2902 }
2903
2904 /**
2905 * Check if lms addon activated or not
2906 *
2907 * @return Bool
2908 * @since 2.4.5
2909 */
2910 public static function is_lms_addon_active() {
2911
2912 if ( in_array( 'wpfunnels-pro-lms/wpfunnels-pro-lms.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
2913 return true;
2914 } elseif ( function_exists( 'is_plugin_active' ) ) {
2915 if ( is_plugin_active( 'wpfunnels-pro-lms/wpfunnels-pro-lms.php' ) ) {
2916 return true;
2917 }
2918 }
2919 return false;
2920 }
2921
2922 /**
2923 * Check if any LMS plugin is active (LearnDash or CreatorLMS)
2924 *
2925 * @return Bool
2926 * @since 2.0.0
2927 */
2928 public static function is_any_lms_plugin_active() {
2929 // Check LearnDash
2930 $is_learndash = in_array( 'sfwd-lms/sfwd_lms.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) );
2931
2932 // Check CreatorLMS
2933 $is_creatorlms = in_array( 'creatorlms/creatorlms.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) );
2934
2935 // For multisite
2936 if ( function_exists( 'is_plugin_active' ) && ! $is_learndash && ! $is_creatorlms ) {
2937 $is_learndash = is_plugin_active( 'sfwd-lms/sfwd_lms.php' );
2938 $is_creatorlms = is_plugin_active( 'creatorlms/creatorlms.php' );
2939 }
2940
2941 return $is_learndash || $is_creatorlms;
2942 }
2943
2944
2945 /**
2946 * Get checkout tabs column name
2947 *
2948 * @return Array
2949 * @since 2.4.5
2950 */
2951 public static function get_checkout_columns( $step_id ) {
2952
2953 $funnel_id = get_post_meta( $step_id, '_funnel_id', true );
2954 $columns = array(
2955 'product-name' => 'Product',
2956 'product-price' => 'Price',
2957 'product-quantity' => 'Quantity',
2958 'total-price' => 'Total Price',
2959 'product-action' => 'Actions',
2960 );
2961
2962 return apply_filters( 'wpfunnels/checkout_columns', $columns, $funnel_id );
2963 }
2964
2965
2966 /**
2967 * Supported order bump position
2968 *
2969 * @return Array
2970 * @since 2.4.5
2971 */
2972 public static function supported_orderbump_position( $step_id ) {
2973 $funnel_id = get_post_meta( $step_id, '_funnel_id', true );
2974
2975 $positions = array(
2976 array(
2977 'name' => 'Before Order Details',
2978 'value' => 'before-order',
2979 ),
2980 array(
2981 'name' => 'After Order Details',
2982 'value' => 'after-order',
2983 ),
2984 array(
2985 'name' => 'Before Checkout Details',
2986 'value' => 'before-checkout',
2987 ),
2988 array(
2989 'name' => 'After Customer Details',
2990 'value' => 'after-customer-details',
2991 ),
2992 array(
2993 'name' => 'Before Payment Options',
2994 'value' => 'before-payment',
2995 ),
2996 array(
2997 'name' => 'After Payment Options',
2998 'value' => 'after-payment',
2999 ),
3000 array(
3001 'name' => 'Pop-up offer',
3002 'value' => 'popup',
3003 ),
3004 );
3005 if ( $funnel_id ) {
3006 return apply_filters( 'wpfunnels/ob_positions', $positions, $funnel_id );
3007 }
3008
3009 return $positions;
3010
3011 }
3012
3013 /**
3014 * Get time zone in string
3015 *
3016 * @return String
3017 * @since 2.4.6
3018 */
3019 public static function wpfnl_timezone_string() {
3020
3021 // If site timezone string exists, return it.
3022 $timezone = get_option( 'timezone_string' );
3023 if ( $timezone ) {
3024 return $timezone;
3025 }
3026
3027 // Get UTC offset, if it isn't set then return UTC.
3028 $utc_offset = floatval( get_option( 'gmt_offset', 0 ) );
3029 if ( ! is_numeric( $utc_offset ) || 0.0 === $utc_offset ) {
3030 return 'UTC';
3031 }
3032
3033 // Adjust UTC offset from hours to seconds.
3034 $utc_offset = (int) ( $utc_offset * 3600 );
3035
3036 // Attempt to guess the timezone string from the UTC offset.
3037 $timezone = timezone_name_from_abbr( '', $utc_offset );
3038 if ( $timezone ) {
3039 return $timezone;
3040 }
3041
3042 // Last try, guess timezone string manually.
3043 foreach ( timezone_abbreviations_list() as $abbr ) {
3044 foreach ( $abbr as $city ) {
3045 // WordPress restrict the use of date(), since it's affected by timezone settings, but in this case is just what we need to guess the correct timezone.
3046 if ( (bool) date( 'I' ) === (bool) $city['dst'] && $city['timezone_id'] && intval( $city['offset'] ) === $utc_offset ) { // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
3047 return $city['timezone_id'];
3048 }
3049 }
3050 }
3051
3052 // Fallback to UTC.
3053 return 'UTC';
3054 }
3055
3056
3057
3058 /**
3059 * Get timezone offset in seconds.
3060 *
3061 * @since 2.4.6
3062 * @return float
3063 */
3064 public static function wpfnl_timezone_offset() {
3065 $timezone = get_option( 'timezone_string' );
3066 if ( $timezone ) {
3067 $timezone_object = new DateTimeZone( $timezone );
3068 return $timezone_object->getOffset( new DateTime( 'now' ) );
3069 } else {
3070 return floatval( get_option( 'gmt_offset', 0 ) ) * HOUR_IN_SECONDS;
3071 }
3072 }
3073
3074
3075 /**
3076 * Check if integrations addon activated or not
3077 *
3078 * @return Bool
3079 * @since 2.4.7
3080 */
3081 public static function is_integrations_addon_active() {
3082 if ( in_array( 'wpfunnels-pro-integrations/wpfunnels-pro-integrations.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
3083 return true;
3084 } elseif ( function_exists( 'is_plugin_active' ) ) {
3085 if ( is_plugin_active( 'wpfunnels-pro-integrations/wpfunnels-pro-integrations.php' ) ) {
3086 return true;
3087 }
3088 }
3089 return false;
3090 }
3091
3092
3093 /**
3094 * Get template types
3095 *
3096 * @return array
3097 * @since 2.4.11
3098 */
3099 public static function get_template_types() {
3100 $general_settings = self::get_general_settings();
3101 $types = array();
3102
3103 // Add WooCommerce templates if WooCommerce is active
3104 $types[] = array(
3105 'slug' => 'wc',
3106 'label' => 'Sales Templates',
3107 );
3108
3109 // Add LMS templates if LMS add-on and at least one LMS plugin (LearnDash or CreatorLMS) is active
3110 if ( self::is_lms_addon_active() && self::is_any_lms_plugin_active() ) {
3111 $types[] = array(
3112 'slug' => 'lms',
3113 'label' => 'LMS Templates',
3114 );
3115 }
3116
3117 // Lead generation templates are always available
3118 $types[] = array(
3119 'slug' => 'lead',
3120 'label' => 'Lead Gen Templates',
3121 );
3122
3123 // If funnel type is set to lead only, show only lead templates
3124 // if ( isset( $general_settings['funnel_type'] ) && 'lead' === $general_settings['funnel_type'] ) {
3125 // $types = array(
3126 // array(
3127 // 'slug' => 'lead',
3128 // 'label' => 'Lead Gen Templates',
3129 // ),
3130 // );
3131 // }
3132
3133 return apply_filters( 'wpfunnels/modify_template_type', $types );
3134
3135 }
3136
3137
3138 /**
3139 * Get global funnel type
3140 *
3141 * @return Mix
3142 */
3143 public static function get_global_funnel_type() {
3144 $general_settings = self::get_general_settings();
3145 if ( isset( $general_settings['funnel_type'] ) ) {
3146 return $general_settings['funnel_type'];
3147 }
3148 return false;
3149 }
3150
3151
3152 /**
3153 * May be allow to create sales funnel
3154 *
3155 * @return Bool
3156 */
3157 public static function maybe_allow_sales_funnel() {
3158 if ( self::is_wc_active() || self::is_lms_addon_active() ) {
3159 return true;
3160 }
3161 return false;
3162 }
3163
3164 /**
3165 * Retrieve all user role
3166 *
3167 * @return Array
3168 */
3169 public static function get_all_user_roles() {
3170 global $wp_roles;
3171
3172 $all_roles = isset( $wp_roles->roles ) ? $wp_roles->roles : array();
3173 $editable_roles = apply_filters( 'editable_roles', $all_roles );
3174
3175 return $editable_roles;
3176 }
3177
3178
3179 /**
3180 * Retrive all the product tags
3181 *
3182 * @return array
3183 * @since 2.4.11
3184 */
3185 public static function get_all_tags() {
3186 $term_array = array();
3187 if ( self::is_wc_active() ) {
3188 $terms = get_terms( 'product_tag' );
3189 if ( ! empty( $terms ) && ! is_wp_error( $terms ) ) {
3190 foreach ( $terms as $term ) {
3191
3192 $term_array[] = array(
3193 'id' => isset( $term->term_id ) ? $term->term_id : '',
3194 'name' => isset( $term->name ) ? $term->name : '',
3195 );
3196 }
3197 }
3198 }
3199 return $term_array;
3200 }
3201
3202 /**
3203 * Get all shiiping classes
3204 *
3205 * @return array
3206 * @since 2.4.10
3207 */
3208 public static function get_shipping_classes() {
3209
3210 if ( self::is_wc_active() ) {
3211 $shipping_classes = WC()->shipping()->get_shipping_classes();
3212 if ( $shipping_classes ) {
3213 return $shipping_classes;
3214 }
3215 }
3216 return array();
3217 }
3218
3219
3220 /**
3221 * Maybe global funnel
3222 *
3223 * @param String
3224 *
3225 * @return String
3226 *
3227 * @since 2.4.14
3228 */
3229 public static function maybe_global_funnel( $step_id = '' ) {
3230 if ( $step_id ) {
3231 $funnel_id = get_post_meta( $step_id, '_funnel_id', true );
3232 $is_gbf = get_post_meta( $funnel_id, 'is_global_funnel', true );
3233 if ( $is_gbf ) {
3234 return $is_gbf;
3235 }
3236 }
3237 return 'no';
3238 }
3239
3240
3241 /**
3242 * Get Woocommerce billing/shipping countries
3243 *
3244 * @return array
3245 * @since 2.4.18
3246 */
3247 public static function get_countries() {
3248 if ( self::is_wc_active() ) {
3249 $wc_countries = new \WC_Countries();
3250 $countries = $wc_countries->get_countries();
3251 if ( $countries ) {
3252 return $countries;
3253 }
3254 }
3255 return array();
3256 }
3257
3258
3259 /**
3260 * Check the checkout layout is express or not
3261 *
3262 * @return Bool
3263 * @since 2.4.18
3264 */
3265 public static function maybe_express_checkout( $checkout_id = '' ) {
3266 if ( ! $checkout_id ) {
3267 global $post;
3268 if ( ! $post ) {
3269 return false;
3270 }
3271 if ( wp_doing_ajax() || isset( $_GET['wc-ajax'] ) ) {
3272 $checkout_id = self::get_checkout_id_from_post( $_POST );
3273 } else {
3274 $checkout_id = $post->ID;
3275 }
3276 if ( ! $checkout_id ) {
3277 $checkout_id = get_the_ID();
3278 }
3279 }
3280
3281 $layout = get_post_meta( $checkout_id, '_wpfnl_checkout_layout', true );
3282
3283 return 'wpfnl-express-checkout' === $layout;
3284 }
3285
3286
3287
3288 /**
3289 * Sanitize request data
3290 *
3291 * @param $data
3292 *
3293 * @return Mix
3294 */
3295 public static function get_sanitized_get_post( $data = array() ) {
3296 if ( is_array( $data ) && ! empty( $data ) ) {
3297 return filter_var_array( $data, FILTER_SANITIZE_FULL_SPECIAL_CHARS );
3298 }
3299 return array(
3300 'get' => filter_input_array( INPUT_GET, FILTER_SANITIZE_FULL_SPECIAL_CHARS ),
3301 'post' => filter_input_array( INPUT_POST, FILTER_SANITIZE_FULL_SPECIAL_CHARS ),
3302 'request' => filter_var_array( $_REQUEST, FILTER_SANITIZE_FULL_SPECIAL_CHARS ),
3303 );
3304 }
3305
3306
3307
3308 /**
3309 * Update funnel type to lead
3310 *
3311 * @since 2.5.1
3312 */
3313 public static function update_funnel_type_to_lead() {
3314
3315 $saved_settings = self::get_admin_settings( '_wpfunnels_general_settings' );
3316 if ( isset( $saved_settings['funnel_type'] ) ) {
3317 $saved_settings['funnel_type'] = 'lead';
3318 update_option( '_wpfunnels_general_settings', $saved_settings );
3319 }
3320 }
3321
3322
3323 /**
3324 * Delete template transients
3325 *
3326 * @since 2.5.1
3327 */
3328 public static function wpfnl_delete_transient() {
3329 delete_option( WPFNL_TEMPLATES_OPTION_KEY . '_wc' );
3330 delete_option( WPFNL_TEMPLATES_OPTION_KEY . '_lms' );
3331 delete_option( WPFNL_TEMPLATES_OPTION_KEY . '_lead' );
3332
3333 delete_transient( 'wpfunnels_remote_template_data_wc_' . WPFNL_VERSION );
3334 delete_transient( 'wpfunnels_remote_template_data_lms_' . WPFNL_VERSION );
3335 delete_transient( 'wpfunnels_remote_template_data_lead_' . WPFNL_VERSION );
3336 delete_transient( 'wpfunnels_remote_template_data_store_checkout_' . WPFNL_VERSION );
3337 }
3338
3339
3340 /**
3341 * Get all the published funnel lists
3342 *
3343 * @return Array $funnels
3344 * @since 2.5.6
3345 */
3346 public static function get_funnel_list() {
3347 $funnels = get_posts(
3348 array(
3349 'post_type' => WPFNL_FUNNELS_POST_TYPE,
3350 'post_status' => 'publish',
3351 'numberposts' => -1,
3352 'fields' => 'ID',
3353 'orderby' => 'date',
3354 'order' => 'ASC',
3355 )
3356 );
3357 $formatted_funnel_data[' '] = __( 'Select funnel', 'wpfnl' );
3358 if ( is_array( $funnels ) ) {
3359 foreach ( $funnels as $funnel ) {
3360 $is_gbf = get_post_meta( $funnel->ID, 'is_global_funnel', true );
3361 if ( ! $is_gbf || 'no' === $is_gbf ) {
3362 $formatted_funnel_data[ self::get_funnel_link( $funnel->ID ) ] = $funnel->post_title;
3363 }
3364 }
3365 }
3366 return $formatted_funnel_data;
3367 }
3368
3369 /**
3370 * Check the log status is enabled or not
3371 *
3372 * @return Bool
3373 * @since 2.5.9
3374 */
3375 public static function maybe_logger_enabled() {
3376 $general_settings = get_option( '_wpfunnels_general_settings' );
3377 if ( $general_settings && isset( $general_settings['enable_log_status'] ) ) {
3378 return 'on' === $general_settings['enable_log_status'];
3379 }
3380 return false;
3381 }
3382
3383
3384
3385 /**
3386 * Check user permission to allow WPFunnels
3387 *
3388 * @param Array $permitted_role
3389 *
3390 * @return String $role
3391 * @since 2.6.2
3392 */
3393 public static function role_permission_to_allow_wpfunnel( $permitted_role = array() ) {
3394 return 'wpf_manage_funnels';
3395 }
3396
3397
3398 /**
3399 * Get supported step type
3400 * Landing, Checkout, Thankyou steps are supported for free
3401 *
3402 * @return Array $types
3403 * @since 2.5.7
3404 */
3405 public static function get_supported_step_type() {
3406 $types = array(
3407 array(
3408 'type' => 'landing',
3409 'name' => 'Landing',
3410 ),
3411 array(
3412 'type' => 'checkout',
3413 'name' => 'Checkout',
3414 ),
3415 array(
3416 'type' => 'upsell',
3417 'name' => 'Upsell',
3418 ),
3419 array(
3420 'type' => 'thankyou',
3421 'name' => 'Thankyou',
3422 ),
3423 );
3424
3425 return apply_filters( 'wpfunnels/supported_step_type', $types );
3426 }
3427
3428
3429 /**
3430 * Check if mint crm is installed
3431 *
3432 * @return bool
3433 * @since 1.0.0
3434 */
3435 public static function is_mint_mrm_active() {
3436 return apply_filters( 'is_mail_mint_pro_active', false );
3437 }
3438
3439 public static function is_mail_mint_free_active() {
3440 if ( is_plugin_active( 'mail-mint/mail-mint.php' ) ) {
3441 return true;
3442 }
3443 return false;
3444 }
3445
3446 public static function is_mail_mint_pro_license_active() {
3447 return apply_filters( 'is_mail_mint_pro_license_active', false );
3448 }
3449
3450 /**
3451 * Check if mint automation exist for a funnel by funnel id.
3452 *
3453 * @param int $funnel_id
3454 * @return bool
3455 * @since 1.0.0
3456 */
3457 public static function maybe_automation_exist_for_a_funnel( $funnel_id ) {
3458 return apply_filters( 'wpfunnels/maybe_automation_exist_for_a_funnel', false, $funnel_id );
3459 }
3460
3461 /**
3462 * Retrieve all automations
3463 *
3464 * @param int $page Current page number
3465 * @param int $per_page Number of items per page
3466 * @return array Array of automation data with pagination info
3467 * @since 3.7.0
3468 */
3469 public static function retrieve_all_automations( $page = 1, $per_page = 10 ){
3470 return apply_filters( 'wpfunnels/retrieve_all_automations', array(
3471 'data' => array(),
3472 'total' => 0,
3473 'total_pages' => 0,
3474 'current_page' => $page,
3475 'per_page' => $per_page,
3476 ), $page, $per_page );
3477 }
3478
3479 /**
3480 * Supported steps for allow settings
3481 *
3482 * @return array
3483 * @since 2.6.6
3484 */
3485 public static function get_settings_steps() {
3486 $settings_steps = array(
3487 'upsell',
3488 'downsell',
3489 'checkout',
3490 'thankyou',
3491 'delay',
3492 'sendMail',
3493 'createUser',
3494 'addTag',
3495 'addList',
3496 'removeTag',
3497 'removeList',
3498 'twilioSendMessage',
3499 'wpf_optin_submit',
3500 'wpf_order_placed',
3501 'wpf_cta_triggered',
3502 'wpf_order_bump_accepted',
3503 'wpf_offer_trigger',
3504 );
3505
3506 return apply_filters( 'wpfunnels/supported_settings_steps', $settings_steps );
3507 }
3508
3509
3510 /**
3511 * Supported steps for allow only settings
3512 *
3513 * @return array
3514 * @since 2.6.6
3515 */
3516 public static function get_only_settings_steps() {
3517 $settings_steps = array(
3518 'delay',
3519 'sendMail',
3520 'createUser',
3521 'addTag',
3522 'addList',
3523 'removeTag',
3524 'removeList',
3525 'twilioSendMessage',
3526 'wpf_optin_submit',
3527 'wpf_order_placed',
3528 'wpf_cta_triggered',
3529 'wpf_order_bump_accepted',
3530 'wpf_offer_trigger',
3531 );
3532
3533 return apply_filters( 'wpfunnels/supported_only_settings_steps', $settings_steps );
3534 }
3535
3536
3537 /**
3538 *
3539 */
3540 public static function get_default_automation() {
3541 $automation_data = array(
3542 'name' => 'automation-1',
3543 'status' => 'active',
3544 'author' => 1,
3545 'trigger_name' => 'wpf-offer-trigger',
3546 'steps' => array(
3547 array(
3548 'step_id' => 'mg3e1i',
3549 'key' => 'wp_user_login',
3550 'type' => 'trigger',
3551 'settings' => array(),
3552 'next_step_id' => 'zytv4',
3553 ),
3554 array(
3555 'step_id' => 'zytv4',
3556 'key' => 'createUser',
3557 'type' => 'action',
3558 'settings' => array(),
3559 'next_step_id' => '9w8vjh',
3560 ),
3561 array(
3562 'step_id' => '9w8vjh',
3563 'key' => 'addTag',
3564 'type' => 'action',
3565 'settings' => array(
3566 'tag_settings' => array(
3567 'tags' => array(
3568 array(
3569 'id' => 3,
3570 'title' => 'demo',
3571 ),
3572 ),
3573 ),
3574 ),
3575 'next_step_id' => '',
3576 ),
3577 ),
3578 'created_ago' => '3 seconds',
3579 );
3580
3581 return $automation_data;
3582 }
3583
3584
3585 /**
3586 * Get mint triggers
3587 *
3588 * @return array
3589 */
3590 public static function get_mint_triggers() {
3591 $triggers = array(
3592 'wpf_optin_submit',
3593 'wpf_order_placed',
3594 'wpf_cta_triggered',
3595 'wpf_order_bump_accepted',
3596 'wpf_offer_trigger',
3597 );
3598
3599 return apply_filters( 'wpfunnels/mint_triggers', $triggers );
3600 }
3601
3602
3603 /**
3604 * Get mint actions
3605 *
3606 * @return array
3607 */
3608 public static function get_mint_actions() {
3609 $actions = array(
3610 'delay',
3611 'sendMail',
3612 'createUser',
3613 'addTag',
3614 'addList',
3615 'removeTag',
3616 'removeList',
3617 'twilioSendMessage',
3618 );
3619
3620 return apply_filters( 'wpfunnels/mint_actions', $actions );
3621 }
3622
3623
3624 /**
3625 * Get all tags/list from mint
3626 *
3627 * @return array
3628 */
3629 public static function get_mint_contact_groups( $type = 'tags' ) {
3630 $class_name = 'Mint\\MRM\\DataBase\\Models\\ContactGroupModel';
3631 if ( class_exists( $class_name ) ) {
3632
3633 $groups = $class_name::get_all_lists_or_tags( $type );
3634 if ( $groups && is_array( $groups ) ) {
3635 $formatted_groups = array();
3636 $i = 1;
3637 foreach ( $groups as $group ) {
3638 $data = array(
3639 'index' => $i,
3640 'title' => $group['title'],
3641 'id' => $group['id'],
3642 'checked' => false,
3643 );
3644 array_push( $formatted_groups, $data );
3645 $i++;
3646 }
3647
3648 return $formatted_groups;
3649 }
3650 }
3651 return array();
3652 }
3653
3654
3655 /**
3656 * Get selected steps
3657 *
3658 * @param string $type
3659 * @param int $funnel_id
3660 *
3661 * @return array
3662 */
3663 public static function get_selected_steps( $type, $funnel_id ) {
3664 if ( $funnel_id ) {
3665 $steps = get_post_meta( $funnel_id, '_steps', true );
3666 if ( $steps && is_array( $steps ) ) {
3667 $i = 1;
3668 $formatted_steps = array();
3669 $step_types = array( $type );
3670 if ( 'landing' == $type ) {
3671 $step_types = array( $type, 'custom' );
3672 }
3673 foreach ( $steps as $step ) {
3674 if ( in_array( $step['step_type'], $step_types ) ) {
3675 $data = array(
3676 'id' => $i,
3677 'title' => $step['name'],
3678 'value' => $step['id'],
3679 );
3680 array_push( $formatted_steps, $data );
3681 $i++;
3682 }
3683 }
3684
3685 return $formatted_steps;
3686 }
3687 }
3688 return array();
3689 }
3690
3691
3692 /**
3693 * Get all order bump of a funnel
3694 *
3695 * @param int $funnel_id
3696 *
3697 * @return array
3698 */
3699 public static function get_all_ob( $funnel_id ) {
3700 if ( $funnel_id ) {
3701 $steps = self::get_steps( $funnel_id );
3702 if ( $steps && is_array( $steps ) ) {
3703 $key = array_search( 'checkout', array_column( $steps, 'step_type' ) );
3704 if ( false !== $key ) {
3705 if ( isset( $steps[ $key ]['id'] ) ) {
3706 $checkout_step_id = $steps[ $key ]['id'];
3707 $order_bumps = get_post_meta( $checkout_step_id, 'order-bump-settings', true );
3708 if ( $order_bumps && is_array( $order_bumps ) ) {
3709 $i = 1;
3710 $formatted_obs = array();
3711 foreach ( $order_bumps as $index => $ob ) {
3712 if ( is_array( $ob ) && isset( $ob['name'] ) ) {
3713 $data = array(
3714 'id' => $i,
3715 'title' => $ob['name'],
3716 'value' => $index,
3717 );
3718 array_push( $formatted_obs, $data );
3719 $i++;
3720 }
3721 }
3722 return $formatted_obs;
3723 }
3724 }
3725 }
3726 }
3727 }
3728 return array();
3729 }
3730
3731
3732
3733 /**
3734 * Get sequences from campaign table
3735 *
3736 * @return array
3737 * @since 1.0.0
3738 */
3739 public static function get_sequences() {
3740 if ( self::is_mint_mrm_active() && class_exists( 'Mint\\MRM\\DataBase\\Tables\\CampaignSchema' ) ) {
3741
3742 global $wpdb;
3743 $class_name = 'Mint\\MRM\\DataBase\\Tables\\CampaignSchema';
3744 $campaign_table = $wpdb->prefix . $class_name::$campaign_table;
3745 $results = $wpdb->get_results( $wpdb->prepare( "SELECT id as value, title as label FROM $campaign_table WHERE type = %s AND status = %s ", 'automation', 'created' ), ARRAY_A ); // phpcs:ignore.
3746 $default = array(
3747 array(
3748 'value' => '',
3749 'label' => 'Select Sequence',
3750 ),
3751 );
3752 if ( ! empty( $results ) ) {
3753 return array_merge( $default, $results );
3754 } else {
3755 return $default;
3756 }
3757 }
3758 return array();
3759 }
3760
3761
3762 /**
3763 * Get CFE deafult fields
3764 *
3765 * @return array
3766 * @since 2.7.0
3767 */
3768 public static function get_cfe_default_fields() {
3769 if ( self::is_wc_active() ) {
3770 $fields = array();
3771 $billing_default_field = WC()->countries->get_address_fields();
3772 foreach ( $billing_default_field as $key => $sf ) {
3773 $billing_default_field[ $key ]['enable'] = 1;
3774 $billing_default_field[ $key ]['show'] = 1;
3775 $billing_default_field[ $key ]['delete'] = 0;
3776 if ( ! ( isset( $sf['type'] ) ) ) {
3777 $billing_default_field[ $key ]['type'] = null;
3778 }
3779 if ( ! ( isset( $sf['placeholder'] ) ) ) {
3780 $billing_default_field[ $key ]['placeholder'] = null;
3781 }
3782 if ( ! ( isset( $sf['label'] ) ) ) {
3783 $billing_default_field[ $key ]['label'] = null;
3784 }
3785 if ( ! ( isset( $sf['validate'] ) ) ) {
3786 $billing_default_field[ $key ]['validate'] = null;
3787 }
3788 if ( ! ( isset( $sf['default'] ) ) ) {
3789 $billing_default_field[ $key ]['default'] = null;
3790 }
3791 }
3792
3793 $countries = new \WC_Countries();
3794 $shipping_default_fields = $countries->get_address_fields( $countries->get_base_country(), 'shipping_' );
3795 foreach ( $shipping_default_fields as $key => $sf ) {
3796 $shipping_default_fields[ $key ]['enable'] = 1;
3797 $shipping_default_fields[ $key ]['show'] = 1;
3798 $shipping_default_fields[ $key ]['delete'] = 0;
3799 if ( ! ( isset( $sf['type'] ) ) ) {
3800 $shipping_default_fields[ $key ]['type'] = null;
3801 }
3802 if ( ! ( isset( $sf['placeholder'] ) ) ) {
3803 $shipping_default_fields[ $key ]['placeholder'] = null;
3804 }
3805 if ( ! ( isset( $sf['label'] ) ) ) {
3806 $shipping_default_fields[ $key ]['label'] = null;
3807 }
3808 if ( ! ( isset( $sf['validate'] ) ) ) {
3809 $shipping_default_fields[ $key ]['validate'] = null;
3810 }
3811 if ( ! ( isset( $sf['default'] ) ) ) {
3812 $shipping_default_fields[ $key ]['default'] = null;
3813 }
3814 }
3815
3816 $order_comment = array(
3817 'type' => 'textarea',
3818 'class' => array( 'notes' ),
3819 'label' => __( 'Order notes', 'woocommerce' ),
3820 'placeholder' => esc_attr__(
3821 'Notes about your order, e.g. special notes for delivery.',
3822 'woocommerce'
3823 ),
3824 'name' => 'order_comments',
3825 'required' => false,
3826 'enable' => 1,
3827 'show' => 1,
3828 'default' => null,
3829 'validate' => null,
3830 'delete' => 0,
3831 );
3832
3833 $additional_default_fields = array(
3834 'order_comments' => $order_comment,
3835 );
3836
3837 $fields = array(
3838 'billing' => $billing_default_field,
3839 'shipping' => $shipping_default_fields,
3840 'additional' => $additional_default_fields,
3841 );
3842 return $fields;
3843 }
3844 }
3845
3846 /**
3847 * Generates and updates the first step id of the funnel
3848 *
3849 * @param int|string $funnel_id Funnel id.
3850 * @since 2.8.0
3851 */
3852 public static function generate_first_step( $funnel_id, $steps = array() ) {
3853 if ( $funnel_id ) {
3854 $steps = ! empty( $steps ) ? $steps : get_post_meta( $funnel_id, '_steps', true ); // Get step order
3855
3856 if ( empty( $steps ) ) {
3857 $steps = get_post_meta( $funnel_id, '_steps_order', true ); // Get step order
3858 }
3859 $priority_order = array( 'landing', 'custom', 'checkout', 'upsell', 'downsell', 'thankyou' );
3860 $first_step = array(
3861 'id' => null,
3862 'step_type' => '',
3863 );
3864
3865 if ( is_array( $steps ) && ! empty( $steps ) ) {
3866 foreach ( $steps as $step ) {
3867 if (
3868 isset( $step['step_type'], $step['id'] )
3869 && ( ! $first_step['id'] || ( array_search( $step['step_type'], $priority_order ) < array_search( $first_step['step_type'], $priority_order ) ) )
3870 ) {
3871 $first_step['id'] = $step['id'];
3872 $first_step['step_type'] = $step['step_type'];
3873 }
3874 }
3875 self::update_funnel_first_step( $funnel_id, $first_step['id'] );
3876 }
3877 }
3878 }
3879
3880 /**
3881 * Get the first step of a funnel
3882 *
3883 * @param int|string $funnel_id Funnel id.
3884 * @return string|int
3885 * @since 2.8.0
3886 */
3887 public static function get_first_step( $funnel_id ) {
3888 return get_post_meta( $funnel_id, '_first_step', true );
3889 }
3890
3891 /**
3892 * Updates the first step id of the funnel
3893 *
3894 * @param int|string $funnel_id Funnel id.
3895 * @param int|string $first_step_id First step id of the funnel.
3896 * @return void
3897 */
3898 public static function update_funnel_first_step( $funnel_id, $first_step_id ) {
3899 update_post_meta( $funnel_id, '_first_step', $first_step_id );
3900 }
3901
3902
3903 /**
3904 * Mail mint email
3905 *
3906 * @return mix
3907 */
3908 public static function get_mailmint_email() {
3909 if ( self::is_mint_mrm_active() ) {
3910 $email_settings = get_option( '_mrm_email_settings' );
3911 if ( isset( $email_settings['from_email'] ) ) {
3912 return $email_settings['from_email'];
3913 }
3914 }
3915 return false;
3916 }
3917
3918
3919 /**
3920 * Mail mint email
3921 *
3922 * @return mix
3923 */
3924 public static function get_mailmint_email_settings() {
3925 if ( self::is_mint_mrm_active() ) {
3926 return get_option( '_mrm_email_settings', \Mint\MRM\Utilites\Helper\Email::default_email_settings() );
3927 }
3928 return false;
3929 }
3930
3931
3932 /**
3933 * Mail mint email
3934 *
3935 * @return mix
3936 */
3937 public static function get_mailmint_twillo_settings() {
3938 if ( self::is_mint_mrm_active() ) {
3939 $settings = get_option( '_mint_integration_settings', array() );
3940 $twilio = isset( $settings['twilio'] ) ? $settings['twilio'] : array();
3941 return is_array( $twilio ) && ! empty( $twilio ) ? $twilio : array(
3942 'account_sid' => '',
3943 'auth_token' => '',
3944 'from_number' => '',
3945 'is_integrated' => false,
3946 );
3947 }
3948 return false;
3949 }
3950
3951
3952 /**
3953 * Maybe duplicate step
3954 *
3955 * @param $step_id Step ID
3956 *
3957 * @since 2.7.7
3958 * @return bool
3959 */
3960 public static function maybe_duplicate_step( $step_id ) {
3961
3962 if ( $step_id ) {
3963 $is_duplicate = get_post_meta( $step_id, '_is_duplicate', true );
3964 if ( 'yes' === $is_duplicate ) {
3965 return true;
3966 }
3967 }
3968 return false;
3969 }
3970
3971
3972 /**
3973 * Retrieves all created coupons from WooCommerce.
3974 * This function fetches all coupon posts of the 'shop_coupon' post type that are currently published in WooCommerce.
3975 *
3976 * @since 2.7.9
3977 * @return array An array of coupon codes and their corresponding names.
3978 */
3979 public static function get_all_coupons() {
3980 global $wpdb;
3981 $table_name = $wpdb->prefix . 'posts';
3982 $coupon_type = 'shop_coupon';
3983 $post_status = 'publish';
3984 $query = $wpdb->prepare(
3985 "SELECT post_title FROM $table_name WHERE post_type = %s AND post_status = %s ORDER BY post_name ASC LIMIT 100",
3986 $coupon_type,
3987 $post_status
3988 );
3989 $coupon_codes = array();
3990 $coupons = $wpdb->get_col( $query );
3991 if ( is_array( $coupons ) ) {
3992 foreach ( $coupons as $coupon ) {
3993 $coupon_codes[] = array(
3994 'name' => $coupon,
3995 );
3996 }
3997 }
3998 return $coupon_codes;
3999 }
4000
4001
4002 /**
4003 * Retrieves the applied coupon for a given step ID.
4004 * This function checks if a step ID is provided and retrieves the applied coupon associated with that step.
4005 * If no step ID is provided or the applied coupon is not found, it returns false.
4006 *
4007 * @param int $step_id The ID of the step for which to retrieve the applied coupon.
4008 *
4009 * @since 2.7.9
4010 * @return string|false The selected coupon code if found and auto-coupon feature is
4011 */
4012 public static function get_applied_coupon( $step_id ) {
4013 if ( ! $step_id ) {
4014 return false;
4015 }
4016 $auto_coupon = get_post_meta( $step_id, '_wpfnl_checkout_auto_coupon', true );
4017 if ( isset( $auto_coupon['enableAutoCoupon'], $auto_coupon['selectedCoupon'] ) && 'yes' === $auto_coupon['enableAutoCoupon'] && $auto_coupon['selectedCoupon'] ) {
4018 return $auto_coupon['selectedCoupon'];
4019 }
4020 return false;
4021 }
4022
4023 /**
4024 * Get step IDs for a given funnel.
4025 *
4026 * Retrieves an array of step IDs associated with a specific funnel, including A/B testing variations.
4027 *
4028 * @param int $funnel_id The ID of the funnel.
4029 * @return array An array of step IDs.
4030 * @since 2.7.10
4031 */
4032 public static function get_step_ids( $funnel_id ) {
4033 $steps = self::get_steps( $funnel_id );
4034
4035 $all_steps_including_ab = array();
4036 $all_steps_including_ab_ids = array();
4037 if ( is_array( $steps ) ) {
4038 foreach ( $steps as $step ) {
4039 if ( isset( $step['id'] ) ) {
4040 $all_steps_including_ab = get_post_meta( $step['id'], '_wpfnl_ab_testing_start_settings', true );
4041 if ( isset( $all_steps_including_ab['variations'] ) ) {
4042 $ids = array_column( $all_steps_including_ab['variations'], 'id' );
4043 $all_steps_including_ab_ids = array_merge( $all_steps_including_ab_ids, $ids );
4044 }
4045 }
4046 }
4047 }
4048
4049 return $all_steps_including_ab_ids;
4050 }
4051
4052 /**
4053 * Validates the order owner's authorization.
4054 *
4055 * @param WC_Order $order The order object to validate.
4056 * @return bool
4057 * @since 2.7.13
4058 */
4059 public static function is_valid_order_owner( $order, $order_key = '' ) {
4060
4061 if ( ! self::is_wc_active() || false === is_a( $order, 'WC_Order' ) ) {
4062 return false;
4063 }
4064
4065 // Validate via order_key when provided. The key is cryptographically random
4066 // and unpredictable, so possession of it proves the requester is the legitimate
4067 // order owner. This covers guest checkout and Express Checkout (Google Pay /
4068 // Apple Pay) in incognito mode where no WP user session or WC session exists.
4069 if ( ! empty( $order_key ) && $order->key_is_valid( $order_key ) ) {
4070 return true;
4071 }
4072
4073 // If it's not a guest order, current user can pay but only if it's their own order,
4074 // or they are an admin or shop manager or they are in a same session(for guest).
4075
4076 $order_has_customer = ! empty( $order->get_customer_id() );
4077 $is_authorized_owner = false;
4078
4079 $has_owner = ! empty( WC()->session->get( 'wpfnl_order_owner' ) );
4080
4081 if ( $order_has_customer ) {
4082 $is_order_owned_by_current_user = $order->get_customer_id() === get_current_user_id();
4083
4084 $is_authorized_owner = $is_order_owned_by_current_user || current_user_can( 'manage_woocommerce' );
4085 }
4086
4087 if ( ! $is_authorized_owner && ! $has_owner ) {
4088 return false;
4089 }
4090 return true;
4091 }
4092
4093
4094 /**
4095 * Capture a screenshot of a webpage given its URL and save it locally.
4096 *
4097 * @param string $url The URL of the webpage to capture the screenshot.
4098 * @param int $step_id The ID of the step associated with the screenshot.
4099 *
4100 * @return string The full URL of the captured screenshot if successful, an empty string otherwise.
4101 *
4102 * @since 2.9.0
4103 */
4104 public static function get_screenshot_from_url( $url, $step_id ) {
4105 try {
4106 $file_name = uniqid();
4107 $path = wp_upload_dir();
4108 $baseurl = $path['baseurl'] . '/wpfunnels';
4109 $path = $path['basedir'] . '/wpfunnels';
4110 $default_file = $path . '/index.php';
4111 if ( ! file_exists( $path ) ) {
4112 wp_mkdir_p( $path );
4113 }
4114
4115 if ( ! file_exists( $default_file ) ) {
4116 $file_handle = @fopen( trailingslashit( $path ) . 'index.php', 'wb' );
4117 if ( $file_handle ) {
4118 fwrite( $file_handle, $file['content'] );
4119 fclose( $file_handle );
4120 }
4121 }
4122
4123 \Spatie\Browsershot\Browsershot::url( $url )
4124 ->waitUntilNetworkIdle()
4125 ->windowSize( 1280, 800 )
4126 ->ignoreHttpsErrors()
4127 ->save( $screenshotPath );
4128
4129 // Update the post meta with the screenshot's base URL.
4130 update_post_meta( $step_id, 'wpfnl_step_screenshot_baseurl', $path . '/' . $file_name . '.png' );
4131
4132 // Return the full URL of the captured screenshot.
4133 return $baseurl . '/' . $file_name . '.png';
4134 } catch ( Exception $e ) {
4135 return '';
4136 }
4137 }
4138
4139
4140 /**
4141 * Update the screenshot URL for a step by its ID.
4142 *
4143 * @param int $step_id The ID of the step.
4144 * @param string $url The new screenshot URL to be set.
4145 *
4146 * @return bool True if the update is successful, false otherwise.
4147 *
4148 * @since 2.9.0
4149 */
4150 public static function maybe_update_screenshot_url_by_step_id( $step_id, $url ) {
4151 if ( ! $step_id || ! $url ) {
4152 return false;
4153 }
4154
4155 // Update the post meta for the step with the new screenshot URL.
4156 update_post_meta( $step_id, 'wpfnl_step_screenshot_url', $url );
4157
4158 return true;
4159 }
4160
4161
4162 /**
4163 * Update the modified date of a step's screenshot identified by its ID.
4164 *
4165 * @param int $step_id The ID of the step.
4166 *
4167 * @return bool True on success, false on failure.
4168 *
4169 * @since 2.9.0
4170 */
4171 public static function maybe_update_screenshot_modified_date_by_step_id( $step_id ) {
4172 if ( ! $step_id ) {
4173 return false;
4174 }
4175 if ( ! self::get_screenshot_url_by_step_id( $step_id ) ) {
4176 return false;
4177 }
4178 // Update the post meta for the step with the new screenshot modified date.
4179 update_post_meta( $step_id, 'wpfnl_step_screenshot_modified_date', date( 'Y-m-d H:i:s' ) );
4180
4181 return true;
4182 }
4183
4184
4185 /**
4186 * Get the screenshot URL for a step by its ID.
4187 *
4188 * @param int $step_id The ID of the step.
4189 *
4190 * @return string|false The screenshot URL if found, false if not found.
4191 *
4192 * @since 2.9.0
4193 */
4194 public static function get_screenshot_url_by_step_id( $step_id ) {
4195 if ( ! $step_id ) {
4196 return false;
4197 }
4198
4199 // Get the post meta for the step's screenshot URL.
4200 $url = get_post_meta( $step_id, 'wpfnl_step_screenshot_url', true );
4201
4202 if ( ! $url ) {
4203 return false;
4204 }
4205
4206 return $url;
4207 }
4208
4209
4210 /**
4211 * Get the modified date of a step identified by its ID.
4212 *
4213 * @param int $step_id The ID of the step.
4214 *
4215 * @return string|bool The modified date in 'Y-m-d H:i:s' format on success, false on failure.
4216 *
4217 * @since 2.9.0
4218 */
4219 public static function get_screenshot_modified_date_by_step_id( $step_id ) {
4220 if ( ! $step_id ) {
4221 return false;
4222 }
4223
4224 // Get the post meta for the step's screenshot modified date.
4225 $date = get_post_meta( $step_id, 'wpfnl_step_screenshot_modified_date', true );
4226
4227 if ( ! $date ) {
4228 return false;
4229 }
4230
4231 return $date;
4232 }
4233
4234
4235 /**
4236 * Get the modified date of a step by its ID.
4237 *
4238 * @param int $step_id The ID of the step.
4239 *
4240 * @return string|false The modified date if found, false if not found.
4241 *
4242 * @since 2.9.0
4243 */
4244 public static function get_the_modified_date_of_step( $step_id ) {
4245 if ( ! $step_id ) {
4246 return false;
4247 }
4248
4249 // Get the modified date of the step.
4250 $date = get_the_modified_date( 'Y-m-d H:i:s', $step_id );
4251
4252 if ( ! $date ) {
4253 return false;
4254 }
4255
4256 return $date;
4257 }
4258
4259
4260 /**
4261 * Delete the screenshot file associated with a step identified by its ID.
4262 *
4263 * @param int $step_id The ID of the step.
4264 *
4265 * @return bool True if the screenshot file is deleted successfully, false otherwise.
4266 */
4267 public static function maybe_delete_screenshot_by_step_id( $step_id ) {
4268
4269 if ( ! $step_id ) {
4270 return false;
4271 }
4272
4273 // Update the screenshot URL to get the file path.
4274 $path = get_post_meta( $step_id, 'wpfnl_step_screenshot_baseurl', true );
4275
4276 // Check if the file exists and is readable.
4277 if ( ! file_exists( $path ) ) {
4278 return false;
4279 }
4280
4281 // Try to delete the file.
4282 unlink( $path );
4283 return true;
4284 }
4285
4286
4287 /**
4288 * Get the URL of a Step with Optional UTM Parameters.
4289 *
4290 * This function retrieves the URL of a specified step within a funnel. It takes a funnel ID
4291 * and a step ID as input and returns the URL of the step. If UTM tracking is enabled for the
4292 * funnel, this function appends the UTM parameters to the URL as query parameters.
4293 *
4294 * @since 1.6.0
4295 *
4296 * @param int $funnel_id The ID of the funnel.
4297 * @param int $step_id The ID of the step whose URL needs to be retrieved.
4298 *
4299 * @return string|false The URL of the step with optional UTM parameters or false if the URL is not found.
4300 */
4301 public static function get_step_url( $funnel_id, $step_id ) {
4302 if ( ! $funnel_id || ! $step_id ) {
4303 return false;
4304 }
4305
4306 $url = get_the_permalink( $step_id );
4307
4308 if ( ! $url ) {
4309 return false;
4310 }
4311
4312 // Get UTM settings for the funnel.
4313 $utm_settings = self::get_funnel_utm_settings( $funnel_id );
4314
4315 // Check if UTM parameters are enabled.
4316 if ( ! is_array( $utm_settings ) || ! isset( $utm_settings['utm_enable'] ) || 'on' !== $utm_settings['utm_enable'] ) {
4317 return $url;
4318 }
4319
4320 unset( $utm_settings['utm_enable'] );
4321 $url = add_query_arg( $utm_settings, $url );
4322 $url = strtolower( $url );
4323
4324 return $url;
4325 }
4326
4327
4328 /**
4329 * Check if conditional logic is enabled for a specific step.
4330 *
4331 * This function checks whether the conditional logic feature is enabled for a given step
4332 * by checking the '_wpfnl_maybe_enable_condition' post meta value associated with the step.
4333 * If the value is 'yes', then the conditional logic is considered enabled; otherwise, it is not.
4334 *
4335 * @param int $step_id The ID of the step to check for conditional logic.
4336 * @return bool True if conditional logic is enabled, false otherwise.
4337 *
4338 * @since 2.9.0
4339 */
4340 public static function maybe_enable_condition( $step_id ) {
4341 if ( ! $step_id ) {
4342 return false;
4343 }
4344
4345 $is_enabled = get_post_meta( $step_id, '_wpfnl_maybe_enable_condition', true );
4346 if ( 'yes' !== $is_enabled ) {
4347 return false;
4348 }
4349
4350 return true;
4351 }
4352
4353
4354 /**
4355 * Get the conditions associated with a specific step.
4356 *
4357 * This function retrieves the conditions linked to a given step by querying the '_wpfnl_step_conditions'
4358 * post meta associated with that step. If conditions are found and are in an array format, they are returned;
4359 * otherwise, false is returned to indicate that no conditions or invalid conditions are available.
4360 *
4361 * @param int $step_id The ID of the step to retrieve conditions for.
4362 * @return array|false An array of conditions if available and valid, false otherwise.
4363 *
4364 * @since 2.9.0
4365 */
4366 public static function get_conditions( $step_id ) {
4367 if ( ! $step_id ) {
4368 return false;
4369 }
4370
4371 $conditions = get_post_meta( $step_id, '_wpfnl_step_conditions', true );
4372 if ( empty( $conditions ) || ! is_array( $conditions ) ) {
4373 return false;
4374 }
4375
4376 return $conditions;
4377
4378 }
4379
4380
4381 /**
4382 * Get the next step to be executed conditionally after the current step.
4383 *
4384 * This function retrieves the next step that should be executed after the current step
4385 * if certain conditions are met. The next step is retrieved by querying the '_wpfnl_next_step_after_condition'
4386 * post meta associated with the given step. If a valid array containing the next step information is found,
4387 * it is returned; otherwise, false is returned to indicate that no next step or invalid data is available.
4388 *
4389 * @param int $step_id The ID of the step to retrieve the conditional next step for.
4390 * @return array|false An array containing information about the next step if available and valid, false otherwise.
4391 *
4392 * @since 2.9.0
4393 */
4394 public static function get_conditional_next_step( $step_id ) {
4395 if ( ! $step_id ) {
4396 return false;
4397 }
4398
4399 $next_step = get_post_meta( $step_id, '_wpfnl_next_step_after_condition', true );
4400 if ( empty( $next_step ) || ! is_array( $next_step ) ) {
4401 return false;
4402 }
4403
4404 return $next_step;
4405
4406 }
4407
4408
4409 /**
4410 * Get the next step to be executed based on conditional criteria.
4411 *
4412 * This function determines the next step to be executed in a funnel based on conditional criteria.
4413 * If conditional criteria are not enabled for the step, it retrieves the next step using the
4414 * Wpfnl_functions::get_next_step method. If conditional criteria are enabled, it checks the conditions
4415 * using the WPFunnels\Conditions\Wpfnl_Condition_Checker class. If the conditions match, the true branch's
4416 * next step is returned; otherwise, the false branch's next step is returned.
4417 *
4418 * @param int $funnel_id The ID of the funnel to which the step belongs.
4419 * @param int $step_id The ID of the current step.
4420 * @param string $order Optional. The order in which the step is executed. Default is empty.
4421 * @param string $checker Optional. The checker to be used for condition checking. Default is 'accept'.
4422 * @return bool|array An array containing information about the next step and its type. if funnel id or step id is missing then it return false;
4423 *
4424 * @since 2.9.0
4425 */
4426 public static function get_next_conditional_step( $funnel_id, $step_id, $order = '', $checker = 'accept' ) {
4427
4428 if ( ! $funnel_id || ! $step_id ) {
4429 return false;
4430 }
4431
4432 $is_condition_enable = self::maybe_enable_condition( $step_id );
4433 if ( ! $is_condition_enable ) {
4434 return self::get_next_step( $funnel_id, $step_id );
4435 }
4436 $condition = \WPFunnels\Conditions\Wpfnl_Condition_Checker::getInstance();
4437 $condition_matched = $condition->check_condition( $funnel_id, $order, $step_id, $step_id, $checker );
4438 $conditional_next_step = self::get_conditional_next_step( $step_id );
4439
4440 if ( ! is_array( $conditional_next_step ) || empty( $conditional_next_step ) ) {
4441 return self::get_next_step( $funnel_id, $step_id, $condition_matched );
4442 }
4443
4444 if ( $condition_matched && empty( $conditional_next_step['true'] ) ) {
4445 return self::get_next_step( $funnel_id, $step_id, $condition_matched );
4446 } elseif ( ! $condition_matched && empty( $conditional_next_step['false'] ) ) {
4447 return self::get_next_step( $funnel_id, $step_id, $condition_matched );
4448 }
4449
4450 $next_node = array(
4451 'step_id' => $condition_matched ? $conditional_next_step['true'] : $conditional_next_step['false'],
4452 'step_type' => $condition_matched ? get_post_meta( $conditional_next_step['true'], '_step_type', true ) : get_post_meta( $conditional_next_step['false'], '_step_type', true ),
4453 );
4454
4455 return $next_node;
4456 }
4457
4458
4459
4460 /**
4461 * Update a meta key with a new value for a given step.
4462 *
4463 * @param int $step_id The ID of the step for which to update the meta.
4464 * @param string $meta_key The key of the meta data to update.
4465 * @param mixed $meta_value The new value to set for the meta key.
4466 *
4467 * @return bool True on success, false on failure.
4468 *
4469 * @since 3.0.0
4470 */
4471 public static function update_meta( $step_id, $meta_key, $meta_value ) {
4472 if ( ! $step_id || ! $meta_key ) {
4473 return false;
4474 }
4475 update_post_meta( $step_id, $meta_key, $meta_value );
4476 return true;
4477 }
4478
4479
4480 /**
4481 * Delete a meta key and its associated value for a given step.
4482 *
4483 * @param int $step_id The ID of the step from which to delete the meta.
4484 * @param string $meta_key The key of the meta data to delete.
4485 *
4486 * @return bool True on success, false on failure.
4487 * @since 3.0.0
4488 */
4489 public static function delete_meta( $step_id, $meta_key ) {
4490 if ( ! $step_id || ! $meta_key ) {
4491 return false;
4492 }
4493 delete_post_meta( $step_id, $meta_key );
4494 return true;
4495 }
4496 /**
4497 * Check if the current page is using the Gutenberg editor.
4498 *
4499 * This function checks whether the current page in the WordPress admin area is using the Gutenberg editor. It does so by checking the availability of a specific function associated with Gutenberg. If this function exists, it is likely that the Gutenberg editor is in use.
4500 *
4501 * @return bool True if the current page is using the Gutenberg editor, false otherwise.
4502 * @since 2.8.12
4503 */
4504 private static function is_gutenberg_edit_page() {
4505 if ( function_exists( 'wp_enqueue_script' ) && function_exists( 'wp_enqueue_style' ) ) {
4506 // Check if Gutenberg scripts and styles are enqueued
4507 return wp_script_is( 'wp-blocks' ) && wp_script_is( 'wp-element' ) && wp_style_is( 'wp-edit-blocks' );
4508 }
4509 return false;
4510 }
4511
4512 /**
4513 * Check if the current page is an Elementor edit page.
4514 *
4515 * This function checks whether the current page in the WordPress admin area is an edit page created with the Elementor page builder plugin. It does so by inspecting the 'action' query parameter in the URL. If the 'action' is set to 'elementor', it is likely an edit page created with Elementor.
4516 *
4517 * @return bool True if the current page is an Elementor edit page, false otherwise.
4518 * @since 2.8.12
4519 */
4520 private static function is_elementor_edit_page() {
4521 // Check if the 'action' query parameter is set to 'elementor'.
4522 if ( defined( 'ELEMENTOR_VERSION' ) && \Elementor\Plugin::$instance->editor->is_edit_mode() ) {
4523 return true;
4524 }
4525 return false;
4526 }
4527
4528 /**
4529 * Check if the current page is an edit page created with the Divi Builder.
4530 *
4531 * This function checks whether the current page in the WordPress admin area is an edit page created with the Divi Builder plugin. It does so by checking the availability of specific functions associated with Divi Builder. If these functions exist, it is likely an edit page created with Divi Builder.
4532 *
4533 * @return bool True if the current page is an edit page created with Divi Builder, false otherwise.
4534 * @since 2.8.12
4535 */
4536 private static function is_divi_edit_page() {
4537 // Check if the Divi Builder's assets are enqueued by verifying the presence of specific functions.
4538 return is_callable( 'et_pb_enqueue_main_scripts' ) && is_callable( 'et_theme_builder_overrides' );
4539 }
4540
4541 /**
4542 * Check if the current page is an Oxygen Builder edit page.
4543 *
4544 * This function checks whether the current page in the WordPress admin area is an Oxygen Builder edit page. It does so by verifying if specific Oxygen assets (scripts and styles) are enqueued. If the assets are enqueued, it is likely that the current page is an Oxygen edit page.
4545 *
4546 * @return bool True if the current page is an Oxygen edit page, false otherwise.
4547 * @since 2.8.12
4548 */
4549 private static function is_oxygen_edit_page() {
4550 // Check if Oxygen's assets are enqueued
4551 return wp_script_is( 'ct-automation' ) || wp_style_is( 'ct-select2' ) || 'ct_render_shortcode' === filter_input( INPUT_GET, 'action', FILTER_SANITIZE_SPECIAL_CHARS ) || filter_input( INPUT_GET, 'ct_builder', FILTER_SANITIZE_FULL_SPECIAL_CHARS ) || filter_input( INPUT_GET, 'ct_inner', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
4552 }
4553
4554 /**
4555 * Check if the current page is being edited using a specific page builder or any builder if not specified.
4556 *
4557 * This function checks whether the current page in the WordPress admin area is being edited using a specific page builder, such as Elementor, Divi, Oxygen, or Gutenberg. If no specific builder is provided, it checks for any of the supported page builders.
4558 *
4559 * @param string|null $builder (Optional) The name of the page builder to check (e.g., 'elementor', 'divi', 'oxygen', 'gutenberg'). If not specified, checks for any supported page builder.
4560 * @return bool True if the current page is being edited with the specified page builder or any supported builder, false otherwise.
4561 * @since 2.8.12
4562 */
4563 public static function is_builder_edit_page( $builder = null ) {
4564 switch ( $builder ) {
4565 case 'elementor':
4566 return self::is_elementor_edit_page();
4567 case 'divi':
4568 return self::is_divi_edit_page();
4569 case 'oxygen':
4570 return self::is_oxygen_edit_page();
4571 case 'gutenberg':
4572 return self::is_gutenberg_edit_page();
4573 default:
4574 // Check for any supported page builder.
4575 return self::is_elementor_edit_page() || self::is_gutenberg_edit_page() || self::is_divi_edit_page() || self::is_oxygen_edit_page() || 'edit' === filter_input( INPUT_GET, 'action', FILTER_SANITIZE_SPECIAL_CHARS );
4576 }
4577 }
4578
4579
4580 /**
4581 * Maybe remote funnel
4582 *
4583 * @return bool
4584 * @since 3.0.6
4585 */
4586 public static function maybe_remote_funnel() {
4587 if ( defined( 'REMOTE_FUNNEL_VERSION' ) ) {
4588 return 'yes';
4589 }
4590 return 'no';
4591 }
4592
4593
4594 /**
4595 * Removes a disconnected addstep node from the funnel data.
4596 *
4597 * @param array $funnel_data The funnel data.
4598 * @param int $funnel_id The ID of the funnel.
4599 * @return array The updated funnel data.
4600 */
4601 public static function remove_disconnected_addstep_node( $funnel_data, $funnel_id ) {
4602 if ( ! $funnel_id || ! isset( $funnel_data['drawflow']['Home']['data'] ) || empty( $funnel_data['drawflow']['Home']['data'] ) ) {
4603 return $funnel_data;
4604 }
4605
4606 $count = count( $funnel_data['drawflow']['Home']['data'] );
4607
4608 if ( $count <= 1 ) {
4609 return $funnel_data;
4610 }
4611
4612 // Loop through each step in funnel
4613 foreach ( $funnel_data['drawflow']['Home']['data'] as $key => &$step ) {
4614 // Find corresponding step in step id data
4615 if ( 'addstep' === $step['data']['step_type'] ) {
4616 $maybeEmptyInput = false;
4617 $maybeEmptyOutput = false;
4618 if ( empty( $step['inputs']['input_1']['connections'] ) ) {
4619 $maybeEmptyInput = true;
4620 }
4621
4622 if ( empty( $step['inputs'] ) ) {
4623 $maybeEmptyInput = true;
4624 }
4625
4626 if ( empty( $step['outputs'] ) ) {
4627 $maybeEmptyOutput = true;
4628 }
4629
4630 if ( empty( $step['outputs']['output_1']['connections'] ) ) {
4631 $maybeEmptyOutput = true;
4632 }
4633 if ( $maybeEmptyInput && $maybeEmptyOutput ) {
4634 unset( $funnel_data['drawflow']['Home']['data'][ $key ] );
4635 update_post_meta( $funnel_id, '_funnel_data', $funnel_data );
4636 }
4637 }
4638 }
4639
4640 return $funnel_data;
4641 }
4642
4643
4644 /**
4645 * Get all static text
4646 *
4647 * @return array
4648 * @since 3.0.13
4649 */
4650 public static function get_text() {
4651 return array(
4652 'error_occurred' => __( 'Error Occurred!', 'wpfnl' ),
4653 'stats' => __( 'Stats', 'wpfnl' ),
4654 'stats_tooltip_txt' => __( 'Toggle to get a quick view of visits & conversion of steps right on the canvas.', 'wpfnl' ),
4655 'find_your_templates' => __( 'Find your templates', 'wpfnl' ),
4656 'enable_global_funnel' => __( 'Enable Global Funnel', 'wpfnl' ),
4657 'enable_gbf_tooltip_txt' => __( 'Enabling this will convert this funnel into a conditional global funnel and you will have define conditions to trigger the funnel right from your WooCommerce store.', 'wpfnl' ),
4658 'save' => __( 'Save', 'wpfnl' ),
4659 'webhook' => __( 'Webhook', 'wpfnl' ),
4660 'analytics' => __( 'Analytics', 'wpfnl' ),
4661 'integrations' => __( 'Integrations', 'wpfnl' ),
4662 'publish' => __( 'Publish', 'wpfnl' ),
4663 'draft' => __( 'Draft', 'wpfnl' ),
4664 'enable' => __( 'Enable', 'wpfnl' ),
4665 'disable' => __( 'Disable', 'wpfnl' ),
4666 'delete' => __( 'Delete', 'wpfnl' ),
4667 'trash' => __( 'Trash', 'wpfnl' ),
4668 'deleting' => __( 'Deleting...', 'wpfnl' ),
4669 'settings' => __( 'Settings', 'wpfnl' ),
4670 'youtube_video' => __( 'Videos', 'wpfnl' ),
4671 'documentation' => __( 'Documentation', 'wpfnl' ),
4672 'blog' => __( 'Blog', 'wpfnl' ),
4673 'select_template_industries' => __( 'Select Template Industries', 'wpfnl' ),
4674 'select_template_builder' => __( 'Select Template Builder', 'wpfnl' ),
4675 'upload_image' => __( 'Upload image', 'wpfnl' ),
4676 'upload_image_tooltip' => __( 'Uploade Funnel Featured Image', 'wpfnl' ),
4677 'remove_image' => __( 'Remove image', 'wpfnl' ),
4678 'enter_seo_title' => __( 'Enter seo title', 'wpfnl' ),
4679 'enter_seo_desc' => __( 'Enter seo description', 'wpfnl' ),
4680 'save_data' => __( 'Save Data', 'wpfnl' ),
4681 'want_add_new_step' => __( 'Do you want to add a new step?', 'wpfnl' ),
4682 'what_change_you_need' => __( 'What Changes Do You Need in this Position?', 'wpfnl' ),
4683 'step_has_dependency' => __( 'The step you are deleting has a dependency. You can delete the step and connect the condition to the previous step or you can add a new step here.', 'wpfnl' ),
4684 'are_you_sure_to_delete_step' => __( 'Are you sure to delete this step?', 'wpfnl' ),
4685 'cancel' => __( 'Cancel', 'wpfnl' ),
4686 'no' => __( 'No', 'wpfnl' ),
4687 'connect_to_previous_step' => __( 'Connect to previous step', 'wpfnl' ),
4688 'add_new_step' => __( 'Add a new step', 'wpfnl' ),
4689 'yes' => __( 'Yes', 'wpfnl' ),
4690 'are_you_sure_delete_product' => __( 'Are you sure you want to delete this product?', 'wpfnl' ),
4691 'thankyou' => __( 'Thank you', 'wpfnl' ),
4692 'add_condition' => __( 'Add Condition', 'wpfnl' ),
4693 'add_featured_image' => __( 'Add Featured Image', 'wpfnl' ),
4694 'title' => __( 'Title', 'wpfnl' ),
4695 'url_slug' => __( 'URL Slug', 'wpfnl' ),
4696 'click_to_copy' => __( 'Click to Copy', 'wpfnl' ),
4697 'copied' => __( 'Copied!', 'wpfnl' ),
4698 'update' => __( 'Update', 'wpfnl' ),
4699 'enable_condition' => __( 'Enable Condition', 'wpfnl' ),
4700 'successfully_saved' => __( 'Succesfully saved', 'wpfnl' ),
4701 'no_condition_found' => __( 'No condition found', 'wpfnl' ),
4702 'add_new_condition' => __( 'Add New Condition', 'wpfnl' ),
4703 'and' => __( 'And', 'wpfnl' ),
4704 'or' => __( 'Or', 'wpfnl' ),
4705 'choose_next_steps' => __( 'Choose next steps', 'wpfnl' ),
4706 'false' => __( 'False', 'wpfnl' ),
4707 'please_select' => __( 'Please select', 'wpfnl' ),
4708 'select_steps' => __( 'Select Steps', 'wpfnl' ),
4709 'select_step' => __( 'Select Step', 'wpfnl' ),
4710 'add_step' => __( 'Add Step', 'wpfnl' ),
4711 'no_steps_found' => __( 'No steps found', 'wpfnl' ),
4712 'reconfigure_conditions' => __( 'Reconfigure Conditions', 'wpfnl' ),
4713 'reconfigure_conditions_helper' => __( 'Seems like you\'ve set a condition for the step earlier. Would you like to reconfigure?', 'wpfnl' ),
4714 'no_keep_the_same' => __( 'No, keep the same', 'wpfnl' ),
4715 'yes_reconfigure' => __( 'Yes, reconfigure', 'wpfnl' ),
4716 'zoom_in' => __( 'Zoom In', 'wpfnl' ),
4717 'zoom_level' => __( 'Zoom Level', 'wpfnl' ),
4718 'zoom_out' => __( 'Zoom Out', 'wpfnl' ),
4719
4720 // ------analytics------
4721 'weekly' => __( 'Weekly', 'wpfnl' ),
4722 'monthly' => __( 'Monthly', 'wpfnl' ),
4723 'yearly' => __( 'Yearly', 'wpfnl' ),
4724 'custom' => __( 'Custom', 'wpfnl' ),
4725 'start_date' => __( 'Start Date', 'wpfnl' ),
4726 'end_date' => __( 'End Date', 'wpfnl' ),
4727 'filter' => __( 'Filter', 'wpfnl' ),
4728 'conversion_overview' => __( 'Conversion Overview', 'wpfnl' ),
4729 'previous' => __( 'Previous', 'wpfnl' ),
4730 'next' => __( 'Next', 'wpfnl' ),
4731 'total_visitors' => __( 'Total visitors:', 'wpfnl' ),
4732 'unique_visitors' => __( 'unique visitors:', 'wpfnl' ),
4733 'conversion_rates' => __( 'conversion rates:', 'wpfnl' ),
4734 'bounce_rates' => __( 'Bounce Rates:', 'wpfnl' ),
4735 'no_data_found' => __( 'No data Found', 'wpfnl' ),
4736 'from' => __( 'From', 'wpfnl' ),
4737 'to' => __( 'To', 'wpfnl' ),
4738 'revenue' => __( 'Revenue', 'wpfnl' ),
4739 'are_you_sure_delete_analytics' => __( 'Are you sure to delete all analytics data? This won\'t affect other funnels.', 'wpfnl' ),
4740
4741 // ---webhook---
4742 'webhooks' => __( 'Webhooks', 'wpfnl' ),
4743 'search_by_name' => __( 'Search by Name', 'wpfnl' ),
4744 'add_webhook' => __( 'Add Webhook', 'wpfnl' ),
4745 'name' => __( 'Name', 'wpfnl' ),
4746 'request_url' => __( 'Request URL', 'wpfnl' ),
4747 'status' => __( 'Status', 'wpfnl' ),
4748 'actions' => __( 'Actions', 'wpfnl' ),
4749 'field_required' => __( 'Field Required', 'wpfnl' ),
4750 'key' => __( 'Key', 'wpfnl' ),
4751 'value' => __( 'Value', 'wpfnl' ),
4752 'select_value' => __( 'Select value', 'wpfnl' ),
4753 'select_name' => __( 'Select name', 'wpfnl' ),
4754 'add' => __( 'Add', 'wpfnl' ),
4755 'remove' => __( 'Remove', 'wpfnl' ),
4756 'delete_webhook' => __( 'Delete Webhook', 'wpfnl' ),
4757 'want_to_delete_webhook_list' => __( 'Are you sure you want to delete this List?', 'wpfnl' ),
4758 'edit_field' => __( 'Edit Field', 'wpfnl' ),
4759 'delete_field' => __( 'Delete Field', 'wpfnl' ),
4760
4761 // ----webhook settings------
4762 'give_name_or_id' => __( 'Give a name or ID to this webhook.', 'wpfnl' ),
4763 'allow_connect_3rd_party_services' => __( 'Allow to connect with 3rd party services.', 'wpfnl' ),
4764 'request_method' => __( 'Request Method', 'wpfnl' ),
4765 'select_http_request_method' => __( 'Select HTTP request sending method.', 'wpfnl' ),
4766 'select_method' => __( 'Select method', 'wpfnl' ),
4767 'request_format' => __( 'Request Format', 'wpfnl' ),
4768 'select_http_request_formate' => __( 'Select HTTP request sending format.', 'wpfnl' ),
4769 'select_format' => __( 'Select format', 'wpfnl' ),
4770 'webhook_events' => __( 'Webhook Events', 'wpfnl' ),
4771 'webhook_events_tooltip' => __( 'Select the WPFunnels event when the request would be sent.', 'wpfnl' ),
4772 'select_an_event' => __( 'Select an event', 'wpfnl' ),
4773 'request_body' => __( 'Request Body', 'wpfnl' ),
4774 'request_body_tooltip' => __( 'Select which values would be sent.', 'wpfnl' ),
4775 'all_fields' => __( 'All Fields', 'wpfnl' ),
4776 'select_fields' => __( 'Select Fields', 'wpfnl' ),
4777 'select_fields' => __( 'Add New Condition', 'wpfnl' ),
4778 'new_condition' => __( 'New Condition', 'wpfnl' ),
4779 'saved_successfully' => __( 'Saved Successfully', 'wpfnl' ),
4780 'please_select_an_event_first' => __( 'Please select an event first', 'wpfnl' ),
4781
4782 // ----funnels settings drawer.vue------
4783 'funnel_settings' => __( 'Funnel Settings', 'wpfnl' ),
4784 'utm_settings' => __( 'UTM Settings', 'wpfnl' ),
4785 'guide_on_utm_integration' => __( 'Guide On UTM Integration', 'wpfnl' ),
4786 'enable_utm_parameters_for_this_funnel' => __( 'Enable UTM Parameters For This Funnel', 'wpfnl' ),
4787 'pro' => __( 'pro', 'wpfnl' ),
4788 'referrer_utm_source' => __( 'Referrer (utm_source)', 'wpfnl' ),
4789 'medium_utm_medium' => __( 'Medium (utm_medium)', 'wpfnl' ),
4790 'campaign_utm_campaign' => __( 'Campaign (utm_campaign)', 'wpfnl' ),
4791 'content_utm_content' => __( 'Content (utm_content)', 'wpfnl' ),
4792 'event_tracking' => __( 'Event Tracking', 'wpfnl' ),
4793 'exclude_this_funnel_from_fb_pixel_tracking' => __( 'Exclude this funnel from FB Pixel tracking', 'wpfnl' ),
4794 'fb_pixel_tracking_hints' => __( 'Please connect from WPFunnels > Settings > Event Tracking to use it in this funnel.', 'wpfnl' ),
4795 'exclude_this_funnel_from_gtm_tracking' => __( 'Exclude this funnel from GTM tracking', 'wpfnl' ),
4796 'gtm_tracking_hints' => __( 'Please connect from WPFunnels > Settings > Event Tracking to use it in this funnel.', 'wpfnl' ),
4797 'more_settings' => __( 'More Settings', 'wpfnl' ),
4798 'skip_offers_for_identical_products_in_the_cart' => __( 'Skip offers for identical products in the cart', 'wpfnl' ),
4799 'skip_offers_cart_tooltip' => __( 'Enable this if you want to skip upsell or downsell offers (for Global Funnels only) when the offer product is the same as main product in the cart.', 'wpfnl' ),
4800 'dont_skip_offer_for_higher_quantity' => __( 'Don\'t skip if the offer is for a higher quantity', 'wpfnl' ),
4801 'dont_skip_offer_for_higher_quantity_tooltip' => __( 'Enabling this will mean that if the offer (for Global Funnels only) product is same as the product in the cart but with higher quantity, then it will not be skipped.', 'wpfnl' ),
4802 'skip_upsell_downsell_for_recurring_buyers' => __( 'Skip upsell/downsell for recurring buyers', 'wpfnl' ),
4803 'skip_upsell_downsell_for_recurring_buyers_tooltip' => __( 'Enabling this will mean if the upsell/downsell offer product was purchased by a buyer in the last 365 days, the offer will be skipped.', 'wpfnl' ),
4804 'threshold_max_365' => __( 'Threshold (max 365)', 'wpfnl' ),
4805 'threshold_max_365_tooltip' => __( 'You may specify the number of days (less than 365 days) within which the product has to be purchased for the offer to be skipped. For example, skip the offer if the product was purchased within the last 100 days.', 'wpfnl' ),
4806 'lms_sales_sunnel_support' => __( 'LMS Sales Funnel Support', 'wpfnl' ),
4807 'use_this_funnel_for_lms_only' => __( 'Use this funnel for LMS only', 'wpfnl' ),
4808 'use_this_funnel_for_lms_only_tooltip' => __( 'Enable this option to turn this funnel into a sales funnel for LMS. You can use it when you have a supported LMS activated such as LearnDash.', 'wpfnl' ),
4809 'save_changes' => __( 'Save Changes', 'wpfnl' ),
4810 'custom_css_desc' => __( 'Add custom CSS code here and it will be automatically added to the head section of this page. Do not include &lt;style&gt; tags.', 'wpfnl' ),
4811 'field_validation' => __( 'Field Validation', 'wpfnl' ),
4812 'enable_field_validation' => __( 'Enable Field validation error message', 'wpfnl' ),
4813 'enable_field_validation_desc' => __( 'Show custom validation error messages for required checkout fields.', 'wpfnl' ),
4814 'validation_message_label' => __( 'Validation error message', 'wpfnl' ),
4815
4816 // ----Global Funnel Offer Mode------
4817 'offer_selection_mode' => __( 'How Should the Offer be Selected?', 'wpfnl' ),
4818 'manual' => __( 'Specific Product', 'wpfnl' ),
4819 'auto_match' => __( 'Auto-match from Store', 'wpfnl' ),
4820 'recommended' => __( 'Recommended', 'wpfnl' ),
4821 'add_existing_product' => __( 'Add Existing Product', 'wpfnl' ),
4822 'create_product' => __( 'Create Product', 'wpfnl' ),
4823 'product' => __( 'PRODUCT', 'wpfnl' ),
4824 'total_price' => __( 'TOTAL PRICE', 'wpfnl' ),
4825 'no_product_yet' => __( 'No Product Yet', 'wpfnl' ),
4826 'fallback_behavior' => __( 'If No product Matches', 'wpfnl' ),
4827 'fallback_description' => __( 'What should happen when no rules match the main product?', 'wpfnl' ),
4828 'dont_show_upsell' => __( "Don’t show this offer", 'wpfnl' ),
4829 'skip_upsell_description' => __( 'Skip the offer if no rules match.', 'wpfnl' ),
4830 'show_default_product' => __( 'Show a default product', 'wpfnl' ),
4831 'default_product_description' => __( 'Offer a specific product when no rules match.', 'wpfnl' ),
4832
4833 // ----AB testing------
4834 'running' => __( 'Running', 'wpfnl' ),
4835 'draft' => __( 'Draft', 'wpfnl' ),
4836 'archived_variant' => __( 'Archived Variant', 'wpfnl' ),
4837 'ab_test' => __( 'A/B Testing', 'wpfnl' ),
4838 'click_to_copy_ab_url' => __( 'Click to Copy A/B URL', 'wpfnl' ),
4839 'copy_link' => __( 'Copy Link', 'wpfnl' ),
4840 'stats' => __( 'Stats', 'wpfnl' ),
4841 'traffic_distribution' => __( 'Traffic Distribution', 'wpfnl' ),
4842 'start' => __( 'Start', 'wpfnl' ),
4843 'pause' => __( 'Pause', 'wpfnl' ),
4844 'archive_list' => __( 'Archive List', 'wpfnl' ),
4845 'templates' => __( 'Templates', 'wpfnl' ),
4846 'duplicate' => __( 'Duplicate', 'wpfnl' ),
4847 'duplicating' => __( 'Duplicating..', 'wpfnl' ),
4848 'delete_variant' => __( 'Delete Variant', 'wpfnl' ),
4849 'are_you_sure_to_delete_this_variant' => __( 'Are you sure to delete this Variant?', 'wpfnl' ),
4850 'visits' => __( 'Visits', 'wpfnl' ),
4851 'conversion_rate' => __( 'Conversion Rate', 'wpfnl' ),
4852 'action' => __( 'Action', 'wpfnl' ),
4853 'retrieve' => __( 'Retrieve', 'wpfnl' ),
4854 'no_variation_found' => __( 'No Variation Found', 'wpfnl' ),
4855 'confirm_retrieve' => __( 'Confirm Retrieve', 'wpfnl' ),
4856 'are_you_sure_to_retrieve' => __( 'Are you sure to retrieve?', 'wpfnl' ),
4857 'confirm' => __( 'Confirm', 'wpfnl' ),
4858 'retrieving' => __( 'Retrieving...', 'wpfnl' ),
4859 'delete_this_variant' => __( 'Delete this Variant', 'wpfnl' ),
4860 'landing' => __( 'Landing', 'wpfnl' ),
4861 'checkout' => __( 'Checkout', 'wpfnl' ),
4862 'buy_now' => __( 'Buy Now', 'wpfnl' ),
4863 'upsell' => __( 'Upsell', 'wpfnl' ),
4864 'downsell' => __( 'Downsell', 'wpfnl' ),
4865 'conversion' => __( 'Conversion', 'wpfnl' ),
4866 'edit' => __( 'Edit', 'wpfnl' ),
4867 'view_step' => __( 'View Step', 'wpfnl' ),
4868 'more_option' => __( 'More Option', 'wpfnl' ),
4869 'declare_as_winner' => __( 'Declare as Winner', 'wpfnl' ),
4870 'make_archive' => __( 'Make Archive', 'wpfnl' ),
4871 'archiving' => __( 'Archiving...', 'wpfnl' ),
4872 'make_archive' => __( 'Make Archive', 'wpfnl' ),
4873 'traffic_distribution_tooltip' => __( 'Traffic distribution should be 100%', 'wpfnl' ),
4874 'close' => __( 'Close', 'wpfnl' ),
4875 'unlock_to_enter_value' => __( 'Unlock to Enter Value', 'wpfnl' ),
4876 'want_to_set_original' => __( 'Want to set “Original', 'wpfnl' ),
4877 'page_as_winner' => __( 'page” as a winner', 'wpfnl' ),
4878 'want_to_set' => __( 'Want to set', 'wpfnl' ),
4879 'as_a_winner' => __( 'as a winner', 'wpfnl' ),
4880 'set_variation_as_winner' => __( 'If you set this variation as a winner', 'wpfnl' ),
4881 'winner_check_list1' => __( 'Winner variant will be live on your site', 'wpfnl' ),
4882 'winner_check_list2' => __( 'Other variants will no longer available for the site visitors', 'wpfnl' ),
4883 'winner_check_list3' => __( 'Other variants will be on draft', 'wpfnl' ),
4884 'archive_all_except_winner' => __( 'Archive All Variants Except Winner', 'wpfnl' ),
4885 'declare_a_winner' => __( 'Declare a Winner', 'wpfnl' ),
4886
4887 // -----mail mint automation-----
4888 'automation' => __( 'Automation', 'wpfnl' ),
4889 'select_start_point' => __( 'Select A Start Point', 'wpfnl' ),
4890 'remove_this_trigger' => __( 'Remove this Trigger', 'wpfnl' ),
4891 'send_an_email' => __( 'Send An Email', 'wpfnl' ),
4892 'email_sequence' => __( 'Email Sequence', 'wpfnl' ),
4893 'assign_tags' => __( 'Assign Tag(s)', 'wpfnl' ),
4894 'add_to_lists' => __( 'Add To List(s)', 'wpfnl' ),
4895 'remove_tags' => __( 'Remove Tag(s)', 'wpfnl' ),
4896 'remove_lists' => __( 'Remove List(s)', 'wpfnl' ),
4897 'create_contact' => __( 'Create Contact', 'wpfnl' ),
4898 'outgoing_webhook' => __( 'Outgoing Webhook', 'wpfnl' ),
4899 'stop_automation' => __( 'Stop Automation', 'wpfnl' ),
4900 'delay' => __( 'Delay', 'wpfnl' ),
4901 'twilioSendMessage' => __( 'Send Message', 'wpfnl' ),
4902 'if_else' => __( 'If/Else', 'wpfnl' ),
4903 'set_hours_or_days' => __( 'Set a number of hours or days to wait before the next step of the journey is triggered.', 'wpfnl' ),
4904 'prepare_custom_email_template' => __( 'Prepare a custom email template to send to contacts that enter this automation flow.', 'wpfnl' ),
4905 'choose_an_email_sequence' => __( 'Choose an email sequence to send at this point of your automation flow.', 'wpfnl' ),
4906 'choose_tags_to_assign' => __( 'Choose Tag(s) to assign to contacts.', 'wpfnl' ),
4907 'choose_list_to_assign' => __( 'Choose List(s) to add contacts on.', 'wpfnl' ),
4908 'choose_tag_to_remove' => __( 'Choose certain tag(s) to remove from your contacts.', 'wpfnl' ),
4909 'choose_list_to_remove' => __( 'Remove contacts from selected lists(s).', 'wpfnl' ),
4910 'contact_meets_if_else' => __( 'Contact meets If/Else conditions.', 'wpfnl' ),
4911 'create_user_hints' => __( 'If the contact is not on the contacts list already, a new contact will be created.', 'wpfnl' ),
4912 'stop_automation_hints' => __( 'Use this action to stop your automation workflow at this point.', 'wpfnl' ),
4913 'webhook_outgoing_hints' => __( 'Send Data to any external server via GET or POST Methods at any point of the Automation workflow', 'wpfnl' ),
4914 'twillo_hints' => __( 'Send a message to the contact.', 'wpfnl' ),
4915 'not_set_up_yet' => __( 'Not set up yet', 'wpfnl' ),
4916 'assigned_tags' => __( 'Assigned Tags', 'wpfnl' ),
4917 'removed_tags' => __( 'Removed Tags', 'wpfnl' ),
4918 'assigned_lists' => __( 'Assigned Lists', 'wpfnl' ),
4919 'removed_lists' => __( 'Removed Lists', 'wpfnl' ),
4920 'select_status' => __( 'Select Status :', 'wpfnl' ),
4921 'welcome_email_from_wpfunnels' => __( 'Welcome email from WPFunnels', 'wpfnl' ),
4922 'stop_this_automation_workflow' => __( 'Stop This Automation Workflow', 'wpfnl' ),
4923 'send_data_via_get_post_method' => __( 'Send Data to external server via GET or POST Method', 'wpfnl' ),
4924 'delay_not_set_yet' => __( 'Delay Not Set Yet', 'wpfnl' ),
4925 'twilloBodyText' => __( 'Dispatch text message through Twilio SMS marketing.', 'wpfnl' ),
4926 'wait_for' => __( 'Wait for', 'wpfnl' ),
4927 'delete_this_step' => __( 'Delete this Step', 'wpfnl' ),
4928 'exit' => __( 'Exit', 'wpfnl' ),
4929 'choose_templates' => __( 'Choose Templates', 'wpfnl' ),
4930 'ready_email_templates' => __( 'Ready Email Templates', 'wpfnl' ),
4931 'my_saved_templates' => __( 'My Saved Templates', 'wpfnl' ),
4932 'edit_template' => __( 'Edit Template', 'wpfnl' ),
4933 'import' => __( 'Import', 'wpfnl' ),
4934 'do_you_want_to_save_automation' => __( 'Do you want to save the automation?', 'wpfnl' ),
4935 'no_back' => __( 'No & Back', 'wpfnl' ),
4936 'yes_back' => __( 'Yes & Back', 'wpfnl' ),
4937 'saving' => __( 'Saving...', 'wpfnl' ),
4938
4939 'choose_list' => __( 'Choose List', 'wpfnl' ),
4940 'select_lists' => __( 'Select Lists', 'wpfnl' ),
4941 'search_list' => __( 'Search List', 'wpfnl' ),
4942 'add_list' => __( 'Add List', 'wpfnl' ),
4943 'choose_tags' => __( 'Choose Tags', 'wpfnl' ),
4944 'select_tags' => __( 'Select Tags', 'wpfnl' ),
4945 'search_tag' => __( 'Search Tag', 'wpfnl' ),
4946 'add_tag' => __( 'Add Tag', 'wpfnl' ),
4947 'contact_status' => __( 'Contact Status', 'wpfnl' ),
4948 'select_status' => __( 'Select Status', 'wpfnl' ),
4949 'set_waiting_time' => __( 'Set waiting time', 'wpfnl' ),
4950 'select_time' => __( 'Select Time', 'wpfnl' ),
4951 'minutes' => __( 'Minutes', 'wpfnl' ),
4952 'hours' => __( 'Hours', 'wpfnl' ),
4953 'days' => __( 'Days', 'wpfnl' ),
4954 'weeks' => __( 'Weeks', 'wpfnl' ),
4955 'month' => __( 'Month', 'wpfnl' ),
4956 'year' => __( 'Year', 'wpfnl' ),
4957 'sender_email' => __( 'Sender Email', 'wpfnl' ),
4958 'sender_name' => __( 'Sender Name', 'wpfnl' ),
4959 'reply_email' => __( 'Reply Email', 'wpfnl' ),
4960 'reply_name' => __( 'Reply Name', 'wpfnl' ),
4961 'email_subject_line' => __( 'Email Subject Line', 'wpfnl' ),
4962 'email_preview_text' => __( 'Email Preview Text', 'wpfnl' ),
4963 'email_preview_placeholder' => __( 'Be Specific and concise to spark interest', 'wpfnl' ),
4964 'design' => __( 'Design', 'wpfnl' ),
4965 'select_a_template' => __( 'Select a Template', 'wpfnl' ),
4966 'choose_a_sequence' => __( 'Choose a sequence', 'wpfnl' ),
4967 'data_send_method' => __( 'Data Send Method', 'wpfnl' ),
4968 'remote_url' => __( 'Remote URL', 'wpfnl' ),
4969 'request_format' => __( 'Request Format', 'wpfnl' ),
4970 'request_body_data' => __( 'Request Body Data', 'wpfnl' ),
4971 'body_key' => __( 'Body Key', 'wpfnl' ),
4972 'body_value' => __( 'Body Value', 'wpfnl' ),
4973 'enter_key' => __( 'Enter key', 'wpfnl' ),
4974 'add_new_item' => __( 'Add new item', 'wpfnl' ),
4975 'add_new' => __( 'Add New', 'wpfnl' ),
4976 'request_header' => __( 'Request Header', 'wpfnl' ),
4977 'header_key' => __( 'Header Key', 'wpfnl' ),
4978 'header_value' => __( 'Header Value', 'wpfnl' ),
4979 'new_rule' => __( 'New Rule', 'wpfnl' ),
4980 'enter_a_value' => __( 'Enter a value', 'wpfnl' ),
4981 'select_date' => __( 'Select Date', 'wpfnl' ),
4982 'mark_this_email_as_transactional' => __( 'Mark this email as transactional', 'wpfnl' ),
4983 'mark_this_email_as_transactional_tooltip' => __( 'Unsubscribed contacts will still receive transactional emails like Order Summaries, Renewal Reminders, and Admin notifications.', 'wpfnl' ),
4984
4985 // -----step importer------
4986 'enter_step_name' => __( 'Enter A Step Name', 'wpfnl' ),
4987 'find_your_templates' => __( 'Find your templates', 'wpfnl' ),
4988 'all' => __( 'all', 'wpfnl' ),
4989 'free' => __( 'free', 'wpfnl' ),
4990 'premium' => __( 'Premium', 'wpfnl' ),
4991 'freemium' => __( 'Freemium', 'wpfnl' ),
4992 'custom' => __( 'Custom', 'wpfnl' ),
4993 'pages' => __( 'Pages', 'wpfnl' ),
4994 'start_from_scratch' => __( 'Start From Scratch', 'wpfnl' ),
4995 'oops_it_looks_like' => __( 'Oops! It looks like', 'wpfnl' ),
4996 'is_inactive' => __( 'is inactive.', 'wpfnl' ),
4997 'it_seems_like_you_have_selected' => __( 'It seems like you have selected', 'wpfnl' ),
4998 'preferred_page_builder' => __( 'as your preferred page builder, but you do not have', 'wpfnl' ),
4999 'activated_your_site' => __( 'activated on your site.', 'wpfnl' ),
5000 'you_see_we_create_funnel_templates_for_gutenberg' => __( 'You see, we create funnel templates for Gutenberg using', 'wpfnl' ),
5001 'please_install_and_activate' => __( 'Please install and activate', 'wpfnl' ),
5002 'to_import_funnel_page_templates_for_gutenberg' => __( 'to import funnel page templates for Gutenberg.', 'wpfnl' ),
5003 'click_here_to_install_and_activate' => __( 'Click here to install & activate', 'wpfnl' ),
5004 'if_you_want_to_create_funnel_steps_without' => __( 'If you want to create funnel steps without using', 'wpfnl' ),
5005 'then_dont_worry' => __( 'then don"t worry.', 'wpfnl' ),
5006 'create_from_scratch' => __( 'You can go ahead and create this step from scratch and design it with any page builder/editor. It will work just fine.', 'wpfnl' ),
5007 'selected_builder_inactive' => __( 'Oops! It looks like the page builder you selected is inactive.', 'wpfnl' ),
5008 'elementor_didnot_active' => __( 'as your preferred page builder, but you do not have the plugin activated on your site.', 'wpfnl' ),
5009 'elementor_template_import' => __( 'to import funnel templates.', 'wpfnl' ),
5010 'if_you_want_to_design_funnel_steps_without' => __( 'If you want to design the funnel steps without using', 'wpfnl' ),
5011 'divi_notice_body1' => __( 'It seems like you have selected Divi builder as your preferred page builder, but you do not have the plugin activated on your site. Please install and activate Divi builder to import funnel templates.', 'wpfnl' ),
5012 'divi_notice_body2' => __( 'If you want to design the funnel steps without using Divi builder, then don"t worry.', 'wpfnl' ),
5013
5014 'oxygen_notice_body1' => __( 'It seems like you have selected Oxygen builder as your preferred page builder, but you do not have the plugin Oxygen builder activated on your site.', 'wpfnl' ),
5015 'oxygen_notice_body2' => __( 'Please install and activate Oxygen builder to import ready funnel templates.', 'wpfnl' ),
5016 'oxygen_notice_body3' => __( 'If you want to create & design funnel pages without using Oxygen builder, then don"t worry.', 'wpfnl' ),
5017 'oxygen_notice_body4' => __( 'You can go ahead and create funnels from scratch using any page builder/editor. It will work just fine.', 'wpfnl' ),
5018
5019 'importing_step' => __( 'Importing Step', 'wpfnl' ),
5020 'preview' => __( 'Preview', 'wpfnl' ),
5021
5022 // -----integration-------
5023 'funnel_integration' => __( 'Funnel Integration', 'wpfnl' ),
5024 'add_new_integration' => __( 'Add New Integration', 'wpfnl' ),
5025 'delete_selected' => __( 'Delete Selected', 'wpfnl' ),
5026 'crm' => __( 'CRM', 'wpfnl' ),
5027 'trigger' => __( 'Trigger', 'wpfnl' ),
5028 'options' => __( 'Options', 'wpfnl' ),
5029 'are_you_sure_delete_automation' => __( 'Are you sure you want to delete this Automation?', 'wpfnl' ),
5030
5031 'integration_name' => __( 'Integration Name:', 'wpfnl' ),
5032 'edit_name' => __( 'Edit Name', 'wpfnl' ),
5033 'save_name' => __( 'Save Name', 'wpfnl' ),
5034 'cancel_changes' => __( 'Cancel Changes', 'wpfnl' ),
5035 'connect_crm' => __( 'Connect CRM', 'wpfnl' ),
5036 'select_crm' => __( 'Select CRM', 'wpfnl' ),
5037 'see_documantation' => __( 'See Documantation', 'wpfnl' ),
5038 'test_zapier_trigger' => __( 'Test Zapier Trigger', 'wpfnl' ),
5039 'choose_crm' => __( 'Choose A CRM To Start Setting Up Your Integration', 'wpfnl' ),
5040 'no_crm_notice' => __( 'It appears no CRMs or automation tools are connected or activated. Please activate or connect a supported automation tool to use this feature.', 'wpfnl' ),
5041 'are_you_sure_dummy_data' => __( 'Are you sure want to send dummy data?', 'wpfnl' ),
5042 'field_sent_successfully' => __( 'Field Sent Successfully', 'wpfnl' ),
5043 'automation_name_required' => __( 'Automation name is required', 'wpfnl' ),
5044 'when' => __( 'When', 'wpfnl' ),
5045 'user_event' => __( 'User Event', 'wpfnl' ),
5046 'select_event' => __( 'Select event', 'wpfnl' ),
5047 'then' => __( 'Then', 'wpfnl' ),
5048 'add_to_audience' => __( 'Add To Audience', 'wpfnl' ),
5049 'add_to_group' => __( 'Add To Group', 'wpfnl' ),
5050 'add_to_static_list' => __( 'Add To Static List', 'wpfnl' ),
5051 'add_to_list' => __( 'Add To List', 'wpfnl' ),
5052 'assign_tag' => __( 'Assign Tag', 'wpfnl' ),
5053 'enter_zapier_webhook_url' => __( 'Enter Zapier Webhook URL', 'wpfnl' ),
5054 'enter_pabbly_webhook_url' => __( 'Enter Pabbly Webhook URL', 'wpfnl' ),
5055 'select_tag' => __( 'Please select', 'wpfnl' ),
5056
5057 // -----coupon.vue----
5058 'select_coupon' => __( 'Select Coupon', 'wpfnl' ),
5059 'search_for_coupon' => __( 'Search for coupon', 'wpfnl' ),
5060
5061 // -----discount.vue----
5062 'discount_type' => __( 'Discount Type', 'wpfnl' ),
5063 'discount_type_tooltip' => __( 'Choose if you want to give a unique percentage/flat discount on your', 'wpfnl' ),
5064 'discount_type_tooltip2' => __( 'Choose if you want to give a unique percentage/flat discount on your offer product in the funnel.', 'wpfnl' ),
5065 'discount_type_tooltip3' => __( 'Choose if you want to give a unique percentage/flat discount on your main product.', 'wpfnl' ),
5066 'offer' => __( 'offer.', 'wpfnl' ),
5067 'discount_apply_to' => __( 'Discount Apply To', 'wpfnl' ),
5068 'discount_apply_to_tooltip' => __( 'Choose if you want the discount to be applied on the Regular Price or the Sale Price of the', 'wpfnl' ),
5069 'discount_apply_to_tooltip2' => __( 'Chose if you want the discount to be applied on the Regular Price or the Sale Price of the offer product.', 'wpfnl' ),
5070 'discount_apply_to_tooltip3' => __( 'Choose if you want the discount to be applied on the Regular Price or the Sale Price of the main product.', 'wpfnl' ),
5071 'offer_product' => __( 'offer product.', 'wpfnl' ),
5072 'discount_value' => __( 'Discount Value', 'wpfnl' ),
5073 'discount_value_tooltip' => __( '(when discount type is percentage) Assign a suitable percentage discount.', 'wpfnl' ),
5074 'discount_value_tooltip2' => __( '(when discount type is flat amount) Choose a certain amount to waive off.', 'wpfnl' ),
5075 'original_price' => __( 'Original Price', 'wpfnl' ),
5076 'sale_price' => __( 'Sale Price', 'wpfnl' ),
5077 'discounted_offer_price' => __( 'Discounted Offer Price', 'wpfnl' ),
5078 'discounted_offer_price_tooltip1' => __( 'This will be the', 'wpfnl' ),
5079 'discounted_offer_price_tooltip2' => __( 'offer price your buyer will pay.', 'wpfnl' ),
5080 'discounted_offer_price_tooltip3' => __( 'This will be the offer price your buyer will pay.', 'wpfnl' ),
5081 'discounted_offer_price_tooltip4' => __( 'This will be the main product price your buyer will pay.', 'wpfnl' ),
5082 'replace_first_product' => __( 'Replace First Product', 'wpfnl' ),
5083 'replace_first_product_hints' => __( 'It will replace the first selected product (from checkout products) with the order bump product.', 'wpfnl' ),
5084 'replace_product' => __( 'Replace Product', 'wpfnl' ),
5085 'pre_purchase_upsell_text' => __( 'Set as pre-purchase upsell', 'wpfnl' ),
5086 'pre_purchase_upsell_tooltip_text' => __( 'Enable this option to display a special offer to customers before they complete their purchase. The upsell will appear after they click the Place Order button, giving them a final opportunity to add the promoted product to their order.', 'wpfnl' ),
5087 'replace_product_tooltip' => __( 'Enabling this will mean that if a buyer accepts the order bump offer, then the order bump product will replace the main products in the checkout and the buyer will just have to pay for the order bump product.', 'wpfnl' ),
5088 'replace_product_hints' => __( 'It will replace all products (from checkout products) with the order bump product.', 'wpfnl' ),
5089
5090 'search_for_categories' => __( 'Search for categories', 'wpfnl' ),
5091 'search_for_tag' => __( 'Search for tag', 'wpfnl' ),
5092 'product' => __( 'Product', 'wpfnl' ),
5093
5094 'enter_funnel_if' => __( 'Enter Funnel If', 'wpfnl' ),
5095 'add_category' => __( 'Add Category', 'wpfnl' ),
5096 'add_product' => __( 'Add Existing Product', 'wpfnl' ),
5097 'amount' => __( 'Amount', 'wpfnl' ),
5098 'ammount_must_be_greater_than_1' => __( 'Amount must be greater than 1', 'wpfnl' ),
5099 'ammount_must_be_greater_than_0' => __( 'Amount must be greater than 0', 'wpfnl' ),
5100 'quantity' => __( 'Quantity', 'wpfnl' ),
5101 'quantity_must_be_greater_than_1' => __( 'Quantity must be greater than 1', 'wpfnl' ),
5102 'day_must_be_greater_than_or_euqal_1' => __( 'Day must be greater than or euqal 1', 'wpfnl' ),
5103 'role' => __( 'Role', 'wpfnl' ),
5104 'select_role' => __( 'Select Role', 'wpfnl' ),
5105 'class' => __( 'Class', 'wpfnl' ),
5106 'slect_shippin_class' => __( 'Select Shipping Class', 'wpfnl' ),
5107 'date' => __( 'Date :', 'wpfnl' ),
5108
5109 // -----image upload.vue------
5110 'product_image' => __( 'Product Image', 'wpfnl' ),
5111 'course_image' => __( 'Course Image', 'wpfnl' ),
5112 'product_image_tooltip' => __( 'You may change this image and use a custom image just for this order bump.', 'wpfnl' ),
5113 'click_to_change_image' => __( 'Click to Change Image', 'wpfnl' ),
5114 'click_to_update_image' => __( 'Drop an Image or ', 'wpfnl' ),
5115 'recommended_image_size' => __( 'Recommended image size 160px x 160px', 'wpfnl' ),
5116
5117 // -----orderbump.vue------
5118 'order_bump' => __( 'Order Bump', 'wpfnl' ),
5119 'add_order_bump' => __( 'Add Order Bump', 'wpfnl' ),
5120 'no_order_bump' => __( 'No Order Bump', 'wpfnl' ),
5121 'order_bump_hints1' => __( 'You can only add 1 order bump offer in the Free version.', 'wpfnl' ),
5122 'order_bump_hints2' => __( 'Upgrade to Pro now to create multiple order bump offers.', 'wpfnl' ),
5123 'upgrade_to_wpfunnels_pro' => __( 'Upgrade to WPFunnels Pro', 'wpfnl' ),
5124 'product_must_be_added' => __( 'Product must be added', 'wpfnl' ),
5125 'offer_must_be_selected' => __( 'Offer must be selected', 'wpfnl' ),
5126 'ob_default_product_name' => __( '6D Screen Protector (20% OFF)', 'wpfnl' ),
5127 'ob_highLight' => __( 'Special one time offer', 'wpfnl' ),
5128 'ob_checkbox_label' => __( 'Grab this offer with one click!', 'wpfnl' ),
5129 'ob_product_details' => __( 'Get this scratch proof 6D Tempered Glass Screen Protector for your iPhone. Keep your phone safe and sound just like a new one.', 'wpfnl' ),
5130 'ob_preview_tooltip' => __( 'The width of the order bump may vary depending on the page/container size on the Checkout Page or the device screen size.', 'wpfnl' ),
5131 'choose_offers' => __( 'Which Products to Pick from', 'wpfnl' ),
5132 'choose_offers_condition' => __( 'Select the rule that determines which product(s) will be automatically recommended as the upsell.', 'wpfnl' ),
5133 'select_product' => __( 'Select Product', 'wpfnl' ),
5134 'select_product_tooltip' => __( 'Choose the product that you want to offer as order bump at the checkout.', 'wpfnl' ),
5135 'search_for_product' => __( 'Search for product', 'wpfnl' ),
5136 'search_for_course' => __( 'Search for course', 'wpfnl' ),
5137 'select_course' => __( 'Select Course', 'wpfnl' ),
5138 'choose_the' => __( 'Choose the', 'wpfnl' ),
5139 'course' => __( 'course', 'wpfnl' ),
5140 'select_course_tooltip' => __( 'that you want to offer as order bump at the checkout.', 'wpfnl' ),
5141 'course_title' => __( 'Course Title', 'wpfnl' ),
5142 'product_title' => __( 'Product Title', 'wpfnl' ),
5143 'select_color_for_title' => __( 'Select Color for Title', 'wpfnl' ),
5144 'course_quantity' => __( 'Course Quantity', 'wpfnl' ),
5145 'product_quantity' => __( 'Product Quantity', 'wpfnl' ),
5146 'highlight_text' => __( 'Highlight Text', 'wpfnl' ),
5147 'hilight_text_color' => __( 'Select Color for Highlight Text', 'wpfnl' ),
5148 'checkbox_label' => __( 'Checkbox Label', 'wpfnl' ),
5149 'checkbox_title_color' => __( 'Select Color for Checkbox Title', 'wpfnl' ),
5150 'course_description' => __( 'Course Description', 'wpfnl' ),
5151 'product_description' => __( 'Product Description', 'wpfnl' ),
5152 'product_description_color' => __( 'Select Color for Product Description', 'wpfnl' ),
5153 'ob_delete_confirmation' => __( 'Are you sure you want to Delete the', 'wpfnl' ),
5154 'enable_order_bump' => __( 'Enable Order Bump', 'wpfnl' ),
5155 'delete_order_bump' => __( 'Delete Order Bump', 'wpfnl' ),
5156 'ob_name' => __( 'Order Bump Name', 'wpfnl' ),
5157 'select_template' => __( 'Template Style', 'wpfnl' ),
5158 'select_template_tooltip' => __( 'Choose a suitable template for your Order bump design.', 'wpfnl' ),
5159 'ob_position' => __( 'Display Position', 'wpfnl' ),
5160 'ob_position_tooltip' => __( 'Decide where the order bump offer should be placed in the checkout page.', 'wpfnl' ),
5161 'ob_arrow_color' => __( 'Arrow Color', 'wpfnl' ),
5162 'ob_remove_arrow_color' => __( 'Remove arrow color', 'wpfnl' ),
5163 'ob_bg_color' => __( 'Background Color', 'wpfnl' ),
5164 'ob_bg_color_tooltip' => __( 'Change the color of the Checkbox bar if you want to.', 'wpfnl' ),
5165 'ob_remove_bg_color' => __( 'Remove background color', 'wpfnl' ),
5166 'ob_main_color' => __( 'Main Color', 'wpfnl' ),
5167 'ob_main_color_tooltip' => __( 'Change the color of the Checkbox bar if you want to.', 'wpfnl' ),
5168 'ob_price_color' => __( 'Price Color', 'wpfnl' ),
5169 'ob_choose_variant_text' => __( 'Order Bump Choose Variant Text', 'wpfnl' ),
5170 'select_color_for_variant_text' => __( 'Select Color for Variant Text', 'wpfnl' ),
5171 'price' => __( 'Price', 'wpfnl' ),
5172 'regular_price' => __( 'Regular Price', 'wpfnl' ),
5173 'ob_template10_title' => __( 'to your order for only', 'wpfnl' ),
5174 'offer_price' => __( 'Offer Price', 'wpfnl' ),
5175
5176 // -----mint automation------
5177 'select_offer' => __( 'Select Offer', 'wpfnl' ),
5178 'select_order_bump' => __( 'Select Order Bump', 'wpfnl' ),
5179
5180 // -----step body------
5181 'new_step' => __( 'New Step', 'wpfnl' ),
5182 'new_step_hints' => __( 'Use this button to create the first step of the funnel.', 'wpfnl' ),
5183 'delete_this_step' => __( 'Delete this step', 'wpfnl' ),
5184 'ab_testing_running' => __( 'A/B Test Running', 'wpfnl' ),
5185 'view_automation' => __( 'View Automation', 'wpfnl' ),
5186 'add_automation_action' => __( 'Add Automation Action', 'wpfnl' ),
5187 'automation_running' => __( 'Automation running', 'wpfnl' ),
5188 'add_automation' => __( 'Add Automation', 'wpfnl' ),
5189 'upload_funnel_feature_image' => __( 'Uploade Funnel Featured Image', 'wpfnl' ),
5190 'oxygen_step_url' => __( 'Oxygen Builder Step URL', 'wpfnl' ),
5191
5192 'no_product_added' => __( 'No Product Added', 'wpfnl' ),
5193 'no_course_added' => __( 'No Course Added', 'wpfnl' ),
5194 'run_ab_split_test' => __( 'Run A/B Split Test', 'wpfnl' ),
5195 'to_funnel_update_msg' => __( 'Please update to WPFunnels Pro 1.7.3 or higher to use this feature.', 'wpfnl' ),
5196 'conditions' => __( 'Conditions', 'wpfnl' ),
5197
5198 // -----step settings drawer------
5199 'assign_the_main_funnel_product' => __( 'Assign the main funnel product here.', 'wpfnl' ),
5200 'courses' => __( 'Courses', 'wpfnl' ),
5201 'products' => __( 'Products', 'wpfnl' ),
5202 'set_ob_tooltip' => __( 'Set up an order bump offer at the checkout.', 'wpfnl' ),
5203 'edit_field_tooltip' => __( 'Checkout Field Editor for this funnel.', 'wpfnl' ),
5204 'edit_fields' => __( 'Edit Fields', 'wpfnl' ),
5205
5206 'add_new_field' => __( 'Add New Field', 'wpfnl' ),
5207 'select_section' => __( 'Select Section', 'wpfnl' ),
5208 'billing' => __( 'Billing', 'wpfnl' ),
5209 'shipping' => __( 'Shipping', 'wpfnl' ),
5210 'additional' => __( 'Additional', 'wpfnl' ),
5211 'type' => __( 'Type', 'wpfnl' ),
5212 'add_more' => __( 'Add More', 'wpfnl' ),
5213 'option_text' => __( 'Option text', 'wpfnl' ),
5214 'option_value' => __( 'Option value', 'wpfnl' ),
5215 'label' => __( 'Label', 'wpfnl' ),
5216 'placeholder' => __( 'Placeholder', 'wpfnl' ),
5217 'default_value' => __( 'Default Value', 'wpfnl' ),
5218 'validation' => __( 'Validation', 'wpfnl' ),
5219 'validations' => __( 'Validations', 'wpfnl' ),
5220 'required' => __( 'Required', 'wpfnl' ),
5221 'enabled' => __( 'Enabled', 'wpfnl' ),
5222 'display_in_order_detail' => __( 'Display in Order Detail Pages', 'wpfnl' ),
5223 'select_section_type' => __( 'Please select section type', 'wpfnl' ),
5224 'select_field_type' => __( 'Please select field type', 'wpfnl' ),
5225 'name_should_not_be_empty' => __( 'Name should not be empty', 'wpfnl' ),
5226 'label_should_not_be_empty' => __( 'Label should not be empty', 'wpfnl' ),
5227 'are_you_sure_delete_this_field' => __( 'Are you sure you want to delete this field?', 'wpfnl' ),
5228
5229 'billing_fields' => __( 'Billing Fields', 'wpfnl' ),
5230 'shipping_fields' => __( 'Shipping Fields', 'wpfnl' ),
5231 'additional_fields' => __( 'Additional Fields', 'wpfnl' ),
5232 'restore_to_default' => __( 'Restore to default', 'wpfnl' ),
5233 'add_field' => __( 'Add Field', 'wpfnl' ),
5234 'additional_options' => __( 'Additional Options', 'wpfnl' ),
5235 'custom_order_button_text' => __( 'Custom order button text', 'wpfnl' ),
5236 'custom_order_button_text_tooltip' => __( 'Set a custom text for the place order button.', 'wpfnl' ),
5237 'custom_billing_section_heading' => __( 'Custom Billing Section Heading', 'wpfnl' ),
5238 'custom_billing_section_heading_tooltip' => __( 'Set a custom heading text for the Billing Section.', 'wpfnl' ),
5239 'custom_shipping_section_heading' => __( 'Custom Shipping Section Heading', 'wpfnl' ),
5240 'custom_shipping_section_heading_tooltip' => __( 'Set a custom heading text for the Shipping Section.', 'wpfnl' ),
5241 'custom_order_detail_section_heading' => __( 'Custom Order Detail Section Heading', 'wpfnl' ),
5242 'custom_order_detail_section_heading_tooltip' => __( 'Set a custom heading text for the Order Detail Section.', 'wpfnl' ),
5243 'save_additional_changes' => __( 'Save Addtional Changes', 'wpfnl' ),
5244 'billint_details' => __( 'Billing details', 'wpfnl' ),
5245 'shipto_different_address' => __( 'Ship to a different address?', 'wpfnl' ),
5246 'your_order' => __( 'Your order', 'wpfnl' ),
5247 'place_order' => __( 'Place Order', 'wpfnl' ),
5248
5249 'this_product_in_trash' => __( 'This product is in the Trash. Please restore it', 'wpfnl' ),
5250 'recurring' => __( 'Recurring', 'wpfnl' ),
5251 'subtext' => __( 'Subtext', 'wpfnl' ),
5252 'enable_highlight' => __( 'Enable Highlight', 'wpfnl' ),
5253 'permanently_deleted' => __( 'This Product is permanently deleted', 'wpfnl' ),
5254 'edit_product' => __( 'Edit product', 'wpfnl' ),
5255 'delete_product' => __( 'Delete product', 'wpfnl' ),
5256
5257 // -------product tab content----
5258 'funnel_products' => __( 'Funnel Products', 'wpfnl' ),
5259 'funnel_products_tooltip' => __( 'This will be the main offer product of the funnel. Search for a product, select it, and then click on the "+ Add Product" button.', 'wpfnl' ),
5260 'add_course' => __( 'Add course', 'wpfnl' ),
5261 'total' => __( 'Total', 'wpfnl' ),
5262 'allow_use_of_coupon' => __( 'Allow Use Of Coupon', 'wpfnl' ),
5263 'allow_use_of_coupon_tooltip' => __( 'Enable this if you want to allow buyers to use coupons during checkout in the funnel.', 'wpfnl' ),
5264 'collapsible_coupon_field' => __( 'Collapsible Coupon Field', 'wpfnl' ),
5265 'collapsible_coupon_field_tooltip' => __( 'Enable this to show the coupon field in a collapsible section on the checkout page.', 'wpfnl' ),
5266 'collapsible' => __( 'Collapsible', 'wpfnl' ),
5267 'coupon_auto_applied' => __( 'Coupon (auto-applied)', 'wpfnl' ),
5268 'coupon_auto_applied_tooltip' => __( 'Enable this to allow Auto-apply Coupon during the checkout on this funnel.', 'wpfnl' ),
5269 'quantity_limit' => __( 'Enable Quantity Limit', 'wpfnl' ),
5270 'quantity_limit_tooltip' => __( 'Enable this settings to set the quantity limit for a single user', 'wpfnl' ),
5271 'set_quantity_limit' => __( 'Set the quantity limit for a single user', 'wpfnl' ),
5272 'set_quantity_limit_tooltip' => __( 'Set the quantity limit for a single user', 'wpfnl' ),
5273 'choose_coupon' => __( 'Choose coupon', 'wpfnl' ),
5274 'choose_coupon_tooltip' => __( 'Choose any existing WooCommerce coupon from the dropdown.', 'wpfnl' ),
5275 'enable_quantity_selection' => __( 'Enable Quantity Selection', 'wpfnl' ),
5276 'enable_quantity_selection_tooltip' => __( 'Enable this if you want to allow buyers to change the quantity of the product they want to buy.', 'wpfnl' ),
5277
5278 // ------downsell-------
5279 'upsell_course' => __( 'Upsell Course', 'wpfnl' ),
5280 'downsell_course' => __( 'Downsell Course', 'wpfnl' ),
5281 'downsell_product' => __( 'Downsell Product', 'wpfnl' ),
5282 'select_an_offer' => __( 'Please select an offer', 'wpfnl' ),
5283 'select_category' => __( 'Select Category', 'wpfnl' ),
5284 'choose_offer_category' => __( 'Choose offer category', 'wpfnl' ),
5285 'choose_offer_tag' => __( 'Choose offer tag', 'wpfnl' ),
5286 'selected_price_is_less_than1' => __( 'Selected price is less than 1', 'wpfnl' ),
5287 'gbf_product_quantity_tooltip' => __( 'The number of this upsell product to add to the cart when the customer accepts the offer.', 'wpfnl' ),
5288 'selected_quantity_is_less_than1' => __( 'Selected quantity is less than 1', 'wpfnl' ),
5289 'enable_replace_settings' => __( 'Enable Replace Settings', 'wpfnl' ),
5290 'enable_replace_settings_tooltip' => __( 'Enabling this will mean that if a buyer accepts the downsell offer, then the downsell offer product will replace the main product in the checkout and the buyer will just have to pay for the downsell offer product.', 'wpfnl' ),
5291 'replace_main_order_including_order_bump' => __( 'Replace Main Order Including Order Bump', 'wpfnl' ),
5292 'replace_main_order_excluding_order_bump' => __( 'Replace Main Order Excluding Order bump', 'wpfnl' ),
5293 'replace_all_prior_orders' => __( 'Replace All Prior Orders', 'wpfnl' ),
5294 'replace_order_in_previous_step' => __( 'Replace Order in Previous Step', 'wpfnl' ),
5295 'enable_replace_with_main_product' => __( 'Enable replace with the main product.', 'wpfnl' ),
5296 'enable_replace_with_main_product_tooltip1' => __( 'You must enable child orders for offers to use this feature.', 'wpfnl' ),
5297 'enable_replace_with_main_product_tooltip2' => __( 'Go to WPFunnels > Settings > Offer Settings and enable "Create a new child order."', 'wpfnl' ),
5298 'product_must_be_added' => __( 'Product must be added', 'wpfnl' ),
5299 'offer_must_be_selected' => __( 'Offer must be selected', 'wpfnl' ),
5300
5301 // ------thank you settings-------
5302 'show_order_overview' => __( 'Show Order Overview', 'wpfnl' ),
5303 'show_order_details' => __( 'Show Order Details', 'wpfnl' ),
5304 'show_billing_details' => __( 'Show Billing Details', 'wpfnl' ),
5305 'show_shipping_details' => __( 'Show Shipping Details', 'wpfnl' ),
5306 'thankyou_redicrection_page' => __( 'Thank You Page Redirection', 'wpfnl' ),
5307 'thankyou_redicrection_page_tooltip' => __( 'Redirect buyers to an external link after viewing the thank you page for a few seconds or take the buyer to another page instead of the thank you page.', 'wpfnl' ),
5308 'redirect_url' => __( 'Redirect URL', 'wpfnl' ),
5309 'redirect_without_viewing_thankyou' => __( 'Redirect without viewing Thank You Page', 'wpfnl' ),
5310 'redirect_without_viewing_thankyou_tooltip' => __( 'The buyer will be taken to the redirect URL directly instead of the thank you page.', 'wpfnl' ),
5311 'redirect_after_viewing_thankyou' => __( 'Redirect after viewing Thank You Page', 'wpfnl' ),
5312 'redirect_after_viewing_thankyou_tooltip' => __( 'The buyer be taken to thank you page, and after the set time, will be redirected to the given redirect URL.', 'wpfnl' ),
5313 'redirect_after_in_second' => __( 'Redirect after [ in second ]', 'wpfnl' ),
5314
5315 // -----upsell settings-----
5316 'upsell_product' => __( 'Upsell Product', 'wpfnl' ),
5317 'please_select_a_category' => __( 'Please select a category', 'wpfnl' ),
5318 'please_select_a_tag' => __( 'Please select a tag', 'wpfnl' ),
5319 'upsell_product_quantity_tooltip' => __( 'The value you input here will be added to the quantity of the product that triggered the funnel, which will be offered to the buyer as the upsell offer. For example, if someone purchases 2 t-shirts, and you input 3 here, the buyer will be offered 2+3 = 5 t-shirts as the upsell offer.', 'wpfnl' ),
5320 'upsell_enable_replace_settings_tooltip' => __( 'Enabling this will mean that if a buyer accepts the upsell offer, then the upsell offer product will replace the main product in the checkout and the buyer will just have to pay for the upsell offer product.', 'wpfnl' ),
5321
5322 // -------funnels template-------
5323 'steps' => __( 'Steps', 'wpfnl' ),
5324 'step' => __( 'Step', 'wpfnl' ),
5325 'getting_ready_to_import' => __( 'Getting ready to import', 'wpfnl' ),
5326 'step_creating' => __( 'Creating Step...', 'wpfnl' ),
5327 'click_to_upgrade' => __( 'Click to Upgrade Pro', 'wpfnl' ),
5328 'template_builder_tooltip1' => __( 'as your preferred page builder, but you do not have the plugin activated on your site. Please install and activate', 'wpfnl' ),
5329 'if_you_want_to_create_funnels_without_using' => __( 'If you want to create funnels without using', 'wpfnl' ),
5330 'create_funnel_from_scratch' => __( 'You can go ahead and create funnels from scratch with any page builder/editor. It will work just fine.', 'wpfnl' ),
5331 'we_have_ready_templates_for' => __( 'As of now, we have ready templates for', 'wpfnl' ),
5332 'more_template_coming_soon' => __( 'only, but we are planning to create templates for more builders soon.', 'wpfnl' ),
5333 'create_a_funnel' => __( 'Create A Funnel', 'wpfnl' ),
5334 'how_to_use_this_funnel' => __( 'How to use this funnel', 'wpfnl' ),
5335 'creating_funnel' => __( 'Creating Funnel...', 'wpfnl' ),
5336 'creating_store_checkout' => __( 'Creating Store Checkout...', 'wpfnl' ),
5337 'write_funnel_name' => __( 'Write Funnel Name', 'wpfnl' ),
5338 'templates' => __( 'Templates', 'wpfnl' ),
5339 'template' => __( 'Template', 'wpfnl' ),
5340 'please_wait' => __( 'Please Wait...', 'wpfnl' ),
5341
5342 // -------Available payment gateways-------
5343 'disable_payment_gateways' => __( 'Disable payment gateways for this checkout', 'wpfnl' ),
5344 'disable_payment_gateways_tooltip' => __( 'Disable payment gateways for this checkout to restrict payment options. This setting is useful for special cases where you want to manage payments manually or through alternative methods.', 'wpfnl' ),
5345
5346 // -------Time bound discount-------
5347 'startDateText' => __( 'Start Date', 'wpfnl' ),
5348 'endDateText' => __( 'End Date', 'wpfnl' ),
5349 'enableTimeBoundDiscountText' => __( 'Enable time bound discount', 'wpfnl' ),
5350 'enableTimeBoundDiscountTooltipText' => __( 'This allows you to set a date range for offering discounts. Simply select the start and end dates, and the discount will automatically apply to purchases made during this period.', 'wpfnl' ),
5351 'undo' => __('Undo', 'wpfnl'),
5352 'stepCopied' => __('Step copied', 'wpfnl'),
5353 'copy' => __('Copy', 'wpfnl'),
5354
5355 // -------Automation Analytics-------
5356 'report' => __('Report', 'wpfnl'),
5357 'back' => __('Back', 'wpfnl'),
5358 'automation' => __('Automation', 'wpfnl'),
5359 'performance' => __('Performance', 'wpfnl'),
5360 'open_rate' => __('Open Rate', 'wpfnl'),
5361 'click_rate' => __('Click Rate', 'wpfnl'),
5362 'email_sent' => __('Email Sent', 'wpfnl'),
5363 'open' => __('Open', 'wpfnl'),
5364 'click' => __('Click', 'wpfnl'),
5365 'overall_report' => __('Overall Report', 'wpfnl'),
5366 'entrance' => __('Entrance', 'wpfnl'),
5367 'subscribers_completed' => __('Subscribers Completed', 'wpfnl'),
5368 'welcome_to_wpfunnels' => __('Welcome to WPFunnels', 'wpfnl'),
5369 'setup_wizard' => __('Setup Wizard', 'wpfnl'),
5370 'support' => __('Support', 'wpfnl'),
5371 'video' => __('Video', 'wpfnl'),
5372
5373 'total_customers' => __('Total Customers', 'wpfnl'),
5374 'total_orders' => __('Total Orders', 'wpfnl'),
5375 'total_revenue' => __('Total Revenue', 'wpfnl'),
5376 'order_bump_revenue' => __('Order Bump Revenue', 'wpfnl'),
5377 'upsell_downsell_evenue' => __('Upsell/Downsell Revenue', 'wpfnl'),
5378 'growth_comparison' => __('Growth Comparison', 'wpfnl'),
5379 'previous_year' => __('Previous Year', 'wpfnl'),
5380 'current_year' => __('Current Year', 'wpfnl'),
5381 'top_performing_funnels' => __('Top Performing Funnels', 'wpfnl'),
5382 'funnel_name' => __('Funnel Name', 'wpfnl'),
5383 'views' => __('Views', 'wpfnl'),
5384 'conversion' => __('Conversion', 'wpfnl'),
5385 'conversion_rate' => __('Conversion Rate', 'wpfnl'),
5386 'no_top_performing_funnels' => __('You have no top performing funnels', 'wpfnl'),
5387 'today' => __('Today', 'wpfnl'),
5388 'week_to_date' => __('Week to date', 'wpfnl'),
5389 'month_to_date' => __('Month to date', 'wpfnl'),
5390 'year_to_date' => __('Year to date', 'wpfnl'),
5391 'previous_period' => __('Previous period', 'wpfnl'),
5392 'previous_year' => __('Previous year', 'wpfnl'),
5393
5394 // -------Funnel dashboard-------
5395
5396 // tour text
5397 'add_product_on_canvas' => __('Add Product', 'wpfnl'),
5398 'add_product_on_canvas_des' => __('To add a product to this funnel, click the cart icon. You can select an existing product from your store or create a new one. This will add the product to your funnel and allow you to adjust its quantity, price, and other details.', 'wpfnl'),
5399 'update_funnel_name' => __('Update Funnel Name', 'wpfnl'),
5400 'update_funnel_name_des' => __('To give your funnel a unique and recognizable name, simply click the Funnel Name field at the top. Enter your new name and make sure to Save your changes to update the funnel details.', 'wpfnl'),
5401 'view_funnel_stats' => __('View Funnel Stats', 'wpfnl'),
5402 'view_funnel_stats_des' => __("To monitor the performance of your funnel, click on the Stats button or navigate to the Analytics section. Here, you'll see key metrics like total leads, conversions, and revenue, helping you track and optimize your funnel's success.", 'wpfnl'),
5403 'preview_funnel' => __("Preview Funnel", 'wpfnl'),
5404 'preview_funnel_des' => __("Click the Preview button to see how your funnel looks in real-time. This allows you to review each step and ensure everything is set up as you want before going live.", 'wpfnl'),
5405 'ab_testing_on_canvas' => __("Enable A/B Testing", 'wpfnl'),
5406 'ab_testing_on_canvas_des' => __("Activate A/B Testing to compare different versions of your funnel steps. This feature allows you to test variations in content, design, and calls to action to determine which version performs better. Use the insights gained to optimize your funnel for maximum conversions.", 'wpfnl'),
5407 'condition_on_canvas' => __("Enable Conditional Funnel", 'wpfnl'),
5408 'condition_on_canvas_des' => __("To create a tailored experience for your users, enable the Conditional Funnel feature. This allows you to set specific conditions that determine which steps users will see based on their actions or selections. Customize your funnel flow to increase engagement and conversion rates.", 'wpfnl'),
5409 'add_new_step' => __("Add New Step", 'wpfnl'),
5410 'add_new_step_des' => __("To enhance your funnel, click the + Add New Step button. You can create various types of steps, such as landing pages, product pages, or thank-you pages. Each step allows you to customize content and settings to guide your customers effectively through the funnel.", 'wpfnl'),
5411 'search_ob' => __("Search and Select Order Bump Product", 'wpfnl'),
5412 'search_ob_des' => __("Use the search bar to find an existing product to offer as an order bump. Once you've found the product, select it to include it as an optional add-on during checkout. This will help increase your average order value.", 'wpfnl'),
5413 'modify_ob_title' => __("Modify Product Title", 'wpfnl'),
5414 'modify_ob_title_des' => __("To edit the product title, click on the product name field and enter a new title that accurately describes the product. A clear and concise title helps customers quickly understand what you're offering.", 'wpfnl'),
5415 'choose_ob_style' => __("Choose Order Bump Style", 'wpfnl'),
5416 'choose_ob_style_des' => __("Customize the appearance of your order bump by selecting a style that fits your funnel’s design. You can choose from various layout options and adjust colors, fonts, and other visual elements to make your order bump stand out during checkout.", 'wpfnl'),
5417 'select_ob_position' => __("Select Order Bump Position", 'wpfnl'),
5418 'select_ob_position_des' => __("Select where you want the order bump to appear during checkout. You can position it above or below the payment details to ensure maximum visibility and encourage customers to add the extra product.", 'wpfnl'),
5419 'save_ob' => __("Save Your Order Bump", 'wpfnl'),
5420 'save_ob_des' => __("Make sure to click the Save button to keep your order bump settings. This ensures that your changes are applied and your order bump is active for your funnel. Don’t forget to review all details before saving!", 'wpfnl'),
5421 );
5422 }
5423
5424 /**
5425 * Maybe current theme is bricks
5426 *
5427 * @return bool
5428 * @since 3.1.0
5429 */
5430 public static function maybe_bricks_theme() {
5431 $current_theme = wp_get_theme();
5432 $parent_theme = $current_theme->parent();
5433
5434 if ('Bricks' === $current_theme->get('Name')) {
5435 return true;
5436 }
5437
5438 if ($parent_theme && 'Bricks' === $parent_theme->get('Name')) {
5439 return true;
5440 }
5441
5442 return false;
5443 }
5444
5445
5446 /**
5447 * Maybe current theme is WoodMart
5448 *
5449 * @return bool
5450 * @since 3.1.0
5451 */
5452 public static function maybe_woodmart_theme() {
5453 $current_theme = wp_get_theme();
5454 $parent_theme = $current_theme->parent();
5455
5456 if ('Woodmart' === $current_theme->get('Name')) {
5457 return true;
5458 }
5459
5460 if ($parent_theme && 'Woodmart' === $parent_theme->get('Name')) {
5461 return true;
5462 }
5463
5464 return false;
5465 }
5466
5467
5468 /**
5469 * Get WooCommerce price & currency configuration
5470 *
5471 * @return array
5472 * @since 3.0.13
5473 */
5474 public static function get_wc_price_config() {
5475 $config = array(
5476 'currency_symbol' => '$',
5477 'currency_position' => 'left',
5478 'thousand_separator' => ',',
5479 'decimal_separator' => '.',
5480 'decimal_places' => 2,
5481 'price_format' => '%1$s%2$s',
5482 );
5483
5484 if ( self::is_wc_active() ) {
5485 $config = array(
5486 'currency_symbol' => get_woocommerce_currency_symbol(),
5487 'currency_position' => get_option( 'woocommerce_currency_pos' ),
5488 'thousand_separator' => wc_get_price_thousand_separator(),
5489 'decimal_separator' => wc_get_price_decimal_separator(),
5490 'decimal_places' => wc_get_price_decimals(),
5491 'price_format' => get_woocommerce_price_format(),
5492 );
5493 }
5494 return $config;
5495 }
5496
5497
5498 /**
5499 * Get default meta for each steps
5500 *
5501 * @param $step_type
5502 * @return array|array[]
5503 *
5504 * @since 3.1.0
5505 */
5506 public static function get_step_default_meta( $step_type ) {
5507 $default_meta = array();
5508 switch ( $step_type ) {
5509 case 'landing':
5510 $default_meta = Wpfnl_Step_Meta_keys::get_landing_meta();
5511 break;
5512 case 'checkout':
5513 $default_meta = Wpfnl_Step_Meta_keys::get_checkout_meta();
5514 break;
5515 case 'thankyou':
5516 $default_meta = Wpfnl_Step_Meta_keys::get_thankyou_meta();
5517 break;
5518 case 'upsell':
5519 case 'downsell':
5520 $default_meta = Wpfnl_Step_Meta_keys::get_offer_meta();
5521 break;
5522 case 'custom':
5523 $default_meta = Wpfnl_Step_Meta_keys::get_custom_meta();
5524 break;
5525 default:
5526 break;
5527 }
5528 return $default_meta;
5529 }
5530
5531
5532 /**
5533 * Get step type from step id
5534 *
5535 * @param $step_id
5536 * @return mixed
5537 * @since 3.1.0
5538 */
5539 public static function get_step_type( $step_id ) {
5540 return get_post_meta( $step_id, '_step_type', true );
5541 }
5542
5543 /**
5544 * Check the current page is funnel page
5545 *
5546 * @return bool
5547 * @since 3.1.4
5548 */
5549 public static function maybe_funnel_page() {
5550 $supported_pages = array( 'wpfnl_settings', 'wpf-license', 'edit_funnel', 'wp_funnels' );
5551 if ( isset( $_GET['page'] ) && in_array( $_GET['page'], $supported_pages ) ) {
5552 return true;
5553 }
5554 return false;
5555 }
5556
5557
5558
5559 /**
5560 * Retrieves the list of enabled payment gateways.
5561 *
5562 * @return array The list of enabled payment gateways.
5563 *
5564 * @since 3.1.8
5565 */
5566 public static function get_enabled_payment_gateways() {
5567 if ( ! self::is_wc_active() ) {
5568 return array();
5569 }
5570 $gateways = WC()->payment_gateways->get_available_payment_gateways();
5571 $enabled_gateways = array();
5572 if ( is_array( $gateways ) && ! empty( $gateways ) ) {
5573 foreach ( $gateways as $gateway ) {
5574 if ( $gateway->enabled == 'yes' ) {
5575 $enabled_gateways[ $gateway->id ] = $gateway->title;
5576 }
5577 }
5578 }
5579 return $enabled_gateways;
5580 }
5581
5582
5583 /**
5584 * Check the slug is already available or not
5585 *
5586 * @param string $slug
5587 * @param int $post_id
5588 * @param string $title
5589 * @return bool
5590 *
5591 * @since 3.1.8
5592 */
5593 public static function is_slug_available( $slug, $post_id = 0, $title = '' ) {
5594 global $wpdb;
5595
5596 // If no title is provided, use the slug itself
5597 if ( empty( $title ) ) {
5598 $title = $slug;
5599 }
5600
5601 // Check if the generated slug exists in the database
5602 $query = $wpdb->prepare( "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND ID != %d", $slug, $post_id );
5603 $result = $wpdb->get_var( $query );
5604
5605 // If the result is null, the slug is available
5606 if ( is_null( $result ) ) {
5607 return true;
5608 }
5609
5610 return false;
5611 }
5612
5613
5614 // Function to get the total price of a composite product
5615 public static function get_composite_product_price( $composite_product_id, $use_regular_price = false ) {
5616 // Get the composite product object
5617 $composite_product = wc_get_product( $composite_product_id );
5618
5619 // Check if the product is a composite product
5620 if ( ! $composite_product || 'composite' !== $composite_product->get_type() ) {
5621 return 'The product is not a composite product.';
5622 }
5623
5624 // Initialize total price
5625 $total_price = $use_regular_price ? $composite_product->get_regular_price() : $composite_product->get_price();
5626
5627 // Get components
5628 $components = $composite_product->get_components();
5629
5630 // Loop through each component
5631 foreach ( $components as $component_id => $component ) {
5632 // Get the selected option (or default option if no selection)
5633 $selected_option = $component->get_default_option();
5634
5635 // Check if component is optional and no selection made
5636 if ( $component->is_optional() && ! $selected_option ) {
5637 continue;
5638 }
5639
5640 // Get the product object for the selected option
5641 $product = wc_get_product( $selected_option );
5642 $configuration = array();
5643 // Calculate price based on selected option and quantity
5644 if ( $product ) {
5645 $component_quantity = $component->get_quantity( $configuration );
5646 $product_price = $use_regular_price ? $product->get_regular_price() : $product->get_price();
5647
5648 // Add the price of the selected option multiplied by the quantity
5649 $total_price += $product_price * $component_quantity;
5650 }
5651 }
5652
5653 // Apply any composite product specific pricing rules or discounts
5654 // Note: This step may vary based on how your site applies discounts or custom pricing rules
5655 // $total_price = apply_composite_product_discounts($composite_product, $total_price);
5656
5657 // Format and return the total price
5658 return $total_price;
5659 }
5660
5661
5662 public static function add_composite_product_to_cart_with_defaults( $composite_product_id, $quantity, $use_regular_price = false ) {
5663
5664 // Get the composite product object
5665 $composite_product = wc_get_product( $composite_product_id );
5666
5667 if ( ! defined( 'WC_CP_VERSION' ) ) {
5668 return $use_regular_price ? $composite_product->get_regular_price() : $composite_product->get_price();
5669 }
5670
5671 // Check if the product is a composite product
5672 if ( ! $composite_product || 'composite' !== $composite_product->get_type() ) {
5673 return 'The product is not a composite product.';
5674 }
5675
5676 // Prepare the components array for the cart
5677 $cart_item_data = array(
5678 'composite_data' => array(),
5679 );
5680
5681 $components = $composite_product->get_components();
5682
5683 foreach ( $components as $component_id => $component ) {
5684 // Get the default option for the component
5685 $selected_option_id = $component->get_default_option();
5686
5687 if ( ! $selected_option_id && ! $component->is_optional() ) {
5688 return 'Missing required component option for component ID ' . $component_id;
5689 }
5690
5691 // Get the product object for the selected option
5692 $product = wc_get_product( $selected_option_id );
5693
5694 // Assuming configuration array as an empty array for this example
5695 // Ideally, this should contain the current state of the component configuration
5696 $configuration = array(); // You should replace this with actual configuration if available
5697
5698 // Calculate quantity
5699 $component_quantity = $component->get_quantity( $configuration );
5700
5701 // Add selected option and quantity to cart item data if the option is not null
5702 if ( $selected_option_id ) {
5703 $cart_item_data['composite_data'][ $component_id ] = array(
5704 'product_id' => $selected_option_id,
5705 'quantity' => $component_quantity,
5706 );
5707 }
5708 }
5709
5710 // Add the composite product to the cart
5711 $added = WC()->cart->add_to_cart( $composite_product_id, $quantity, 0, array(), $cart_item_data );
5712
5713 if ( $added ) {
5714 return 'Composite product added to cart successfully.';
5715 } else {
5716 return 'Failed to add composite product to cart.';
5717 }
5718 }
5719
5720
5721
5722 /**
5723 * Checks if a theme is installed.
5724 *
5725 * @param string $theme_slug The slug of the theme to check.
5726 * @return bool True if the theme is installed, false otherwise.
5727 *
5728 * @since 3.3.1
5729 */
5730 public static function maybe_theme_installed( $theme_slug ) {
5731 $theme = wp_get_theme( $theme_slug );
5732 // Check if the theme exists and is not an empty theme
5733 if ( $theme->exists() ) {
5734 return true;
5735 } else {
5736 return false;
5737 }
5738 }
5739
5740
5741 /**
5742 * Validate google autocomplete API key
5743 *
5744 * @param string $api_key
5745 * @return bool
5746 * @since 3.4.8
5747 */
5748 public static function validate_google_places_api_key($api_key) {
5749 if (!is_string($api_key)) {
5750 // Throw an error or handle this case as appropriate for your application
5751 throw new InvalidArgumentException('API key must be a string');
5752 }
5753
5754 $url = 'https://maps.googleapis.com/maps/api/place/textsearch/json?key=' . $api_key;
5755
5756 $response = wp_remote_get($url);
5757
5758 if (is_wp_error($response)) {
5759 return false;
5760 }
5761
5762 $body = wp_remote_retrieve_body($response);
5763 $data = json_decode($body, true);
5764
5765 if (isset($data['status']) && 'REQUEST_DENIED' === $data['status'] ) {
5766 return false;
5767 }
5768
5769 return true;
5770 }
5771
5772
5773 /**
5774 * Get Guided tour
5775 *
5776 * @return false|mixed|null
5777 * @since 3.4.16
5778 */
5779
5780 public static function get_guided_tour() {
5781 $guided_tour_default = apply_filters('wpfnl_guided_tour_default', [
5782 'checkout',
5783 'upsell',
5784 'downsell',
5785 'orderbump',
5786 'condition',
5787 'add-step',
5788 'a/b-testing',
5789 'mm-automation',
5790 'canvas-step',
5791 'view-step',
5792 'edit-step',
5793 ]);
5794 $guided_tour = get_option('wpfnl_guided_tour');
5795 // Check if the option is not found and return the default
5796 if (false === $guided_tour) {
5797 update_option('wpfnl_guided_tour',$guided_tour_default);
5798 return $guided_tour_default;
5799 }
5800 return $guided_tour;
5801 }
5802
5803 /**
5804 * Check if the Global Thank You Page feature is enabled.
5805 *
5806 * This method retrieves the `_wpfunnels_offer_settings` option from the database
5807 * and checks whether the `enable_global_thankyou` setting is set to `'on'`.
5808 *
5809 * @since 3.5.31
5810 *
5811 * @return bool True if the Global Thank You Page is enabled, false otherwise.
5812 */
5813 public static function is_global_thank_you_page_enabled() {
5814 $offer_settings = get_option('_wpfunnels_offer_settings');
5815 if( isset($offer_settings['enable_global_thankyou']) && $offer_settings['enable_global_thankyou'] ){
5816 return 'on' == $offer_settings['enable_global_thankyou'] ? true : false;
5817 }
5818 return false;
5819 }
5820
5821
5822 /**
5823 * Retrieves the product type of an offer.
5824 *
5825 * @param string $step_id The ID of the step.
5826 * @return string The product type of the offer.
5827 */
5828 public static function get_offer_product_type( $step_id = '' ) {
5829
5830 if ( $step_id ) {
5831 $step_type = get_post_meta( $step_id, '_step_type', true );
5832 if ( $step_type == 'upsell' || $step_type == 'downsell' ) {
5833 $offer_product = self::get_offer_product( $step_id, $step_type );
5834 if ( is_array( $offer_product ) ) {
5835 $product_type = '';
5836 foreach ( $offer_product as $pr_index => $pr_data ) {
5837 $product_id = $pr_data['id'];
5838 $product = wc_get_product( $product_id );
5839 if ( $product ) {
5840 $product_type = $product->get_type();
5841 break;
5842 }
5843 }
5844 return $product_type;
5845 }
5846 }
5847 }
5848 return false;
5849 }
5850
5851 /**
5852 * Retrieves the offer product for a given step ID.
5853 *
5854 * @param int $step_id The ID of the funnel step.
5855 * @param string $type The type of offer product (default is 'upsell').
5856 * @param mixed $default The default value to return if no offer product is found.
5857 *
5858 * @return mixed The offer product data or the default value if not found.
5859 *
5860 * @since 1.0.0
5861 */
5862 public static function get_offer_product( $step_id, $type = 'upsell', $default = false ) {
5863 if ( $default ) {
5864 return $default;
5865 }
5866 $value = get_post_meta( $step_id, "_wpfnl_{$type}_products", true );
5867 if ( ! $value ) {
5868 return array();
5869 }
5870 return $value;
5871 }
5872
5873
5874 /**
5875 * Get product data for widget
5876 *
5877 * @param String
5878 *
5879 * @return Array
5880 * @since 1.6.8
5881 */
5882 public static function get_product_data_for_widget( $step_id = '' ) {
5883
5884 if ( $step_id && Wpfnl_functions::is_wc_active() ) {
5885 $funnel_id = get_post_meta( $step_id, '_funnel_id', true );
5886 $step_type = get_post_meta( $step_id, '_step_type', true );
5887 $is_gbf = get_post_meta( $funnel_id, 'is_global_funnel', true );
5888 $offer_product = '';
5889 if ( 'yes' === $is_gbf && ( 'upsell' === $step_type || 'downsell' === $step_type ) ) {
5890 if ( self::is_global_funnel_activated() ) {
5891 $instance = new \WPFunnelsPro\GBF\Wpfnl_Pro_GBF_Functions();
5892 $offer_rules = get_post_meta( $step_id, 'global_funnel_' . $step_type . '_rules', true );
5893 $quantity = isset( $offer_rules['quantity'] ) ? $offer_rules['quantity'] : 1;
5894 $rules_type = isset( $offer_rules['type'] ) ? $offer_rules['type'] : '';
5895 if ( 'moreQuantity' == $rules_type ) {
5896 $rand_product_id = self::get_random_product();
5897 $offer_product = wc_get_product( $rand_product_id );
5898 $get_product_type = $offer_product ? $offer_product->get_type() : '';
5899 $quantity = isset( $gbf_product[0]['quantity'] ) ? $quantity + $gbf_product[0]['quantity'] : $quantity;
5900
5901 } elseif ( 'specificProduct' == $rules_type ) {
5902 $rules = get_post_meta( $step_id, 'global_funnel_' . $step_type . '_rules', true );
5903 $offer_product = '';
5904 if ( is_array( $rules ) ) {
5905 if ( isset( $rules['show'] ) && $rules['show'] ) {
5906 $offer_product = wc_get_product( $rules['show'] );
5907 }
5908 }
5909 $get_product_type = $offer_product ? $offer_product->get_type() : '';
5910
5911 } elseif ( 'randomProduct' == $rules_type ) {
5912 $offer_mappings = get_post_meta( $step_id, 'global_funnel_' . $step_type . '_rules', true );
5913 if ( $offer_mappings ) {
5914 $category = isset( $offer_mappings['category'] ) ? $offer_mappings['category'] : null;
5915 $function_exist = is_callable( array( $instance, 'get_random_product_in_category_for_offer' ) );
5916 if ( $function_exist ) {
5917 $id = '';
5918 if ( is_admin() ) {
5919 $dynamic_product = Wpfnl_Pro_GB_Functions::get_random_product_in_shop_for_widget( 1 );
5920 if ( isset( $dynamic_product[0]->ID ) ) {
5921 $id = $dynamic_product[0]->ID;
5922 }
5923 } else {
5924 $dynamic_product = json_decode( wp_unslash( get_option( 'wpfunnels_dynamic_offer_data' ) ), true );
5925 if ( is_array( $dynamic_product ) && isset( $dynamic_product[0]['ID'] ) ) {
5926 $id = $dynamic_product[0]['ID'];
5927 }
5928 }
5929
5930 if ( $id ) {
5931 $offer_product = wc_get_product( $id );
5932 $get_product_type = $offer_product ? $offer_product->get_type() : '';
5933 }
5934 }
5935 }
5936 } elseif ( 'randomProductInsideCategoryWithinPrice' == $rules_type ) {
5937 $offer_mappings = get_post_meta( $step_id, 'global_funnel_' . $step_type . '_rules', true );
5938 if ( $offer_mappings ) {
5939 $category = isset( $offer_mappings['category'] ) ? $offer_mappings['category'] : null;
5940 $function_exist = is_callable( array( $instance, 'get_random_product_in_category_within_price_for_offer_for_widget' ) );
5941
5942 if ( $function_exist ) {
5943 $id = '';
5944 if ( is_admin() ) {
5945 $dynamic_product = Wpfnl_Pro_GB_Functions::get_random_product_in_category_within_price_for_offer_for_widget( 1 );
5946 if ( isset( $dynamic_product[0]->ID ) ) {
5947 $id = $dynamic_product[0]->ID;
5948 }
5949 } else {
5950 $dynamic_product = json_decode( wp_unslash( get_option( 'wpfunnels_dynamic_offer_data' ) ), true );
5951 if ( is_array( $dynamic_product ) && isset( $dynamic_product[0]['ID'] ) ) {
5952 $id = $dynamic_product[0]['ID'];
5953 }
5954 }
5955
5956 if ( $id ) {
5957 $offer_product = wc_get_product( $id );
5958 $get_product_type = $offer_product ? $offer_product->get_type() : '';
5959 }
5960 }
5961 }
5962 } elseif ( 'highestSoldInsideCategory' == $rules_type ) {
5963 $offer_mappings = get_post_meta( $step_id, 'global_funnel_' . $step_type . '_rules', true );
5964 if ( $offer_mappings ) {
5965 $category = isset( $offer_mappings['category'] ) ? $offer_mappings['category'] : null;
5966 $function_exist = is_callable( array( $instance, 'get_highest_sold_product_in_category_for_offer' ) );
5967 if ( $function_exist ) {
5968 $highestSoldInsideCategory = Wpfnl_Pro_GB_Functions::get_highest_sold_product_in_category_for_offer( 1, $category );
5969 if ( is_array( $highestSoldInsideCategory ) && isset( $highestSoldInsideCategory['posts'][0]->ID ) ) {
5970 $id = $highestSoldInsideCategory['posts'][0]->ID;
5971 $offer_product = wc_get_product( $id );
5972 $get_product_type = $offer_product ? $offer_product->get_type() : '';
5973 }
5974 }
5975 }
5976 } elseif ( 'highestSoldInsideTag' == $rules_type ) {
5977 $offer_mappings = get_post_meta( $step_id, 'global_funnel_' . $step_type . '_rules', true );
5978 if ( $offer_mappings ) {
5979 $tag = isset( $offer_mappings['tag'] ) ? $offer_mappings['tag'] : null;
5980 $function_exist = is_callable( array( $instance, 'get_highest_sold_product_in_tag_for_offer' ) );
5981 if ( $function_exist ) {
5982 $highestSoldInsideTag = Wpfnl_Pro_GB_Functions::get_highest_sold_product_in_tag_for_offer( $tag, 1 );
5983 if ( is_array( $highestSoldInsideTag ) && isset( $highestSoldInsideTag['posts'][0]->ID ) ) {
5984 $id = $highestSoldInsideTag['posts'][0]->ID;
5985 $offer_product = wc_get_product( $id );
5986 $get_product_type = $offer_product ? $offer_product->get_type() : '';
5987 }
5988 }
5989 }
5990 } elseif ( 'highestSold' == $rules_type ) {
5991 $function_exist = is_callable( array( $instance, 'get_highest_sold_product_for_offer' ) );
5992 if ( $function_exist ) {
5993 $highestSold = Wpfnl_Pro_GB_Functions::get_highest_sold_product_for_offer( 1 );
5994 if ( is_array( $highestSold ) && isset( $highestSold['posts'][0]->ID ) ) {
5995 $id = $highestSold['posts'][0]->ID;
5996 $offer_product = wc_get_product( $id );
5997 $get_product_type = $offer_product ? $offer_product->get_type() : '';
5998 }
5999 }
6000 } elseif ( 'randomProductInTag' == $rules_type ) {
6001 $function_exist = is_callable( array( $instance, 'get_random_product_in_tag_for_offer_for_widget' ) );
6002 if ( $function_exist ) {
6003 $id = '';
6004 if ( is_admin() ) {
6005 $dynamic_product = Wpfnl_Pro_GB_Functions::get_random_product_in_tag_for_offer_for_widget( 1 );
6006 if ( isset( $dynamic_product[0]->ID ) ) {
6007 $id = $dynamic_product[0]->ID;
6008 }
6009 } else {
6010 $dynamic_product = json_decode( wp_unslash( get_option( 'wpfunnels_dynamic_offer_data' ) ), true );
6011 if ( is_array( $dynamic_product ) && isset( $dynamic_product[0]['ID'] ) ) {
6012 $id = $dynamic_product[0]['ID'];
6013 }
6014 }
6015 if ( $id ) {
6016 $offer_product = wc_get_product( $id );
6017 $get_product_type = $offer_product ? $offer_product->get_type() : '';
6018 }
6019 }
6020 } elseif ( 'randomProductInsideTagWithinPrice' == $rules_type ) {
6021 $function_exist = is_callable( array( $instance, 'get_random_product_in_tag_within_price_for_offer_for_widget' ) );
6022 if ( $function_exist ) {
6023 $id = '';
6024 if ( is_admin() ) {
6025 $dynamic_product = Wpfnl_Pro_GB_Functions::get_random_product_in_tag_within_price_for_offer_for_widget( 1 );
6026
6027 if ( isset( $dynamic_product[0]->ID ) ) {
6028 $id = $dynamic_product[0]->ID;
6029 }
6030 } else {
6031 $dynamic_product = json_decode( wp_unslash( get_option( 'wpfunnels_dynamic_offer_data' ) ), true );
6032 if ( is_array( $dynamic_product ) && isset( $dynamic_product[0]['ID'] ) ) {
6033 $id = $dynamic_product[0]['ID'];
6034 }
6035 }
6036 if ( $id ) {
6037 $offer_product = wc_get_product( $id );
6038 $get_product_type = $offer_product ? $offer_product->get_type() : '';
6039 }
6040 }
6041 } elseif ( 'randomInShop' == $rules_type ) {
6042 $id = '';
6043 if ( is_admin() ) {
6044 $dynamic_product = Wpfnl_Pro_GB_Functions::get_random_product_in_shop_for_widget( 1 );
6045 if ( isset( $dynamic_product[0]->ID ) ) {
6046 $id = $dynamic_product[0]->ID;
6047 }
6048 } else {
6049 $dynamic_product = json_decode( wp_unslash( get_option( 'wpfunnels_dynamic_offer_data' ) ), true );
6050 if ( is_array( $dynamic_product ) && isset( $dynamic_product[0]['ID'] ) ) {
6051 $id = $dynamic_product[0]['ID'];
6052 }
6053 }
6054 if ( $id ) {
6055 $offer_product = wc_get_product( $id );
6056 $get_product_type = $offer_product ? $offer_product->get_type() : '';
6057 }
6058 }
6059 }
6060 } else {
6061 $offer_product_data = self::get_offer_product( $step_id, $step_type );
6062 $quantity = isset( $offer_product_data['quantity'] ) ? $offer_product_data['quantity'] : 1;
6063 $product = null;
6064 if ( is_array( $offer_product_data ) ) {
6065 foreach ( $offer_product_data as $pr_index => $pr_data ) {
6066 $product_id = $pr_data['id'];
6067 $product = wc_get_product( $product_id );
6068 break;
6069 }
6070 }
6071
6072 $offer_product = $product;
6073 $get_product_type = $offer_product ? $offer_product->get_type() : '';
6074 }
6075
6076 if ( $offer_product && $get_product_type ) {
6077
6078 return array(
6079 'offer_product' => $offer_product,
6080 'get_product_type' => $get_product_type,
6081 'is_gbf' => $is_gbf,
6082 'quantity' => $quantity,
6083 );
6084 }
6085 }
6086
6087 return array(
6088 'offer_product' => '',
6089 'get_product_type' => '',
6090 'is_gbf' => 'no',
6091 'quantity' => 1,
6092 );
6093 }
6094
6095
6096 /**
6097 * Checks if a payment gateway is potentially unsupported.
6098 *
6099 * @return bool
6100 * @since 2.0.5
6101 */
6102 public static function maybe_unsupported_payment_gateway() {
6103
6104 if ( ! Wpfnl_functions::is_wc_active() || ! isset( $_GET['wpfnl-order'] ) ) {
6105 return false;
6106 }
6107
6108 $order_id = ( isset( $_GET['wpfnl-order'] ) ) ? intval( $_GET['wpfnl-order'] ) : 0;
6109 $order = wc_get_order( $order_id );
6110 if ( false === is_a( $order, 'WC_Order' ) ) {
6111 return false;
6112 }
6113 $payment_method = $order->get_payment_method();
6114
6115 if ( $payment_method ) {
6116 // First check if Pro version's factory exists (for backward compatibility)
6117 if ( class_exists( '\WPFunnelsPro\Frontend\Modules\Gateways\Payment_Gateways_Factory' ) ) {
6118 $payment_gateways = \WPFunnelsPro\Frontend\Modules\Gateways\Payment_Gateways_Factory::getInstance()->get_supported_payment_gateways();
6119 }
6120 // Otherwise use the free version's factory
6121 elseif ( class_exists( '\WPFunnels\Gateway\Payment_Gateways_Factory' ) ) {
6122 $payment_gateways = \WPFunnels\Gateway\Payment_Gateways_Factory::getInstance()->get_supported_payment_gateways();
6123 } else {
6124 // If neither exists, assume unsupported
6125 return true;
6126 }
6127
6128 if ( ! isset( $payment_gateways[ $payment_method ] ) ) {
6129 return true;
6130 } else {
6131 return false;
6132 }
6133 }
6134 return true;
6135 }
6136
6137
6138 /**
6139 * Checks if an offer exists in a funnel.
6140 *
6141 * @param int $funnel_id The ID of the funnel to check.
6142 *
6143 * @return bool True if an offer exists, false otherwise.
6144 *
6145 * @since 2.0.5
6146 */
6147 public static function is_offer_exists_in_funnel( $funnel_id ) {
6148 $is_offer_exists = false;
6149 $steps = Wpfnl_functions::get_steps( $funnel_id );
6150 if ( is_array( $steps ) ) {
6151 foreach ( $steps as $index => $step ) {
6152 $step_type = $step['step_type'];
6153 if ( in_array( $step_type, array( 'upsell', 'downsell' ) ) ) {
6154 $is_offer_exists = true;
6155 break;
6156 }
6157 }
6158 }
6159 return $is_offer_exists;
6160 }
6161
6162
6163 /**
6164 * Get upsell/downsell offer product information
6165 *
6166 * @param $step_id
6167 * @param string $selected_product_id
6168 * @param string $input_qty
6169 * @param int $order_id
6170 * @return array
6171 *
6172 * @since 1.0.0
6173 */
6174 public static function get_offer_product_data( $step_id, $selected_product_id = '', $input_qty = '', $order_id = 0 ) {
6175 $funnel_id = get_post_meta( $step_id, '_funnel_id', true );
6176
6177 return apply_filters( 'wpfunnels/offer_product_data', self::get_offer_data( $step_id, $selected_product_id, $input_qty, $order_id = 0 ), $funnel_id, $step_id );
6178 }
6179
6180
6181 /**
6182 * Retrieves offer data based on the provided parameters.
6183 *
6184 * @param int $step_id The ID of the step.
6185 * @param string $selected_product_id The ID of the selected product.
6186 * @param string $input_qty The quantity input.
6187 * @param int $order_id The ID of the order.
6188 *
6189 * @return mixed The offer data.
6190 *
6191 * @since 1.0.0
6192 */
6193 public static function get_offer_data( $step_id, $selected_product_id = '', $input_qty = '', $order_id = 0 ) {
6194 $data = array();
6195 $amount_diff = 0;
6196 $cancel_main_order = false;
6197 $product_id = 0;
6198 $product_qty = 0;
6199
6200 $step_type = get_post_meta( $step_id, '_step_type', true );
6201 $offer_product = get_post_meta( $step_id, '_wpfnl_' . $step_type . '_products', true );
6202 $discount = get_post_meta( $step_id, '_wpfnl_' . $step_type . '_discount', true );
6203 if ( isset( $offer_product[0] ) && ! $selected_product_id ) {
6204 $product_id = $offer_product[0]['id'];
6205 $product_qty = $offer_product[0]['quantity'];
6206 } else {
6207 $product_id = $selected_product_id;
6208 $product_qty = ! empty( $input_qty ) ? intval( $input_qty ) : ( isset( $offer_product[0]['quantity'] ) ? $offer_product[0]['quantity'] : 1 );
6209 }
6210
6211 if ( $product_id ) {
6212
6213 $product = wc_get_product( $product_id );
6214 if ( $product ) {
6215 $main_qty = $product->get_stock_quantity();
6216 if ( $main_qty <= 0 && $product->get_manage_stock() == true ) {
6217 $product_qty = 0;
6218 }
6219 $product_qty = intval( $product_qty );
6220 $order = wc_get_order( $order_id );
6221
6222 $product_type = $product->get_type();
6223 $original_price = $product->get_price( 'edit' );
6224 $custom_price = $original_price;
6225
6226 if ( is_a( $product, 'WC_Product_Bundle' ) ) {
6227 $custom_price = $product->get_bundle_price( 'min' );
6228 }
6229 if ( 'composite' === $product->get_type() ) {
6230 $custom_price = Wpfnl_functions::get_composite_product_price( $product->get_id(), false );
6231 }
6232
6233 $custom_price = apply_filters( 'wpfunnels/modify_offer_product_price_data_without_discount', $custom_price );
6234
6235 if ( is_plugin_active( 'woocommerce-subscriptions/woocommerce-subscriptions.php' ) ) {
6236 if ( 'subscription_variation' === $product->get_type() || 'subscription' === $product->get_type() ) {
6237 $signUpFee = \WC_Subscriptions_Product::get_sign_up_fee( $product );
6238 $custom_price = $custom_price + $signUpFee;
6239 }
6240 }
6241
6242 $unit_price = $custom_price;
6243 $unit_price_tax = $custom_price;
6244 $product_price = floatval( $custom_price ) * intval( $product_qty );
6245
6246 /** tax calculation */
6247 $tax_enabled = get_option( 'woocommerce_calc_taxes' );
6248 $shipping_fee = 0;
6249 $shipping_incl_tax = 0;
6250 $shipping_excl_tax = 0;
6251 $shipping_method_name = 0;
6252 if ( $order ) {
6253 $shipping_fee = $order->get_shipping_total();
6254 $shipping_method_name = $order->get_shipping_method();
6255 }
6256
6257 if ( 'yes' === $tax_enabled ) {
6258 if ( ! wc_prices_include_tax() ) {
6259 $product_price = wc_get_price_including_tax( $product, array( 'price' => $custom_price ) ) * floatval( $product_qty );
6260 $shipping_excl_tax = wc_get_price_including_tax( $product, array( 'price' => $shipping_fee ) );
6261 } else {
6262 $custom_price = wc_get_price_excluding_tax( $product, array( 'price' => $custom_price ) ) * floatval( $product_qty );
6263 $shipping_incl_tax = wc_get_price_excluding_tax( $product, array( 'price' => $shipping_fee ) );
6264 }
6265 $unit_price_tax = $custom_price;
6266 }
6267
6268 $shipping_incl_tax = $shipping_incl_tax ? $shipping_incl_tax : $shipping_fee;
6269 $shipping_excl_tax = $shipping_excl_tax ? $shipping_excl_tax : $shipping_fee;
6270
6271 /** if offer product has discount */
6272 if ( is_array( $discount ) ) {
6273 $discount_instance = new WpfnlDiscount();
6274
6275 if ( ! $discount_instance->maybe_time_bound_discount( $step_id ) || ( $discount_instance->maybe_time_bound_discount( $step_id ) && $discount_instance->maybe_validate_discount_time( $step_id ) ) ) {
6276
6277 $discount_type = $discount['discountType'];
6278 $discount_apply_to = $discount['discountApplyTo'];
6279 $discount_value = $discount['discountValue'];
6280 if ( 'discount-percentage' === $discount_type || 'discount-price' === $discount_type ) {
6281 $regular_price = $product->get_regular_price();
6282 if ( is_plugin_active( 'woocommerce-subscriptions/woocommerce-subscriptions.php' ) ) {
6283 if ( 'subscription_variation' === $product->get_type() || 'subscription' === $product->get_type() ) {
6284 $signUpFee = \WC_Subscriptions_Product::get_sign_up_fee( $product );
6285 $regular_price = $regular_price + $signUpFee;
6286 }
6287 }
6288
6289 $product_price = $discount_apply_to === 'sale' ? $product->get_sale_price() : $regular_price;
6290 $product_price = $product_price ? $product_price : $product->get_price();
6291
6292 if ( is_a( $product, 'WC_Product_Bundle' ) ) {
6293 $custom_price = $discount_apply_to === 'sale' ? $product->get_bundle_price( 'min' ) : $product->get_bundle_regular_price( 'max' );
6294 }
6295 if ( 'composite' === $product->get_type() ) {
6296 $custom_price = Wpfnl_functions::get_composite_product_price( $product->get_id(), false );
6297 }
6298
6299 $product_price = self::calculate_discount_price_for_widget( $discount_type, $discount_value, floatval( $product_price ) * floatval( $product_qty ) );
6300 $product_price = apply_filters( 'wpfunnels/modify_offer_product_price_data_with_discount', $product_price );
6301
6302 $custom_price = $product_price;
6303 $unit_price = $product_price;
6304 $unit_price_tax = $product_price;
6305 }
6306 }
6307 }
6308
6309 $data = array(
6310 'step_id' => $step_id,
6311 'id' => $product_id,
6312 'name' => $product->get_title(),
6313 'desc' => self::get_item_description( $product ),
6314 'qty' => $product_qty,
6315 'original_price' => $original_price,
6316 'regular_price' => $product->get_regular_price(),
6317 'sale_price' => $product->get_sale_price(),
6318 'unit_price' => $unit_price,
6319 'unit_price_tax' => $unit_price_tax,
6320 'args' => array(
6321 'subtotal' => $custom_price,
6322 'total' => $custom_price,
6323 ),
6324 'shipping_fee' => $shipping_excl_tax,
6325 'shipping_fee_incl_tax' => $shipping_incl_tax,
6326 'shipping_method_name' => $shipping_method_name,
6327 'price' => wc_prices_include_tax() ? $custom_price : $product_price,
6328 'url' => $product->get_permalink(),
6329 'total_unit_price_amount' => floatval( preg_replace( '/[^\d.]/', '', $unit_price_tax ) ) * floatval( $product_qty ),
6330 'total' => wc_prices_include_tax() ? $custom_price : $product_price,
6331 'cancel_main_order' => $cancel_main_order,
6332 'amount_diff' => $amount_diff,
6333 'discount' => $discount ? true : false,
6334 'discount_type' => isset( $discount['discountType'] ) ? $discount['discountType'] : '',
6335 'discount_apply_to' => isset( $discount['discountApplyTo'] ) ? $discount['discountApplyTo'] : '',
6336 'discount_value' => isset( $discount['discountValue'] ) ? $discount['discountValue'] : '',
6337 );
6338 }
6339 }
6340 return $data;
6341 }
6342
6343 /**
6344 * Helper method to return the item description, which is composed of item
6345 * meta flattened into a comma-separated string, if available. Otherwise the
6346 * product SKU is included.
6347 *
6348 * The description is automatically truncated to the 127 char limit.
6349 *
6350 * @param array $item cart or order item
6351 * @param \WC_Product $product product data
6352 *
6353 * @return string
6354 * @since 1.0.0
6355 */
6356 public static function get_item_description( $product ) {
6357
6358 if ( is_string( $product ) ) {
6359 $str = $product;
6360 } else {
6361 $str = $product->get_short_description();
6362 }
6363 $item_desc = wp_strip_all_tags( wp_specialchars_decode( wp_staticize_emoji( $str ) ) );
6364 $item_desc = preg_replace( '/[\x00-\x1F\x80-\xFF]/', '', $item_desc );
6365 $item_desc = str_replace( "\n", ', ', rtrim( $item_desc ) );
6366 if ( strlen( $item_desc ) > 127 ) {
6367 $item_desc = substr( $item_desc, 0, 124 ) . '...';
6368 }
6369
6370 return html_entity_decode( $item_desc, ENT_NOQUOTES, 'UTF-8' );
6371 }
6372 }
6373
6374