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 +577 -68 1.1.11 → 3.3.0 View file →
@@ -4,8 +4,12 @@
4 4 *
5 5 * @package CartFlows
6 6 */
7 7
8 +// Exit if accessed directly.
9 +if ( ! defined( 'ABSPATH' ) ) {
10 + exit;
11 +}
8 12 /**
9 13 * Class Cartflows_Frontend.
10 14 */
11 15 class Cartflows_Frontend {
@@ -21,9 +25,9 @@
21 25 * Initiator
22 26 */
23 27 public static function get_instance() {
24 28 if ( ! isset( self::$instance ) ) {
25 - self::$instance = new self;
29 + self::$instance = new self();
26 30 }
27 31 return self::$instance;
28 32 }
29 33
@@ -34,24 +38,26 @@
34 38
35 39 /* Set / Destroy Flow Sessions. Set data */
36 40 add_action( 'wp', array( $this, 'init_actions' ), 1 );
37 41
42 + add_action( 'init', array( $this, 'debug_data_setting_actions' ) );
43 + add_action( 'init', array( $this, 'setup_optin_checkout_filter' ) );
38 44 /* Enqueue global required scripts */
39 45 add_action( 'wp', array( $this, 'wp_actions' ), 55 );
40 46
41 47 /* Modify the checkout order received url to go thank you page in our flow */
42 48 add_filter( 'woocommerce_get_checkout_order_received_url', array( $this, 'redirect_to_thankyou_page' ), 10, 2 );
43 -
44 49 }
45 50
46 51 /**
47 52 * Redirect to thank page if upsell not exists
48 53 *
49 - * @param string $order_recieve_url url.
54 + * @param string $order_receive_url url.
50 55 * @param object $order order object.
56 + * @return string $order_receive_url next step URL.
51 57 * @since 1.0.0
52 58 */
53 - function redirect_to_thankyou_page( $order_recieve_url, $order ) {
59 + public function redirect_to_thankyou_page( $order_receive_url, $order ) {
54 60
55 61 /* Only for thank you page */
56 62 wcf()->logger->log( 'Start-' . __CLASS__ . '::' . __FUNCTION__ );
57 63 wcf()->logger->log( 'Only for thank you page' );
@@ -62,12 +68,12 @@
62 68
63 69 $checkout_id = wcf()->utils->get_checkout_id_from_post_data();
64 70
65 71 if ( ! $checkout_id ) {
66 - $checkout_id = wcf()->utils->get_checkout_id_from_order( $order->get_id() );
72 + $checkout_id = wcf()->utils->get_checkout_id_from_order( $order );
67 73 }
68 74 } else {
69 - $checkout_id = wcf()->utils->get_checkout_id_from_order( $order->get_id() );
75 + $checkout_id = wcf()->utils->get_checkout_id_from_order( $order );
70 76 }
71 77
72 78 wcf()->logger->log( 'Checkout ID : ' . $checkout_id );
73 79
@@ -73,20 +79,25 @@
73 79
74 80 if ( $checkout_id ) {
75 81
76 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 );
77 84
78 85 if ( $thankyou_step_id ) {
79 86
80 - $order_recieve_url = get_permalink( $thankyou_step_id );
81 -
82 - $order_recieve_url = add_query_arg(
87 + $query_param = wcf()->utils->may_be_append_query_string(
88 + // Default query string args.
83 89 array(
90 + 'wcf-key' => $order->get_order_key(),
84 91 'wcf-order' => $order->get_id(),
85 - 'wcf-key' => $order->get_order_key(),
86 - ),
87 - $order_recieve_url
92 + )
88 93 );
94 +
95 + $order_receive_url = add_query_arg(
96 + $query_param,
97 + get_permalink( $thankyou_step_id )
98 + );
99 +
89 100 }
90 101 }
91 102 }
92 103
@@ -91,9 +102,9 @@
91 102 }
92 103
93 104 wcf()->logger->log( 'End-' . __CLASS__ . '::' . __FUNCTION__ );
94 105
95 - return $order_recieve_url;
106 + return $order_receive_url;
96 107 }
97 108
98 109 /**
99 110 * Cancel and redirect to checkout
@@ -100,9 +111,9 @@
100 111 *
101 112 * @param string $return_url url.
102 113 * @since 1.0.0
103 114 */
104 - function redirect_to_checkout_on_cancel( $return_url ) {
115 + public function redirect_to_checkout_on_cancel( $return_url ) {
105 116
106 117 if ( _is_wcf_doing_checkout_ajax() ) {
107 118
108 119 $checkout_id = wcf()->utils->get_checkout_id_from_post_data();
@@ -107,12 +118,12 @@
107 118
108 119 $checkout_id = wcf()->utils->get_checkout_id_from_post_data();
109 120
110 121 if ( ! $checkout_id ) {
111 - $checkout_id = wcf()->utils->get_checkout_id_from_order( $order->get_id() );
122 + $checkout_id = wcf()->utils->get_checkout_id_from_order( $order );
112 123 }
113 124 } else {
114 - $checkout_id = wcf()->utils->get_checkout_id_from_order( $order->get_id() );
125 + $checkout_id = wcf()->utils->get_checkout_id_from_order( $order );
115 126 }
116 127
117 128 if ( $checkout_id ) {
118 129
@@ -133,14 +144,20 @@
133 144 * Remove theme styles.
134 145 *
135 146 * @since 1.0.0
136 147 */
137 - function remove_theme_styles() {
148 + public function remove_theme_styles() {
138 149
139 150 if ( Cartflows_Compatibility::get_instance()->is_compatibility_theme_enabled() ) {
140 151 return;
141 152 }
142 153
154 + $page_template = Cartflows_Helper::get_current_page_template();
155 +
156 + if ( ! _wcf_supported_template( $page_template ) ) {
157 + return;
158 + }
159 +
143 160 // get all styles data.
144 161 global $wp_styles;
145 162 global $wp_scripts;
146 163
@@ -153,9 +170,9 @@
153 170
154 171 // loop over all of the registered scripts..
155 172 foreach ( $wp_styles->registered as $handle => $data ) {
156 173
157 - if ( strpos( $data->src, $get_template ) !== false || strpos( $data->src, $get_stylesheet ) !== false ) {
174 + if ( ! empty( $data->src ) && ( strpos( $data->src, $get_template ) !== false || strpos( $data->src, $get_stylesheet ) !== false ) ) {
158 175
159 176 // remove it.
160 177 wp_deregister_style( $handle );
161 178 wp_dequeue_style( $handle );
@@ -169,9 +186,9 @@
169 186
170 187 // loop over all of the registered scripts.
171 188 foreach ( $wp_scripts->registered as $handle => $data ) {
172 189
173 - if ( strpos( $data->src, $get_template ) !== false || strpos( $data->src, $get_stylesheet ) !== false ) {
190 + if ( ! empty( $data->src ) && ( strpos( $data->src, $get_template ) !== false || strpos( $data->src, $get_stylesheet ) !== false ) ) {
174 191
175 192 // remove it.
176 193 wp_deregister_script( $handle );
177 194 wp_dequeue_script( $handle );
@@ -177,9 +194,8 @@
177 194 wp_dequeue_script( $handle );
178 195 }
179 196 }
180 197 }
181 -
182 198 }
183 199
184 200 /**
185 201 * Update main order data in transient.
@@ -187,9 +203,9 @@
187 203 * @param array $woo_styles new styles array.
188 204 * @since 1.0.0
189 205 * @return array.
190 206 */
191 - function woo_default_css( $woo_styles ) {
207 + public function woo_default_css( $woo_styles ) {
192 208
193 209 $woo_styles = array(
194 210 'woocommerce-layout' => array(
195 211 'src' => plugins_url( 'assets/css/woocommerce-layout.css', WC_PLUGIN_FILE ),
@@ -221,11 +237,22 @@
221 237 * Init Actions.
222 238 *
223 239 * @since 1.0.0
224 240 */
225 - function init_actions() {
241 + public function init_actions() {
226 242
227 - $this->set_flow_session();
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 + }
228 255 }
229 256
230 257 /**
231 258 * Set flow session.
@@ -231,41 +258,83 @@
231 258 * Set flow session.
232 259 *
233 260 * @since 1.0.0
234 261 */
235 - function set_flow_session() {
262 + public function set_flow_session() {
236 263
237 - if ( wcf()->utils->is_step_post_type() ) {
264 + global $wp;
238 265
239 - add_action( 'wp_head', array( $this, 'noindex_flow' ) );
266 + add_action( 'wp_head', array( $this, 'noindex_flow' ) );
240 267
241 - wcf()->utils->do_not_cache();
268 + wcf()->utils->do_not_cache();
242 269
243 - /* Set key to support pixel */
270 + if ( _is_wcf_thankyou_type() ) {
271 + /*
272 + Set key to support pixel
273 + */
274 + //phpcs:disable WordPress.Security.NonceVerification
244 275 if ( isset( $_GET['wcf-key'] ) ) {
245 - $_GET['key'] = $_GET['wcf-key'];
246 - $_REQUEST['key'] = $_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;
247 281 }
248 282
249 283 if ( isset( $_GET['wcf-order'] ) ) {
250 - $_GET['order'] = $_GET['wcf-order'];
251 - $_REQUEST['order'] = $_GET['wcf-order'];
252 - $_GET['order-received'] = $_GET['wcf-order'];
253 - $_REQUEST['order-received'] = $_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 );
254 293 }
255 294 }
256 295 }
257 296
258 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 + /**
259 321 * Add noindex, nofollow.
260 322 *
261 323 * @since 1.0.0
262 324 */
263 - function noindex_flow() {
325 + public function noindex_flow() {
264 326
265 327 $common = Cartflows_Helper::get_common_settings();
266 328
267 - if ( 'enable' === $common['disallow_indexing'] ) {
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 ) ) {
268 337 echo '<meta name="robots" content="noindex,nofollow">';
269 338 }
270 339 }
271 340
@@ -273,12 +342,16 @@
273 342 * WP Actions.
274 343 *
275 344 * @since 1.0.0
276 345 */
277 - function wp_actions() {
346 + public function wp_actions() {
278 347
279 348 if ( wcf()->utils->is_step_post_type() ) {
280 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 +
281 354 /* CSS Compatibility for All theme */
282 355 add_filter( 'woocommerce_enqueue_styles', array( $this, 'woo_default_css' ), 9999 );
283 356
284 357 add_action( 'wp_enqueue_scripts', array( $this, 'remove_theme_styles' ), 9999 );
@@ -300,47 +373,130 @@
300 373 }
301 374 }
302 375
303 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 + /**
304 404 * Global flow scripts.
305 405 *
306 406 * @since 1.0.0
307 407 */
308 - function global_flow_scripts() {
408 + public function global_flow_scripts() {
309 409
310 - global $post;
410 + global $post, $wcf_step;
311 411
312 - $flow = get_post_meta( $post->ID, 'wcf-flow-id', true );
313 - $current_step = $post->ID;
412 + $flow = $wcf_step->get_flow_id();
413 + $current_step = $wcf_step->get_current_step();
414 + $control_step = $wcf_step->get_control_step();
314 415 $next_step_link = '';
315 416 $compatibility = Cartflows_Compatibility::get_instance();
417 + $is_checkout = _is_wcf_checkout_type();
418 + $is_optin = _is_wcf_optin_type();
316 419
317 420 if ( _is_wcf_landing_type() ) {
318 421
319 - $next_step_id = wcf()->utils->get_next_step_id( $flow, $current_step );
422 + $next_step_id = $wcf_step->get_direct_next_step_id();
320 423 $next_step_link = get_permalink( $next_step_id );
321 424 }
322 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 +
323 435 $localize = array(
324 - 'ajax_url' => admin_url( 'admin-ajax.php' ),
325 - 'is_pb_preview' => $compatibility->is_page_builder_preview(),
326 - 'current_theme' => $compatibility->get_current_theme(),
327 - 'current_flow' => $flow,
328 - 'current_step' => $current_step,
329 - 'next_step' => $next_step_link,
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,
330 454 );
331 455
332 - wp_localize_script( 'jquery', 'cartflows', apply_filters( 'global_cartflows_js_localize', $localize ) );
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 + }
333 464
334 - wp_enqueue_style( 'wcf-frontend-global', CARTFLOWS_URL . 'assets/css/frontend.css', array(), CARTFLOWS_VER );
335 - wp_style_add_data( 'wcf-frontend-global', 'rtl', 'replace' );
465 + $localize = apply_filters( 'global_cartflows_js_localize', $localize );
336 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 +
337 493 wp_enqueue_script(
338 494 'wcf-frontend-global',
339 - CARTFLOWS_URL . 'assets/js/frontend.js',
340 - array( 'jquery' ),
495 + wcf()->utils->get_js_url( 'frontend' ),
496 + array( 'jquery', 'jquery-cookie' ),
341 497 CARTFLOWS_VER,
342 - true
498 + false
343 499 );
344 500 }
345 501
346 502 /**
@@ -347,23 +503,119 @@
347 503 * Custom Script in head.
348 504 *
349 505 * @since 1.0.0
350 506 */
351 - function custom_script_option() {
507 + public function custom_script_option() {
352 508
353 - /* Add custom script to header in frontend. */
354 - $script = $this->get_custom_script();
355 - if ( '' !== $script ) {
356 - if ( false === strpos( $script, '<script' ) ) {
357 - $script = '<script>' . $script . '</script>';
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
358 546 }
359 - echo '<!-- Custom CartFlows Script -->';
360 - echo $script;
361 - echo '<!-- End Custom CartFlows Script -->';
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;
362 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;
363 600 }
364 601
365 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 + /**
366 618 * Override woo templates.
367 619 *
368 620 * @param string $template new Template full path.
369 621 * @param string $template_name Template name.
@@ -370,9 +622,9 @@
370 622 * @param string $template_path Template Path.
371 623 * @since 1.1.5
372 624 * @return string.
373 625 */
374 - function override_woo_template( $template, $template_name, $template_path ) {
626 + public function override_woo_template( $template, $template_name, $template_path ) {
375 627
376 628 global $woocommerce;
377 629
378 630 $_template = $template;
@@ -395,9 +647,9 @@
395 647 *
396 648 * @since 1.1.5
397 649 * @return void.
398 650 */
399 - function remove_flatsome_action() {
651 + public function remove_flatsome_action() {
400 652
401 653 // Remove action where flatsome dequeued the woocommerce's default styles.
402 654 remove_action( 'wp_enqueue_scripts', 'flatsome_woocommerce_scripts_styles', 98 );
403 655 }
@@ -408,28 +660,285 @@
408 660 * @since 1.1.5
409 661 * @param array $classes classes.
410 662 * @return array $classes classes.
411 663 */
412 - function add_cartflows_lite_version_to_body( $classes ) {
664 + public function add_cartflows_lite_version_to_body( $classes ) {
413 665
414 666 $classes[] = 'cartflows-' . CARTFLOWS_VER;
415 667
416 668 return $classes;
669 + }
417 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;
418 685 }
419 686
420 687 /**
688 + * Replace the dynamic vars in the custom script.
689 + *
690 + }
691 +
692 + /**
421 693 * Get custom script data.
422 694 *
423 695 * @since 1.0.0
424 696 */
425 - function get_custom_script() {
697 + public function get_flow_custom_script() {
426 698
427 699 global $post;
428 700
429 - $script = get_post_meta( $post->ID, 'wcf-custom-script', true );
701 + $step_id = $post->ID;
430 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 +
431 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;
432 941 }
433 942 }
434 943
435 944 /**