PluginProbe
CartFlows – Funnel Builder & Checkout Plugin for WooCommerce / 3.3.0
CartFlows – Funnel Builder & Checkout Plugin for WooCommerce v3.3.0
3.3.0 3.2.1 3.2.0 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.1 trunk 1.0.4 1.1.0 1.1.0.1 1.1.1 1.1.10 1.1.11 1.1.12 1.1.13 1.1.14 1.1.15 1.1.16 1.1.17 1.1.18 1.1.19 1.1.2 All 162 releases
← All changes | classes/class-cartflows-frontend.php +948 -328 1.1.1 → 3.3.0 View file →
@@ -1,328 +1,948 @@
1 -<?php
2 -/**
3 - * CartFlows Frontend.
4 - *
5 - * @package CartFlows
6 - */
7 -
8 -/**
9 - * Class Cartflows_Frontend.
10 - */
11 -class Cartflows_Frontend {
12 -
13 - /**
14 - * Member Variable
15 - *
16 - * @var instance
17 - */
18 - private static $instance;
19 -
20 - /**
21 - * Initiator
22 - */
23 - public static function get_instance() {
24 - if ( ! isset( self::$instance ) ) {
25 - self::$instance = new self;
26 - }
27 - return self::$instance;
28 - }
29 -
30 - /**
31 - * Constructor
32 - */
33 - public function __construct() {
34 -
35 - /* Set / Destroy Flow Sessions. Set data */
36 - add_action( 'wp', array( $this, 'init_actions' ), 1 );
37 -
38 - /* Enqueue global required scripts */
39 - add_action( 'wp', array( $this, 'wp_actions' ), 55 );
40 -
41 - /* Modify the checkout order received url to go thank you page in our flow */
42 - add_filter( 'woocommerce_get_checkout_order_received_url', array( $this, 'redirect_to_thankyou_page' ), 10, 2 );
43 - }
44 -
45 - /**
46 - * Redirect to thank page if upsell not exists
47 - *
48 - * @param string $order_recieve_url url.
49 - * @param object $order order object.
50 - * @since 1.0.0
51 - */
52 - function redirect_to_thankyou_page( $order_recieve_url, $order ) {
53 -
54 - /* Only for thank you page */
55 - wcf()->logger->log( 'Start-' . __CLASS__ . '::' . __FUNCTION__ );
56 - wcf()->logger->log( 'Only for thank you page' );
57 -
58 - if ( wcf()->flow->is_thankyou_page_exists( $order ) ) {
59 -
60 - if ( _is_wcf_doing_checkout_ajax() ) {
61 -
62 - $checkout_id = wcf()->utils->get_checkout_id_from_post_data();
63 -
64 - if ( ! $checkout_id ) {
65 - $checkout_id = wcf()->utils->get_checkout_id_from_order( $order->get_id() );
66 - }
67 - } else {
68 - $checkout_id = wcf()->utils->get_checkout_id_from_order( $order->get_id() );
69 - }
70 -
71 - wcf()->logger->log( 'Checkout ID : ' . $checkout_id );
72 -
73 - if ( $checkout_id ) {
74 -
75 - $thankyou_step_id = wcf()->flow->get_thankyou_page_id( $order );
76 -
77 - if ( $thankyou_step_id ) {
78 -
79 - $order_recieve_url = get_permalink( $thankyou_step_id );
80 -
81 - $order_recieve_url = add_query_arg(
82 - array(
83 - 'wcf-order' => $order->get_id(),
84 - 'wcf-key' => $order->get_order_key(),
85 - ),
86 - $order_recieve_url
87 - );
88 - }
89 - }
90 - }
91 -
92 - wcf()->logger->log( 'End-' . __CLASS__ . '::' . __FUNCTION__ );
93 -
94 - return $order_recieve_url;
95 - }
96 -
97 - /**
98 - * Cancel and redirect to checkout
99 - *
100 - * @param string $return_url url.
101 - * @since 1.0.0
102 - */
103 - function redirect_to_checkout_on_cancel( $return_url ) {
104 -
105 - if ( _is_wcf_doing_checkout_ajax() ) {
106 -
107 - $checkout_id = wcf()->utils->get_checkout_id_from_post_data();
108 -
109 - if ( ! $checkout_id ) {
110 - $checkout_id = wcf()->utils->get_checkout_id_from_order( $order->get_id() );
111 - }
112 - } else {
113 - $checkout_id = wcf()->utils->get_checkout_id_from_order( $order->get_id() );
114 - }
115 -
116 - if ( $checkout_id ) {
117 -
118 - $return_url = add_query_arg(
119 - array(
120 - 'cancel_order' => 'true',
121 - '_wpnonce' => wp_create_nonce( 'woocommerce-cancel_order' ),
122 - ),
123 - get_permalink( $checkout_id )
124 - );
125 - }
126 -
127 - return $return_url;
128 - }
129 -
130 -
131 - /**
132 - * Remove theme styles.
133 - *
134 - * @since 1.0.0
135 - */
136 - function remove_theme_styles() {
137 -
138 - // get all styles data.
139 - global $wp_styles;
140 - global $wp_scripts;
141 -
142 - $get_stylesheet = get_stylesheet();
143 - $get_template = get_template();
144 -
145 - if ( Cartflows_Compatibility::get_instance()->is_compatibility_theme_enabled() ) {
146 - return;
147 - }
148 -
149 - $get_stylesheet = 'themes/' . get_stylesheet();
150 - $get_template = 'themes/' . get_template();
151 -
152 - // loop over all of the registered scripts..
153 - foreach ( $wp_styles->registered as $handle => $data ) {
154 -
155 - if ( strpos( $data->src, $get_template ) !== false || strpos( $data->src, $get_stylesheet ) !== false ) {
156 -
157 - // remove it.
158 - wp_deregister_style( $handle );
159 - wp_dequeue_style( $handle );
160 - }
161 - }
162 -
163 - // loop over all of the registered scripts.
164 - foreach ( $wp_scripts->registered as $handle => $data ) {
165 -
166 - if ( strpos( $data->src, $get_template ) !== false || strpos( $data->src, $get_stylesheet ) !== false ) {
167 -
168 - // remove it.
169 - wp_deregister_script( $handle );
170 - wp_dequeue_script( $handle );
171 - }
172 - }
173 - }
174 -
175 - /**
176 - * Update main order data in transient.
177 - *
178 - * @param array $woo_styles new styles array.
179 - * @since 1.0.0
180 - * @return array.
181 - */
182 - function woo_default_css( $woo_styles ) {
183 -
184 - $woo_styles = array(
185 - 'woocommerce-layout' => array(
186 - 'src' => plugins_url( 'assets/css/woocommerce-layout.css', WC_PLUGIN_FILE ),
187 - 'deps' => '',
188 - 'version' => WC_VERSION,
189 - 'media' => 'all',
190 - 'has_rtl' => true,
191 - ),
192 - 'woocommerce-smallscreen' => array(
193 - 'src' => plugins_url( 'assets/css/woocommerce-smallscreen.css', WC_PLUGIN_FILE ),
194 - 'deps' => 'woocommerce-layout',
195 - 'version' => WC_VERSION,
196 - 'media' => 'only screen and (max-width: ' . apply_filters( 'woocommerce_style_smallscreen_breakpoint', '768px' ) . ')',
197 - 'has_rtl' => true,
198 - ),
199 - 'woocommerce-general' => array(
200 - 'src' => plugins_url( 'assets/css/woocommerce.css', WC_PLUGIN_FILE ),
201 - 'deps' => '',
202 - 'version' => WC_VERSION,
203 - 'media' => 'all',
204 - 'has_rtl' => true,
205 - ),
206 - );
207 -
208 - return $woo_styles;
209 - }
210 -
211 - /**
212 - * Init Actions.
213 - *
214 - * @since 1.0.0
215 - */
216 - function init_actions() {
217 -
218 - $this->set_flow_session();
219 - }
220 -
221 - /**
222 - * Set flow session.
223 - *
224 - * @since 1.0.0
225 - */
226 - function set_flow_session() {
227 -
228 - if ( wcf()->utils->is_step_post_type() ) {
229 -
230 - add_action( 'wp_head', array( $this, 'noindex_flow' ) );
231 -
232 - wcf()->utils->do_not_cache();
233 -
234 - /* Set key to support pixel */
235 - if ( isset( $_GET['wcf-key'] ) ) {
236 - $_GET['key'] = $_GET['wcf-key'];
237 - $_REQUEST['key'] = $_GET['wcf-key'];
238 - }
239 -
240 - if ( isset( $_GET['wcf-order'] ) ) {
241 - $_GET['order'] = $_GET['wcf-order'];
242 - $_REQUEST['order'] = $_GET['wcf-order'];
243 - }
244 - }
245 - }
246 -
247 - /**
248 - * Add noindex, nofollow.
249 - *
250 - * @since 1.0.0
251 - */
252 - function noindex_flow() {
253 -
254 - $common = Cartflows_Helper::get_common_settings();
255 -
256 - if ( 'enable' === $common['disallow_indexing'] ) {
257 - echo '<meta name="robots" content="noindex,nofollow">';
258 - }
259 - }
260 -
261 - /**
262 - * WP Actions.
263 - *
264 - * @since 1.0.0
265 - */
266 - function wp_actions() {
267 -
268 - if ( wcf()->utils->is_step_post_type() ) {
269 -
270 - /* CSS Compatibility for All theme */
271 - add_filter( 'woocommerce_enqueue_styles', array( $this, 'woo_default_css' ), 9999 );
272 -
273 - add_action( 'wp_enqueue_scripts', array( $this, 'remove_theme_styles' ), 9999 );
274 -
275 - add_action( 'wp_enqueue_scripts', array( $this, 'global_flow_scripts' ), 20 );
276 - }
277 -
278 - }
279 -
280 - /**
281 - * Global flow scripts.
282 - *
283 - * @since 1.0.0
284 - */
285 - function global_flow_scripts() {
286 -
287 - global $post;
288 -
289 - $flow = get_post_meta( $post->ID, 'wcf-flow-id', true );
290 - $current_step = $post->ID;
291 - $next_step_link = '';
292 - $compatibility = Cartflows_Compatibility::get_instance();
293 -
294 - if ( _is_wcf_landing_type() ) {
295 -
296 - $next_step_id = wcf()->utils->get_next_step_id( $flow, $current_step );
297 - $next_step_link = get_permalink( $next_step_id );
298 - }
299 -
300 - $localize = array(
301 - 'ajax_url' => admin_url( 'admin-ajax.php' ),
302 - 'is_pb_preview' => $compatibility->is_page_builder_preview(),
303 - 'current_theme' => $compatibility->get_current_theme(),
304 - 'current_flow' => $flow,
305 - 'current_step' => $current_step,
306 - 'next_step' => $next_step_link,
307 - );
308 -
309 - wp_localize_script( 'jquery', 'cartflows', apply_filters( 'global_cartflows_js_localize', $localize ) );
310 -
311 - wp_enqueue_style( 'wcf-frontend-global', CARTFLOWS_URL . 'assets/css/frontend.css', array(), CARTFLOWS_VER );
312 - wp_style_add_data( 'wcf-frontend-global', 'rtl', 'replace' );
313 -
314 - wp_enqueue_script(
315 - 'wcf-frontend-global',
316 - CARTFLOWS_URL . 'assets/js/frontend.js',
317 - array( 'jquery' ),
318 - CARTFLOWS_VER,
319 - true
320 - );
321 - }
322 -}
323 -
324 -/**
325 - * Prepare if class 'Cartflows_Frontend' exist.
326 - * Kicking this off by calling 'get_instance()' method
327 - */
328 -Cartflows_Frontend::get_instance();
1 +<?php
2 +/**
3 + * CartFlows Frontend.
4 + *
5 + * @package CartFlows
6 + */
7 +
8 +// Exit if accessed directly.
9 +if ( ! defined( 'ABSPATH' ) ) {
10 + exit;
11 +}
12 +/**
13 + * Class Cartflows_Frontend.
14 + */
15 +class Cartflows_Frontend {
16 +
17 + /**
18 + * Member Variable
19 + *
20 + * @var instance
21 + */
22 + private static $instance;
23 +
24 + /**
25 + * Initiator
26 + */
27 + public static function get_instance() {
28 + if ( ! isset( self::$instance ) ) {
29 + self::$instance = new self();
30 + }
31 + return self::$instance;
32 + }
33 +
34 + /**
35 + * Constructor
36 + */
37 + public function __construct() {
38 +
39 + /* Set / Destroy Flow Sessions. Set data */
40 + add_action( 'wp', array( $this, 'init_actions' ), 1 );
41 +
42 + add_action( 'init', array( $this, 'debug_data_setting_actions' ) );
43 + add_action( 'init', array( $this, 'setup_optin_checkout_filter' ) );
44 + /* Enqueue global required scripts */
45 + add_action( 'wp', array( $this, 'wp_actions' ), 55 );
46 +
47 + /* Modify the checkout order received url to go thank you page in our flow */
48 + add_filter( 'woocommerce_get_checkout_order_received_url', array( $this, 'redirect_to_thankyou_page' ), 10, 2 );
49 + }
50 +
51 + /**
52 + * Redirect to thank page if upsell not exists
53 + *
54 + * @param string $order_receive_url url.
55 + * @param object $order order object.
56 + * @return string $order_receive_url next step URL.
57 + * @since 1.0.0
58 + */
59 + public function redirect_to_thankyou_page( $order_receive_url, $order ) {
60 +
61 + /* Only for thank you page */
62 + wcf()->logger->log( 'Start-' . __CLASS__ . '::' . __FUNCTION__ );
63 + wcf()->logger->log( 'Only for thank you page' );
64 +
65 + if ( wcf()->flow->is_thankyou_page_exists( $order ) ) {
66 +
67 + if ( _is_wcf_doing_checkout_ajax() ) {
68 +
69 + $checkout_id = wcf()->utils->get_checkout_id_from_post_data();
70 +
71 + if ( ! $checkout_id ) {
72 + $checkout_id = wcf()->utils->get_checkout_id_from_order( $order );
73 + }
74 + } else {
75 + $checkout_id = wcf()->utils->get_checkout_id_from_order( $order );
76 + }
77 +
78 + wcf()->logger->log( 'Checkout ID : ' . $checkout_id );
79 +
80 + if ( $checkout_id ) {
81 +
82 + $thankyou_step_id = wcf()->flow->get_thankyou_page_id( $order );
83 + $thankyou_step_id = apply_filters( 'cartflows_checkout_next_step_id', $thankyou_step_id, $order, $checkout_id );
84 +
85 + if ( $thankyou_step_id ) {
86 +
87 + $query_param = wcf()->utils->may_be_append_query_string(
88 + // Default query string args.
89 + array(
90 + 'wcf-key' => $order->get_order_key(),
91 + 'wcf-order' => $order->get_id(),
92 + )
93 + );
94 +
95 + $order_receive_url = add_query_arg(
96 + $query_param,
97 + get_permalink( $thankyou_step_id )
98 + );
99 +
100 + }
101 + }
102 + }
103 +
104 + wcf()->logger->log( 'End-' . __CLASS__ . '::' . __FUNCTION__ );
105 +
106 + return $order_receive_url;
107 + }
108 +
109 + /**
110 + * Cancel and redirect to checkout
111 + *
112 + * @param string $return_url url.
113 + * @since 1.0.0
114 + */
115 + public function redirect_to_checkout_on_cancel( $return_url ) {
116 +
117 + if ( _is_wcf_doing_checkout_ajax() ) {
118 +
119 + $checkout_id = wcf()->utils->get_checkout_id_from_post_data();
120 +
121 + if ( ! $checkout_id ) {
122 + $checkout_id = wcf()->utils->get_checkout_id_from_order( $order );
123 + }
124 + } else {
125 + $checkout_id = wcf()->utils->get_checkout_id_from_order( $order );
126 + }
127 +
128 + if ( $checkout_id ) {
129 +
130 + $return_url = add_query_arg(
131 + array(
132 + 'cancel_order' => 'true',
133 + '_wpnonce' => wp_create_nonce( 'woocommerce-cancel_order' ),
134 + ),
135 + get_permalink( $checkout_id )
136 + );
137 + }
138 +
139 + return $return_url;
140 + }
141 +
142 +
143 + /**
144 + * Remove theme styles.
145 + *
146 + * @since 1.0.0
147 + */
148 + public function remove_theme_styles() {
149 +
150 + if ( Cartflows_Compatibility::get_instance()->is_compatibility_theme_enabled() ) {
151 + return;
152 + }
153 +
154 + $page_template = Cartflows_Helper::get_current_page_template();
155 +
156 + if ( ! _wcf_supported_template( $page_template ) ) {
157 + return;
158 + }
159 +
160 + // get all styles data.
161 + global $wp_styles;
162 + global $wp_scripts;
163 +
164 + $get_stylesheet = 'themes/' . get_stylesheet() . '/';
165 + $get_template = 'themes/' . get_template() . '/';
166 +
167 + $remove_styles = apply_filters( 'cartflows_remove_theme_styles', true );
168 +
169 + if ( $remove_styles ) {
170 +
171 + // loop over all of the registered scripts..
172 + foreach ( $wp_styles->registered as $handle => $data ) {
173 +
174 + if ( ! empty( $data->src ) && ( strpos( $data->src, $get_template ) !== false || strpos( $data->src, $get_stylesheet ) !== false ) ) {
175 +
176 + // remove it.
177 + wp_deregister_style( $handle );
178 + wp_dequeue_style( $handle );
179 + }
180 + }
181 + }
182 +
183 + $remove_scripts = apply_filters( 'cartflows_remove_theme_scripts', true );
184 +
185 + if ( $remove_scripts ) {
186 +
187 + // loop over all of the registered scripts.
188 + foreach ( $wp_scripts->registered as $handle => $data ) {
189 +
190 + if ( ! empty( $data->src ) && ( strpos( $data->src, $get_template ) !== false || strpos( $data->src, $get_stylesheet ) !== false ) ) {
191 +
192 + // remove it.
193 + wp_deregister_script( $handle );
194 + wp_dequeue_script( $handle );
195 + }
196 + }
197 + }
198 + }
199 +
200 + /**
201 + * Update main order data in transient.
202 + *
203 + * @param array $woo_styles new styles array.
204 + * @since 1.0.0
205 + * @return array.
206 + */
207 + public function woo_default_css( $woo_styles ) {
208 +
209 + $woo_styles = array(
210 + 'woocommerce-layout' => array(
211 + 'src' => plugins_url( 'assets/css/woocommerce-layout.css', WC_PLUGIN_FILE ),
212 + 'deps' => '',
213 + 'version' => WC_VERSION,
214 + 'media' => 'all',
215 + 'has_rtl' => true,
216 + ),
217 + 'woocommerce-smallscreen' => array(
218 + 'src' => plugins_url( 'assets/css/woocommerce-smallscreen.css', WC_PLUGIN_FILE ),
219 + 'deps' => 'woocommerce-layout',
220 + 'version' => WC_VERSION,
221 + 'media' => 'only screen and (max-width: ' . apply_filters( 'woocommerce_style_smallscreen_breakpoint', '768px' ) . ')',
222 + 'has_rtl' => true,
223 + ),
224 + 'woocommerce-general' => array(
225 + 'src' => plugins_url( 'assets/css/woocommerce.css', WC_PLUGIN_FILE ),
226 + 'deps' => '',
227 + 'version' => WC_VERSION,
228 + 'media' => 'all',
229 + 'has_rtl' => true,
230 + ),
231 + );
232 +
233 + return $woo_styles;
234 + }
235 +
236 + /**
237 + * Init Actions.
238 + *
239 + * @since 1.0.0
240 + */
241 + public function init_actions() {
242 +
243 + if ( wcf()->utils->is_step_post_type() ) {
244 +
245 + global $post;
246 +
247 + $GLOBALS['wcf_step'] = wcf_get_step( $post->ID );
248 +
249 + do_action( 'cartflows_wp', $post->ID );
250 +
251 + $this->set_flow_session();
252 +
253 + $this->delete_checkout_cookies();
254 + }
255 + }
256 +
257 + /**
258 + * Set flow session.
259 + *
260 + * @since 1.0.0
261 + */
262 + public function set_flow_session() {
263 +
264 + global $wp;
265 +
266 + add_action( 'wp_head', array( $this, 'noindex_flow' ) );
267 +
268 + wcf()->utils->do_not_cache();
269 +
270 + if ( _is_wcf_thankyou_type() ) {
271 + /*
272 + Set key to support pixel
273 + */
274 + //phpcs:disable WordPress.Security.NonceVerification
275 + if ( isset( $_GET['wcf-key'] ) ) {
276 +
277 + $wcf_key = sanitize_text_field( wp_unslash( $_GET['wcf-key'] ) );
278 +
279 + $_GET['key'] = $wcf_key;
280 + $_REQUEST['key'] = $wcf_key;
281 + }
282 +
283 + if ( isset( $_GET['wcf-order'] ) ) {
284 + $wcf_order = intval( wp_unslash( $_GET['wcf-order'] ) );
285 + //phpcs:enable WordPress.Security.NonceVerification
286 +
287 + $_GET['order'] = $wcf_order;
288 + $_REQUEST['order'] = $wcf_order;
289 + $_GET['order-received'] = $wcf_order;
290 + $_REQUEST['order-received'] = $wcf_order;
291 +
292 + $wp->set_query_var( 'order-received', $wcf_order );
293 + }
294 + }
295 + }
296 +
297 + /**
298 + * Delete checkout cookies.
299 + *
300 + * @since 1.0.0
301 + */
302 + public function delete_checkout_cookies() {
303 +
304 + if ( _is_wcf_thankyou_type() ) {
305 +
306 + if ( ! wcf()->is_woo_active || ! isset( WC()->session ) ) {
307 + return;
308 + }
309 +
310 + $user_key = WC()->session->get_customer_id();
311 +
312 + if ( isset( $_COOKIE[ CARTFLOWS_ACTIVE_CHECKOUT ] ) ) {
313 + delete_transient( 'wcf_user_' . $user_key . '_checkout_' . sanitize_text_field( wp_unslash( $_COOKIE[ CARTFLOWS_ACTIVE_CHECKOUT ] ) ) ); //phpcs:ignore WordPressVIPMinimum.Variables.RestrictedVariables.cache_constraints___COOKIE
314 + unset( $_COOKIE[ CARTFLOWS_ACTIVE_CHECKOUT ] ); //phpcs:ignore WordPressVIPMinimum.Variables.RestrictedVariables.cache_constraints___COOKIE
315 + setcookie( CARTFLOWS_ACTIVE_CHECKOUT, '', time() - 3600, '/', COOKIE_DOMAIN, CARTFLOWS_HTTPS, true ); //phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.cookies_setcookie
316 + }
317 + }
318 + }
319 +
320 + /**
321 + * Add noindex, nofollow.
322 + *
323 + * @since 1.0.0
324 + */
325 + public function noindex_flow() {
326 +
327 + $common = Cartflows_Helper::get_common_settings();
328 +
329 + global $post;
330 +
331 + $flow_id = wcf()->utils->get_flow_id_from_step_id( $post->ID );
332 + $flow_indexing = get_post_meta( $flow_id, 'wcf-flow-indexing', true );
333 +
334 + $allow_indexing = ( ( '' === $flow_indexing && 'enable' === $common['disallow_indexing'] ) || 'disallow' === $flow_indexing );
335 +
336 + if ( apply_filters( 'cartflows_step_add_noindex_meta', $allow_indexing, $flow_id ) ) {
337 + echo '<meta name="robots" content="noindex,nofollow">';
338 + }
339 + }
340 +
341 + /**
342 + * WP Actions.
343 + *
344 + * @since 1.0.0
345 + */
346 + public function wp_actions() {
347 +
348 + if ( wcf()->utils->is_step_post_type() ) {
349 +
350 + if ( ! wcf()->is_woo_active && wcf()->utils->check_is_woo_required_page() ) {
351 + wp_die( ' This page requires WooCommerce plugin installed and activated!', 'WooCommerce Required' );
352 + }
353 +
354 + /* CSS Compatibility for All theme */
355 + add_filter( 'woocommerce_enqueue_styles', array( $this, 'woo_default_css' ), 9999 );
356 +
357 + add_action( 'wp_enqueue_scripts', array( $this, 'remove_theme_styles' ), 9999 );
358 + add_action( 'wp_enqueue_scripts', array( $this, 'global_flow_scripts' ), 20 );
359 +
360 + /* Load woo templates from plugin */
361 + add_filter( 'woocommerce_locate_template', array( $this, 'override_woo_template' ), 20, 3 );
362 +
363 + /* Add version class to body in frontend. */
364 + add_filter( 'body_class', array( $this, 'add_cartflows_lite_version_to_body' ) );
365 +
366 + /* Custom Script Option */
367 + add_action( 'wp_head', array( $this, 'custom_script_option' ) );
368 +
369 + /* Remove the action applied by the Flatsome theme */
370 + if ( Cartflows_Compatibility::get_instance()->is_flatsome_enabled() ) {
371 + $this->remove_flatsome_action();
372 + }
373 + }
374 + }
375 +
376 + /**
377 + * Debug Data Setting Actions.
378 + *
379 + * @since 1.1.14
380 + */
381 + public function debug_data_setting_actions() {
382 +
383 + add_filter( 'cartflows_load_min_assets', array( $this, 'allow_load_minify' ) );
384 + }
385 +
386 + /**
387 + * Get/Set the allow minify option.
388 + *
389 + * @since 1.1.14
390 + */
391 + public function allow_load_minify() {
392 + $debug_data = Cartflows_Helper::get_debug_settings();
393 + $allow_minified = $debug_data['allow_minified_files'];
394 + $allow_minify = false;
395 +
396 + if ( 'enable' === $allow_minified ) {
397 + $allow_minify = true;
398 + }
399 +
400 + return $allow_minify;
401 + }
402 +
403 + /**
404 + * Global flow scripts.
405 + *
406 + * @since 1.0.0
407 + */
408 + public function global_flow_scripts() {
409 +
410 + global $post, $wcf_step;
411 +
412 + $flow = $wcf_step->get_flow_id();
413 + $current_step = $wcf_step->get_current_step();
414 + $control_step = $wcf_step->get_control_step();
415 + $next_step_link = '';
416 + $compatibility = Cartflows_Compatibility::get_instance();
417 + $is_checkout = _is_wcf_checkout_type();
418 + $is_optin = _is_wcf_optin_type();
419 +
420 + if ( _is_wcf_landing_type() ) {
421 +
422 + $next_step_id = $wcf_step->get_direct_next_step_id();
423 + $next_step_link = get_permalink( $next_step_id );
424 + }
425 +
426 + $page_template = get_post_meta( $current_step, '_wp_page_template', true );
427 +
428 + $fb_tracking_settings = Cartflows_Helper::get_facebook_settings();
429 + $ga_tracking_settings = Cartflows_Helper::get_google_analytics_settings();
430 + $tik_pixel_settings = Cartflows_Helper::get_tiktok_settings();
431 + $pinterest_settings = Cartflows_Helper::get_pinterest_settings();
432 + $gads_settings = Cartflows_Helper::get_google_ads_settings();
433 + $snapchat_settings = Cartflows_Helper::get_snapchat_settings();
434 +
435 + $localize = array(
436 + 'ajax_url' => admin_url( 'admin-ajax.php', 'relative' ),
437 + 'is_pb_preview' => $compatibility->is_page_builder_preview(),
438 + 'current_theme' => $compatibility->get_current_theme(),
439 + 'current_flow' => $flow,
440 + 'current_step' => $current_step,
441 + 'control_step' => $control_step,
442 + 'next_step' => $next_step_link,
443 + 'page_template' => $page_template,
444 + 'default_page_builder' => \Cartflows_Helper::get_common_setting( 'default_page_builder' ),
445 + 'is_checkout_page' => $is_checkout,
446 + 'fb_setting' => $fb_tracking_settings,
447 + 'ga_setting' => $ga_tracking_settings,
448 + 'tik_setting' => $tik_pixel_settings,
449 + 'pin_settings' => $pinterest_settings,
450 + 'gads_setting' => $gads_settings,
451 + 'snap_settings' => $snapchat_settings,
452 + 'active_checkout_cookie' => CARTFLOWS_ACTIVE_CHECKOUT,
453 + 'is_optin' => $is_optin,
454 + );
455 +
456 + if ( $is_checkout ) {
457 + $localize['ajax_url'] = add_query_arg(
458 + array(
459 + 'wcf_checkout_id' => $current_step,
460 + ),
461 + $localize['ajax_url']
462 + );
463 + }
464 +
465 + $localize = apply_filters( 'global_cartflows_js_localize', $localize );
466 +
467 + $localize_script = '<!-- script to print the admin localized variables -->';
468 + $localize_script .= '<script type="text/javascript">';
469 + $localize_script .= 'var cartflows = ' . wp_json_encode( $localize ) . ';';
470 + $localize_script .= '</script>';
471 +
472 + echo $localize_script; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
473 +
474 + if ( _wcf_supported_template( $page_template ) ) {
475 + $page_builder = Cartflows_Helper::get_common_setting( 'default_page_builder' );
476 + if ( ! ( 'bricks-builder' === $page_builder && function_exists( 'bricks_is_builder' ) && bricks_is_builder() ) ) {
477 + wp_enqueue_style( 'wcf-normalize-frontend-global', wcf()->utils->get_css_url( 'cartflows-normalize' ), array(), CARTFLOWS_VER );
478 + }
479 + }
480 +
481 + if ( ! wcf()->is_woo_active ) {
482 + wp_register_script(
483 + 'jquery-cookie',
484 + CARTFLOWS_URL . 'assets/js/lib/jquery-cookie/jquery.cookie.min.js',
485 + array( 'jquery' ),
486 + CARTFLOWS_VER,
487 + false
488 + );
489 + }
490 +
491 + wp_enqueue_style( 'wcf-frontend-global', wcf()->utils->get_css_url( 'frontend' ), array(), CARTFLOWS_VER );
492 +
493 + wp_enqueue_script(
494 + 'wcf-frontend-global',
495 + wcf()->utils->get_js_url( 'frontend' ),
496 + array( 'jquery', 'jquery-cookie' ),
497 + CARTFLOWS_VER,
498 + false
499 + );
500 + }
501 +
502 + /**
503 + * Custom Script in head.
504 + *
505 + * @since 1.0.0
506 + */
507 + public function custom_script_option() {
508 +
509 + // Check if migration to separate JS/CSS fields is completed.
510 + $migration_completed = 'completed' === Cartflows_Helper::get_script_migration_status();
511 +
512 + $global_css = trim( $this->get_global_custom_css() );
513 + $global_js = trim( $this->get_global_custom_js() );
514 + $flow_css = '';
515 + $flow_js = '';
516 + $step_css = '';
517 + $step_js = '';
518 +
519 + // Old combined script values (used only if migration not completed).
520 + $script = '';
521 + $flow_script = '';
522 +
523 + if ( $migration_completed ) {
524 + // Migration completed: load from new separate JS and CSS meta keys.
525 + $flow_css = trim( $this->get_flow_custom_css() );
526 + $flow_js = trim( $this->get_flow_custom_js() );
527 + $step_css = trim( $this->get_step_custom_css() );
528 + $step_js = trim( $this->get_step_custom_js() );
529 + } else {
530 + // Migration not completed: load from old combined script meta keys.
531 + $script = $this->get_custom_script();
532 + $flow_script = $this->get_flow_custom_script();
533 + }
534 +
535 + // -------------------------
536 + // CSS Output (Global → Flow → Step)
537 + // Step CSS takes priority due to later output.
538 + // -------------------------
539 + if ( '' !== $global_css || '' !== $flow_css || '' !== $step_css ) {
540 + echo '<!-- CartFlows Custom CSS -->';
541 + echo '<style>';
542 +
543 + if ( '' !== $global_css ) {
544 + // Global CSS is already pure CSS from settings.
545 + echo html_entity_decode( $global_css ) . PHP_EOL; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
546 + }
547 +
548 + if ( '' !== $flow_css ) {
549 + // New format: pure CSS. Old format: strip style tags.
550 + $flow_css_output = $migration_completed ? $flow_css : $this->strip_script_style_tags( $flow_css );
551 + echo html_entity_decode( $flow_css_output ) . PHP_EOL; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
552 + }
553 +
554 + if ( '' !== $step_css ) {
555 + // New format: pure CSS. Old format: strip style tags.
556 + $step_css_output = $migration_completed ? $step_css : $this->strip_script_style_tags( $step_css );
557 + echo html_entity_decode( $step_css_output ) . PHP_EOL; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
558 + }
559 +
560 + echo '</style>';
561 + echo '<!-- End CartFlows Custom CSS -->';
562 + echo PHP_EOL;
563 + }
564 +
565 + // -------------------------
566 + // JS Output (Global → Flow → Step)
567 + // Step JS takes priority due to later execution.
568 + // -------------------------
569 + echo '<!-- CartFlows Custom JS -->';
570 + echo '<script>';
571 +
572 + // Global JS.
573 + if ( '' !== $global_js ) {
574 + echo str_replace( '</script>', '<\/script>', html_entity_decode( $global_js ) ) . PHP_EOL; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
575 + }
576 +
577 + // Flow JS (new or old format).
578 + if ( $migration_completed && '' !== $flow_js ) {
579 + // New format: already pure JS, just escape closing tags.
580 + echo str_replace( '</script>', '<\/script>', html_entity_decode( $flow_js ) ) . PHP_EOL; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
581 + } elseif ( ! $migration_completed && '' !== $flow_script ) {
582 + // Old format: strip any existing script/style tags and output raw JS.
583 + $flow_script_output = $this->strip_script_style_tags( $flow_script );
584 + echo str_replace( '</script>', '<\/script>', html_entity_decode( $flow_script_output ) ) . PHP_EOL; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
585 + }
586 +
587 + // Step JS (new or old format).
588 + if ( $migration_completed && '' !== $step_js ) {
589 + // New format: already pure JS, just escape closing tags.
590 + echo str_replace( '</script>', '<\/script>', html_entity_decode( $step_js ) ) . PHP_EOL; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
591 + } elseif ( ! $migration_completed && '' !== $script ) {
592 + // Old format: strip any existing script/style tags and output raw JS.
593 + $step_script_output = $this->strip_script_style_tags( $script );
594 + echo str_replace( '</script>', '<\/script>', html_entity_decode( $step_script_output ) ) . PHP_EOL; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
595 + }
596 +
597 + echo '</script>';
598 + echo '<!-- End CartFlows Custom JS -->';
599 + echo PHP_EOL;
600 + }
601 +
602 + /**
603 + * Strip <script> and <style> tags from content, returning only the inner content.
604 + *
605 + * @since 2.2.3
606 + * @param string $content Content to strip tags from.
607 + * @return string Content with script/style tags removed.
608 + */
609 + private function strip_script_style_tags( $content ) {
610 + // Remove <script>...</script> tags but keep inner content.
611 + $content = preg_replace( '/<script[^>]*>(.*?)<\/script>/is', '$1', $content );
612 + // Remove <style>...</style> tags but keep inner content.
613 + $content = preg_replace( '/<style[^>]*>(.*?)<\/style>/is', '$1', $content );
614 + return trim( $content );
615 + }
616 +
617 + /**
618 + * Override woo templates.
619 + *
620 + * @param string $template new Template full path.
621 + * @param string $template_name Template name.
622 + * @param string $template_path Template Path.
623 + * @since 1.1.5
624 + * @return string.
625 + */
626 + public function override_woo_template( $template, $template_name, $template_path ) {
627 +
628 + global $woocommerce;
629 +
630 + $_template = $template;
631 +
632 + $plugin_path = CARTFLOWS_DIR . 'woocommerce/template/';
633 +
634 + if ( file_exists( $plugin_path . $template_name ) ) {
635 + $template = $plugin_path . $template_name;
636 + }
637 +
638 + if ( ! $template ) {
639 + $template = $_template;
640 + }
641 +
642 + return $template;
643 + }
644 +
645 + /**
646 + * Remove the action applied by the Flatsome theme.
647 + *
648 + * @since 1.1.5
649 + * @return void.
650 + */
651 + public function remove_flatsome_action() {
652 +
653 + // Remove action where flatsome dequeued the woocommerce's default styles.
654 + remove_action( 'wp_enqueue_scripts', 'flatsome_woocommerce_scripts_styles', 98 );
655 + }
656 +
657 + /**
658 + * Add version class to body in frontend.
659 + *
660 + * @since 1.1.5
661 + * @param array $classes classes.
662 + * @return array $classes classes.
663 + */
664 + public function add_cartflows_lite_version_to_body( $classes ) {
665 +
666 + $classes[] = 'cartflows-' . CARTFLOWS_VER;
667 +
668 + return $classes;
669 + }
670 +
671 + /**
672 + * Get custom script data.
673 + *
674 + * @since 1.0.0
675 + */
676 + public function get_custom_script() {
677 +
678 + global $post;
679 +
680 + $script = get_post_meta( $post->ID, 'wcf-custom-script', true );
681 +
682 + $script = $this->maybe_replace_vars( $script );
683 +
684 + return $script;
685 + }
686 +
687 + /**
688 + * Replace the dynamic vars in the custom script.
689 + *
690 + }
691 +
692 + /**
693 + * Get custom script data.
694 + *
695 + * @since 1.0.0
696 + */
697 + public function get_flow_custom_script() {
698 +
699 + global $post;
700 +
701 + $step_id = $post->ID;
702 +
703 + $flow_id = wcf()->utils->get_flow_id_from_step_id( $step_id );
704 +
705 + $script = get_post_meta( $flow_id, 'wcf-flow-custom-script', true );
706 +
707 + $script = $this->maybe_replace_vars( $script );
708 +
709 + return $script;
710 + }
711 +
712 + /**
713 + * Get custom JS script for steps.
714 + *
715 + * @since 2.2.2
716 + */
717 + public function get_step_custom_js() {
718 +
719 + global $post;
720 +
721 + $script = get_post_meta( $post->ID, 'wcf-step-custom-js', true );
722 +
723 + $script = $this->maybe_replace_vars( $script );
724 +
725 + return $script;
726 + }
727 +
728 + /**
729 + * Get custom CSS script for steps.
730 + *
731 + * @since 2.2.2
732 + */
733 + public function get_step_custom_css() {
734 +
735 + global $post;
736 +
737 + $style = get_post_meta( $post->ID, 'wcf-step-custom-css', true );
738 +
739 + return is_string( $style ) ? $style : '';
740 + }
741 +
742 + /**
743 + * Replace the dynamic vars in the custom script.
744 + *
745 + * @param string $script custom script.
746 + * @return string $script modified custom script.
747 + *
748 + * @since 1.10.0
749 + */
750 + public function maybe_replace_vars( $script ) {
751 + //phpcs:disable WordPress.Security.NonceVerification
752 + if ( isset( $_GET['wcf-order'] ) && isset( $_GET['wcf-key'] ) ) {
753 +
754 + $order_id = intval( wp_unslash( $_GET['wcf-order'] ) );
755 + $order_key = wc_clean( wp_unslash( $_GET['wcf-key'] ) );
756 + //phpcs:enable WordPress.Security.NonceVerification
757 + $order = wc_get_order( $order_id );
758 +
759 + if ( $order && $order_key === $order->get_order_key() ) {
760 +
761 + // These variables will be available to use on Upsell, Downsell, Thank you pages of CartFlows only.
762 + $script = str_replace( '{{order_id}}', $order_id, $script );
763 + $script = str_replace( '{{txn_id}}', $order->get_transaction_id(), $script );
764 + $script = str_replace( '{{order_total}}', $order->get_total(), $script );
765 +
766 + $script = apply_filters( 'cartflows_dynamic_js_vars', $script );
767 + }
768 + }
769 +
770 + return $script;
771 + }
772 +
773 + /**
774 + * Get global custom CSS from settings.
775 + *
776 + * @since 2.2.2
777 + * @return string
778 + */
779 + public function get_global_custom_css() {
780 +
781 + $global_scripts = get_option( '_cartflows_global_scripts', array() );
782 +
783 + if ( ! is_array( $global_scripts ) || empty( $global_scripts['global_css'] ) ) {
784 + return '';
785 + }
786 +
787 + return (string) $global_scripts['global_css'];
788 + }
789 +
790 + /**
791 + * Get global custom JS from settings.
792 + *
793 + * @since 2.2.2
794 + * @return string
795 + */
796 + public function get_global_custom_js() {
797 +
798 + $global_scripts = get_option( '_cartflows_global_scripts', array() );
799 +
800 + if ( ! is_array( $global_scripts ) || empty( $global_scripts['global_js'] ) ) {
801 + return '';
802 + }
803 +
804 + return (string) $global_scripts['global_js'];
805 + }
806 +
807 + /**
808 + * Get custom JS script for flow.
809 + *
810 + * @since 2.2.2
811 + * @return string
812 + */
813 + public function get_flow_custom_js() {
814 +
815 + global $post;
816 +
817 + $step_id = $post->ID;
818 +
819 + $flow_id = wcf()->utils->get_flow_id_from_step_id( $step_id );
820 +
821 + $script = get_post_meta( $flow_id, 'wcf-flow-custom-js', true );
822 +
823 + $script = $this->maybe_replace_vars( $script );
824 +
825 + return $script;
826 + }
827 +
828 + /**
829 + * Get custom CSS script for flow.
830 + *
831 + * @since 2.2.2
832 + * @return string
833 + */
834 + public function get_flow_custom_css() {
835 +
836 + global $post;
837 +
838 + $step_id = $post->ID;
839 +
840 + $flow_id = wcf()->utils->get_flow_id_from_step_id( $step_id );
841 +
842 + $style = get_post_meta( $flow_id, 'wcf-flow-custom-css', true );
843 +
844 + return is_string( $style ) ? $style : '';
845 + }
846 +
847 + /**
848 + * Set appropriate filter sctions.
849 + *
850 + * @since 1.1.14
851 + */
852 + public function setup_optin_checkout_filter() {
853 +
854 + if ( _is_wcf_doing_optin_ajax() ) {
855 + /* Modify the optin order received url to go next step */
856 + remove_filter( 'woocommerce_get_checkout_order_received_url', array( $this, 'redirect_to_thankyou_page' ), 10, 2 );
857 + add_filter( 'woocommerce_get_checkout_order_received_url', array( $this, 'redirect_optin_to_next_step' ), 10, 2 );
858 + }
859 + }
860 +
861 + /**
862 + * Redirect to thank page if upsell not exists
863 + *
864 + * @param string $order_receive_url url.
865 + * @param object $order order object.
866 + * @return string $order_receive_url next step URL.
867 + * @since 1.0.0
868 + */
869 + public function redirect_optin_to_next_step( $order_receive_url, $order ) {
870 +
871 + /* Only for optin page */
872 + wcf()->logger->log( 'Start-' . __CLASS__ . '::' . __FUNCTION__ );
873 + wcf()->logger->log( 'Only for optin page' );
874 +
875 + if ( _is_wcf_doing_optin_ajax() ) {
876 +
877 + $optin_id = wcf()->utils->get_optin_id_from_post_data();
878 +
879 + if ( ! $optin_id ) {
880 + $optin_id = wcf()->utils->get_optin_id_from_order( $order );
881 + }
882 + } else {
883 + $optin_id = wcf()->utils->get_optin_id_from_order( $order );
884 + }
885 +
886 + wcf()->logger->log( 'Optin ID : ' . $optin_id );
887 +
888 + if ( $optin_id ) {
889 +
890 + $wcf_step_obj = wcf_get_step( $optin_id );
891 + $next_step_id = $wcf_step_obj->get_direct_next_step_id();
892 +
893 + if ( $next_step_id ) {
894 +
895 + $order_receive_url = get_permalink( $next_step_id );
896 + $query_param = array(
897 + 'wcf-key' => $order->get_order_key(),
898 + 'wcf-order' => $order->get_id(),
899 + );
900 +
901 + if ( 'yes' === wcf()->options->get_optin_meta_value( $optin_id, 'wcf-optin-pass-fields' ) ) {
902 +
903 + $fields_string = wcf()->options->get_optin_meta_value( $optin_id, 'wcf-optin-pass-specific-fields' );
904 +
905 + $fields = array_map( 'trim', explode( ',', $fields_string ) );
906 +
907 + if ( is_array( $fields ) ) {
908 +
909 + foreach ( $fields as $in => $key ) {
910 + switch ( $key ) {
911 + case 'first_name':
912 + $query_param[ $key ] = $order->get_billing_first_name();
913 + break;
914 + case 'last_name':
915 + $query_param[ $key ] = $order->get_billing_last_name();
916 + break;
917 + case 'email':
918 + $query_param[ $key ] = $order->get_billing_email();
919 + break;
920 + default:
921 + $query_param[ $key ] = $order->get_meta( '_billing_' . $key, true );
922 + break;
923 + }
924 + }
925 + }
926 + }
927 +
928 + // Add any existing URL parameters at the end of the URL before redirecting.
929 + $query_param = wcf()->utils->may_be_append_query_string( $query_param );
930 +
931 + $order_receive_url = add_query_arg(
932 + $query_param,
933 + $order_receive_url
934 + );
935 + }
936 + }
937 +
938 + wcf()->logger->log( 'End-' . __CLASS__ . '::' . __FUNCTION__ );
939 +
940 + return $order_receive_url;
941 + }
942 +}
943 +
944 +/**
945 + * Prepare if class 'Cartflows_Frontend' exist.
946 + * Kicking this off by calling 'get_instance()' method
947 + */
948 +Cartflows_Frontend::get_instance();