PluginProbe
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell / 3.12.6
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell v3.12.6
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.12.6, at includes/utils/class-wpfnl-functions.php

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