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 | admin-core/inc/admin-menu.php +44 -5 3.1.4 → 3.3.0 View file →
@@ -222,8 +222,12 @@
222 222 // Ignoring nonce verification as using SuperGlobal variables on WordPress hooks.
223 223 if ( isset( $_GET['page'] ) && ( 'cartflows' === sanitize_text_field( $_GET['page'] ) || false !== strpos( sanitize_text_field( $_GET['page'] ), 'cartflows_' ) ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
224 224
225 225 add_action( 'admin_enqueue_scripts', array( $this, 'styles_scripts' ) );
226 +
227 + // Twemoji rewrites emoji text nodes inside our React tree, detaching nodes React still tracks and crashing the editor.
228 + remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
229 + remove_action( 'admin_print_styles', 'print_emoji_styles' );
226 230 }
227 231 }
228 232
229 233 /**
@@ -276,8 +280,22 @@
276 280 $capability,
277 281 'admin.php?page=' . $this->menu_slug . '&path=analytics'
278 282 );
279 283
284 + // Persistent re-entry point until the guided setup is finished.
285 + if ( current_user_can( 'manage_options' ) && '1' !== get_option( 'wcf_setup_complete', false ) ) {
286 + $exit_step = get_option( 'wcf_exit_setup_step', '' );
287 + $resume_link = 'index.php?page=cartflows-onboarding' . ( ! empty( $exit_step ) && is_string( $exit_step ) ? '&step=' . sanitize_key( $exit_step ) : '' );
288 +
289 + add_submenu_page(
290 + $parent_slug,
291 + __( 'Resume Setup', 'cartflows' ),
292 + __( 'Resume Setup', 'cartflows' ),
293 + $capability,
294 + $resume_link
295 + );
296 + }
297 +
280 298 if ( current_user_can( 'cartflows_manage_settings' ) ) {
281 299
282 300 add_submenu_page(
283 301 $parent_slug,
@@ -354,10 +372,8 @@
354 372 if ( $this->is_current_page( 'cartflows' ) ) {
355 373 include_once CARTFLOWS_ADMIN_CORE_DIR . 'views/settings-app.php';
356 374 } elseif ( $this->is_current_page( 'cartflows', array( 'wcf-edit-flow' ) ) ) {
357 375 include_once CARTFLOWS_ADMIN_CORE_DIR . 'views/editor-app.php';
358 - } elseif ( $this->is_current_page( 'cartflows', array( 'wcf-log' ) ) ) {
359 - include_once CARTFLOWS_ADMIN_CORE_DIR . 'views/debugger.php';
360 376 } elseif ( $this->is_current_page( 'cartflows', array( 'wcf-license' ) ) && _is_cartflows_pro() ) {
361 377 do_action( 'cartflows_admin_log', 'wcf-license' );
362 378 } else {
363 379 include_once CARTFLOWS_ADMIN_CORE_DIR . 'views/404-error.php';
@@ -475,10 +491,16 @@
475 491 'cf_font_family' => AdminHelper::get_font_family(),
476 492 'flows_and_steps' => ! empty( $flows_and_steps ) ? $flows_and_steps : '',
477 493 'store_checkout_flows_and_steps' => \Cartflows_Helper::get_instance()->get_flows_and_steps( '', 'store-checkout' ),
478 494 'woo_currency' => function_exists( 'get_woocommerce_currency_symbol' ) ? get_woocommerce_currency_symbol() : '',
495 + 'woo_currency_pos' => function_exists( 'wc' ) ? get_option( 'woocommerce_currency_pos', 'left' ) : 'left',
496 + 'woo_decimal_sep' => function_exists( 'wc_get_price_decimal_separator' ) ? wc_get_price_decimal_separator() : '.',
497 + 'woo_thousand_sep' => function_exists( 'wc_get_price_thousand_separator' ) ? wc_get_price_thousand_separator() : ',',
498 + 'woo_decimals' => function_exists( 'wc_get_price_decimals' ) ? wc_get_price_decimals() : 2,
479 499 'template_library_url' => wcf()->get_site_url(),
480 500 'image_placeholder' => esc_url_raw( CARTFLOWS_URL . 'admin-core/assets/images/image-placeholder.png' ),
501 + 'ai_connected' => class_exists( '\Cartflows_Ai_Auth' ) ? \Cartflows_Ai_Auth::get_instance()->get_auth_status() : false,
502 + 'can_manage_ai_auth' => current_user_can( 'manage_options' ),
481 503 'google_fonts' => \CartFlows_Font_Families::get_google_fonts(),
482 504 'system_fonts' => \CartFlows_Font_Families::get_system_fonts(),
483 505 'font_weights' => array(
484 506 '100' => __( 'Thin 100', 'cartflows' ),
@@ -501,9 +523,8 @@
501 523 'moderncart_status' => $this->get_plugin_status( 'modern-cart/modern-cart.php' ),
502 524 'cpsw_connection_status' => 'success' === get_option( 'cpsw_test_con_status', false ) || 'success' === get_option( 'cpsw_con_status', false ),
503 525 'current_user_can_manage_cartflows' => current_user_can( 'cartflows_manage_settings' ),
504 526 'is_set_report_email_ids' => get_option( 'cartflows_stats_report_email_ids', false ),
505 - 'cf_docs_data' => get_option( 'cartflows_docs_data', false ),
506 527 'woo_order_url' => $order_url,
507 528 'integrations' => $this->get_recommendation_integrations(),
508 529 'plugin_installer_nonce' => wp_create_nonce( 'updates' ),
509 530 'instant_checkout_notice_status' => \Cartflows_Helper::get_admin_settings_option( 'wcf-instant-checkout-notice-skipped', false, false ),
@@ -808,8 +829,17 @@
808 829 array(),
809 830 CARTFLOWS_VER
810 831 );
811 832
833 + // Store Checkout renders the canvas inside this app too, so it needs the React Flow base styles.
834 + wp_register_style(
835 + 'wcf-canvas-base-style',
836 + $build_url . 'style-editor-app.css',
837 + array(),
838 + CARTFLOWS_VER
839 + );
840 + wp_enqueue_style( 'wcf-canvas-base-style' );
841 +
812 842 wp_enqueue_script( $handle );
813 843
814 844 wp_set_script_translations( $handle, 'cartflows' );
815 845
@@ -1174,10 +1204,19 @@
1174 1204
1175 1205 // Fetch the RSS feed from the URL. This saves us from the CORS issue.
1176 1206 $feed = wp_remote_retrieve_body( wp_safe_remote_get( 'https://cartflows.com/product/cartflows/feed/' ) ); // phpcs:ignore -- This is a valid use case cannot use VIP rules here.
1177 1207
1178 - // Security: Set proper content type header and strip script tags to prevent XSS.
1179 - echo $feed; // phpcs:ignore -- RSS feed content sanitized via wp_kses_post.
1208 + /*
1209 + * This is an RSS document, parsed as XML by the What's New client. It must not be
1210 + * run through wp_kses_post() — that strips the feed's own elements and leaves the
1211 + * client nothing to parse. Declaring the type is what stops a browser sniffing the
1212 + * response as HTML; the body itself is fetched over HTTPS from our own domain and
1213 + * this endpoint is behind a nonce and a capability check.
1214 + */
1215 + header( 'Content-Type: application/rss+xml; charset=' . get_option( 'blog_charset' ) );
1216 + header( 'X-Content-Type-Options: nosniff' );
1217 +
1218 + echo $feed; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- RSS/XML body, see above.
1180 1219 exit;
1181 1220 }
1182 1221 }
1183 1222