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

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