PluginProbe
CartFlows – Funnel Builder & Checkout Plugin for WooCommerce / 3.1.3
CartFlows – Funnel Builder & Checkout Plugin for WooCommerce v3.1.3
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
cartflows / admin-legacy-core / inc / admin-menu.php

admin-menu.php in CartFlows – Funnel Builder & Checkout Plugin for WooCommerce 3.1.3, at admin-legacy-core/inc/admin-menu.php

1,224 lines 43.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * CartFlows Admin Menu.
4 *
5 * @package CartFlows
6 */
7
8 namespace CartflowsAdmin\AdminLegacyCore\Inc;
9
10 use CartflowsAdmin\AdminLegacyCore\Inc\AdminHelper;
11 use CartflowsAdmin\AdminLegacyCore\Inc\LogStatus;
12
13
14 // Exit if accessed directly.
15 if ( ! defined( 'ABSPATH' ) ) {
16 exit;
17 }
18
19 /**
20 * Class Admin_Menu.
21 */
22 class AdminMenu {
23
24 /**
25 * Instance
26 *
27 * @access private
28 * @var object Class object.
29 * @since 1.0.0
30 */
31 private static $instance;
32
33 /**
34 * For Gutenberg
35 *
36 * @var $is_gutenberg_editor_active
37 */
38 private $is_gutenberg_editor_active = false;
39
40 /**
41 * Initiator
42 *
43 * @since 1.0.0
44 * @return object initialized object of class.
45 */
46 public static function get_instance() {
47 if ( ! isset( self::$instance ) ) {
48 self::$instance = new self();
49 }
50 return self::$instance;
51 }
52
53 /**
54 * Instance
55 *
56 * @access private
57 * @var string Class object.
58 * @since 1.0.0
59 */
60 private $menu_slug;
61
62 /**
63 * Constructor
64 *
65 * @since 1.0.0
66 */
67 public function __construct() {
68 $this->menu_slug = 'cartflows';
69
70 $this->initialize_hooks();
71 }
72
73 /**
74 * Init Hooks.
75 *
76 * @since 1.0.0
77 * @return void
78 */
79 public function initialize_hooks() {
80
81 add_action( 'admin_menu', array( $this, 'setup_menu' ) );
82 add_action( 'admin_init', array( $this, 'settings_admin_scripts' ) );
83 add_action( 'admin_init', array( $this, 'add_capabilities_to_admin' ) );
84
85 /* Flow content view */
86 add_action( 'cartflows_render_admin_page_content', array( $this, 'render_content' ), 10, 2 );
87
88 add_action( 'edit_form_after_title', array( $this, 'new_admin_flow_setting_redirection' ), 10, 1 );
89
90 /* To check the status of gutenberg */
91 add_action( 'enqueue_block_editor_assets', array( $this, 'set_block_editor_status' ) );
92 add_action( 'admin_footer', array( $this, 'back_to_new_step_ui_for_gutenberg' ), 999 );
93
94 add_action( 'admin_notices', array( $this, 'back_to_new_step_ui_for_classic_editor' ) );
95
96 add_action( 'wp_ajax_cartflows_fetch_whats_new_data', array( $this, 'fetch_whats_new_data' ) );
97 }
98
99 /**
100 * Display admin notices.
101 *
102 * @since 1.0.0
103 *
104 * @return void
105 */
106 public function back_to_new_step_ui_for_classic_editor() {
107
108 if ( CARTFLOWS_STEP_POST_TYPE !== get_post_type() ) {
109 return;
110 }
111
112 $flow_id = get_post_meta( get_the_id(), 'wcf-flow-id', true );
113 $step_id = isset( $_GET['post'] ) ? intval( $_GET['post'] ) : 0; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
114
115 if ( $flow_id && $step_id ) {
116 $path = \Cartflows_Helper::get_global_setting( '_cartflows_store_checkout' ) === $flow_id ? 'store-checkout' : 'flows';
117
118 $flow_redirect_url = esc_url( admin_url() . 'admin.php?page=' . $this->menu_slug . '&path= ' . $path . '&action=wcf-edit-flow&flow_id=' . $flow_id ); // phpcs:igmore Generic.Strings.UnnecessaryStringConcat.Found.
119 ?>
120 <div class="wcf-notice-back-edit-step">
121 <p>
122 <a href="<?php echo esc_url( $flow_redirect_url ); ?>" class="button button-primary button-hero wcf-header-back-button" style="text-decoration: none;">
123 <?php esc_html_e( 'Edit Funnel', 'cartflows' ); ?>
124 </a>
125 </p>
126 </div>
127 <?php
128 }
129 }
130
131 /**
132 * Set status true for gutenberg.
133 *
134 * @return void
135 */
136 public function set_block_editor_status() {
137
138 if ( ! current_user_can( 'cartflows_manage_flows_steps' ) ) {
139 return;
140 }
141
142 // Set gutenberg status here.
143 $this->is_gutenberg_editor_active = true;
144 }
145
146 /**
147 * Back to flow button gutenberg template
148 *
149 * @return void
150 */
151 public function back_to_new_step_ui_for_gutenberg() {
152
153 // Exit if block editor is not enabled.
154 if ( ! $this->is_gutenberg_editor_active ) {
155 return;
156 }
157
158 wp_enqueue_script( 'cartflows-admin-common-script', CARTFLOWS_ADMIN_CORE_URL . 'assets/js/common.js', array( 'jquery' ), CARTFLOWS_VER, false );
159
160 if ( CARTFLOWS_STEP_POST_TYPE !== get_post_type() ) {
161 return;
162 }
163
164 $flow_id = get_post_meta( get_the_id(), 'wcf-flow-id', true );
165 $step_id = isset( $_GET['post'] ) ? intval( $_GET['post'] ) : 0; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
166
167 if ( $flow_id && $step_id ) {
168 $path = \Cartflows_Helper::get_global_setting( '_cartflows_store_checkout' ) === $flow_id ? 'store-checkout' : 'flows';
169 $flow_redirect_url = esc_url( admin_url() . 'admin.php?page=' . $this->menu_slug . '&path=' . $path . '&action=wcf-edit-flow&flow_id=' . $flow_id );
170 ?>
171 <script id="wcf-gutenberg-back-step-button" type="text/html">
172 <div class="wcf-notice-back-edit-step gutenberg-button" style="display: flex; margin: 2px 5px;">
173 <a href="<?php echo esc_url( $flow_redirect_url ); ?>" class="button button-primary button-large wcf-header-back-button" style="text-decoration: none; font-size: 13px; line-height: 2.5;"><?php esc_html_e( 'Edit Funnel', 'cartflows' ); ?></a>
174 </div>
175 </script>
176 <script>
177 window.addEventListener('load', function () {
178 ( function( window, wp ){
179 var link = document.querySelector('a.components-button.edit-post-fullscreen-mode-close');
180 if (link) {
181 link.setAttribute('href', "<?php echo htmlspecialchars_decode( esc_url( $flow_redirect_url ) );//phpcs:ignore ?>")
182 }
183
184 } )( window, wp )
185 });
186 </script>
187 <?php
188 }
189 }
190
191
192 /**
193 * Back to flow button
194 *
195 * @param array $meta meta data.
196 *
197 * @return void
198 */
199 public function new_admin_flow_setting_redirection( $meta ) {
200
201 $flow_id = isset( $_GET['post'] ) ? intval( $_GET['post'] ) : 0; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
202
203 $post_type = get_post_type();
204
205 if ( CARTFLOWS_FLOW_POST_TYPE === $post_type && 0 !== $flow_id ) {
206
207 $redirect_url = esc_url( admin_url() . 'admin.php?page=' . $this->menu_slug . '&path=flows&action=wcf-edit-flow&flow_id=' . $flow_id );
208 $btn_markup = '<div class="wcf-flow-editing-action" style="padding: 50px;text-align: center;">';
209 $btn_markup .= '<a class="button button-primary button-hero" href="' . $redirect_url . '">' . __( 'Go to Funnel Editing', 'cartflows' ) . '</a>';
210 $btn_markup .= '</div>';
211
212 echo wp_kses_post( $btn_markup );
213 }
214 }
215
216 /**
217 * Initialize after Cartflows pro get loaded.
218 */
219 public function settings_admin_scripts() {
220
221 // Enqueue admin scripts.
222 // Ignoring nonce verification as using SuperGlobal variables on WordPress hooks.
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
225 add_action( 'admin_enqueue_scripts', array( $this, 'styles_scripts' ) );
226
227 add_filter( 'admin_footer_text', array( $this, 'add_footer_link' ), 99 );
228 }
229 }
230
231 /**
232 * Add submenu to admin menu.
233 *
234 * @since 1.0.0
235 */
236 public function setup_menu() {
237 global $submenu;
238
239 if ( current_user_can( 'cartflows_manage_flows_steps' ) ) {
240 $parent_slug = $this->menu_slug;
241 $capability = 'cartflows_manage_flows_steps';
242 $menu_priority = apply_filters( 'cartflows_menu_priority', ! defined( 'ASTRA_THEME_VERSION' ) ? 40 : 3 );
243
244 add_menu_page(
245 'CartFlows',
246 'CartFlows',
247 $capability,
248 $parent_slug,
249 array( $this, 'render' ),
250 'data:image/svg+xml;base64,' . base64_encode( file_get_contents( CARTFLOWS_DIR . 'assets/images/cartflows-icon.svg' ) ),
251 $menu_priority
252 );
253
254 // Add settings menu.
255 add_submenu_page(
256 $parent_slug,
257 __( 'Funnels', 'cartflows' ),
258 __( 'Funnels', 'cartflows' ),
259 $capability,
260 'admin.php?page=' . $this->menu_slug . '&path=flows'
261 );
262
263 $global_checkout_id = absint( \Cartflows_Helper::get_global_setting( '_cartflows_store_checkout' ) );
264 $global_checkout_param = ( empty( $global_checkout_id ) ) ? 'path=store-checkout' : 'path=store-checkout&action=wcf-edit-flow&flow_id=' . $global_checkout_id;
265
266 add_submenu_page(
267 $parent_slug,
268 __( 'Store Checkout', 'cartflows' ),
269 __( 'Store Checkout', 'cartflows' ),
270 $capability,
271 'admin.php?page=' . $this->menu_slug . '&' . $global_checkout_param
272 );
273
274 add_submenu_page(
275 $parent_slug,
276 __( 'Analytics', 'cartflows' ),
277 __( 'Analytics', 'cartflows' ),
278 $capability,
279 'admin.php?page=' . $this->menu_slug . '&path=analytics'
280 );
281
282 if ( current_user_can( 'cartflows_manage_settings' ) ) {
283 add_submenu_page(
284 $parent_slug,
285 __( 'Automations', 'cartflows' ),
286 // Here the inline CSS is added to make sure that the menu's tag css should display correctly on all pages.
287 __( 'Automations', 'cartflows' ) . '<span class="submenu-tag" style="margin-left: 4px; color: #f06434; vertical-align: super; font-size: 9px;">' . __( 'New', 'cartflows' ) . '</span>',
288 $capability,
289 'admin.php?page=' . $this->menu_slug . '&path=automations'
290 );
291
292 if ( 'active' !== $this->get_plugin_status( 'modern-cart/modern-cart.php' ) ) {
293 add_submenu_page(
294 $parent_slug,
295 __( 'Modern Cart', 'cartflows' ),
296 // Here the inline CSS is added to make sure that the menu's tag css should display correctly on all pages.
297 __( 'Modern Cart', 'cartflows' ) . '<span class="submenu-tag" style="margin-left: 4px; color: #f06434; vertical-align: super; font-size: 9px;">' . __( 'New', 'cartflows' ) . '</span>',
298 $capability,
299 'admin.php?page=' . $this->menu_slug . '&path=modern-cart'
300 );
301 }
302
303 add_submenu_page(
304 $parent_slug,
305 __( 'Add-ons', 'cartflows' ),
306 __( 'Add-ons', 'cartflows' ),
307 ! wcf_file_mod_disabled() ? $capability : 'do_not_allow',
308 'admin.php?page=' . $this->menu_slug . '&path=addons'
309 );
310
311 add_submenu_page(
312 $parent_slug,
313 __( 'Learn', 'cartflows' ),
314 __( 'Learn', 'cartflows' ),
315 $capability,
316 'admin.php?page=' . $this->menu_slug . '&path=learn'
317 );
318
319 if ( ! _is_cartflows_pro() ) {
320 add_submenu_page(
321 $parent_slug,
322 __( 'Get CartFlows Pro', 'cartflows' ),
323 __( 'Get CartFlows Pro', 'cartflows' ),
324 $capability,
325 \Cartflows_Helper::get_upgrade_to_pro_link()
326 );
327 }
328 }
329
330 // Rename to Home menu.
331 // Disable phpcs since we need to override submenu name.
332 $submenu[ $parent_slug ][0][0] = __( 'Dashboard', 'cartflows' ); //phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
333 }
334 }
335
336 /**
337 * Add custom capabilities to Admin user.
338 */
339 public function add_capabilities_to_admin() {
340
341 global $wp_roles;
342 // Add custom capabilities to admin by default.
343 $capabilities = array(
344 'cartflows_manage_settings',
345 'cartflows_manage_flows_steps',
346 );
347
348 foreach ( $capabilities as $cap ) {
349 $wp_roles->add_cap( 'administrator', $cap );
350 }
351 }
352
353 /**
354 * Renders the admin settings.
355 *
356 * @since 1.0.0
357 * @return void
358 */
359 public function render() {
360 $menu_page_slug = ( isset( $_GET['page'] ) ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : CARTFLOWS_SETTINGS; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
361 $page_action = '';
362
363 if ( isset( $_GET['action'] ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
364 $page_action = sanitize_text_field( wp_unslash( $_GET['action'] ) ); //phpcs:ignore WordPress.Security.NonceVerification.Recommended
365 $page_action = str_replace( '_', '-', $page_action );
366 }
367
368 include_once CARTFLOWS_ADMIN_CORE_DIR . 'views/admin-base.php';
369 }
370
371 /**
372 * Renders the admin settings content.
373 *
374 * @since 1.0.0
375 * @param sting $menu_page_slug current page name.
376 * @param sting $page_action current page action.
377 *
378 * @return void
379 */
380 public function render_content( $menu_page_slug, $page_action ) {
381
382 if ( 'cartflows' === $menu_page_slug ) {
383 if ( $this->is_current_page( 'cartflows' ) ) {
384 include_once CARTFLOWS_ADMIN_CORE_DIR . 'views/settings-app.php';
385 } elseif ( $this->is_current_page( 'cartflows', array( 'wcf-edit-flow' ) ) ) {
386 include_once CARTFLOWS_ADMIN_CORE_DIR . 'views/editor-app.php';
387 } elseif ( $this->is_current_page( 'cartflows', array( 'wcf-log' ) ) ) {
388 include_once CARTFLOWS_ADMIN_CORE_DIR . 'views/debugger.php';
389 } elseif ( $this->is_current_page( 'cartflows', array( 'wcf-license' ) ) && _is_cartflows_pro() ) {
390 do_action( 'cartflows_admin_log', 'wcf-license' );
391 } else {
392 include_once CARTFLOWS_ADMIN_CORE_DIR . 'views/404-error.php';
393 }
394 }
395 }
396
397 /**
398 * Enqueues the needed CSS/JS for the builder's admin settings page.
399 *
400 * @since 1.0.0
401 */
402 public function styles_scripts() {
403
404 $admin_slug = 'cartflows-admin';
405
406 // Load the custom font for admin area.
407 wp_enqueue_style( $admin_slug . '-font', 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap', array(), CARTFLOWS_VER );
408
409 // Styles.
410 wp_enqueue_style( $admin_slug . '-common', CARTFLOWS_ADMIN_CORE_URL . 'assets/css/common.css', array(), CARTFLOWS_VER );
411 wp_style_add_data( $admin_slug . '-common', 'rtl', 'replace' );
412
413 wp_enqueue_script( $admin_slug . '-common-script', CARTFLOWS_ADMIN_CORE_URL . 'assets/js/common.js', array( 'jquery' ), CARTFLOWS_VER, false );
414
415 wp_enqueue_script( $admin_slug . '-suretriggers-integration', CARTFLOWS_SURETRIGGERS_INTEGRATION_BASE_URL . 'js/v2/embed.js', array(), CARTFLOWS_VER, true );
416
417 $current_flow_steps = array();
418 $flow_id = isset( $_GET['flow_id'] ) ? intval( $_GET['flow_id'] ) : 0; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
419 if ( $flow_id ) {
420 $current_flow_steps = AdminHelper::get_flow_meta_options( $flow_id );
421 }
422
423 $product_src = esc_url_raw(
424 add_query_arg(
425 array(
426 'post_type' => 'product',
427 'wcf-woo-iframe' => 'true',
428 ),
429 admin_url( 'post-new.php' )
430 )
431 );
432
433
434 $page_builder = \Cartflows_Helper::get_common_setting( 'default_page_builder' );
435 $page_builder_name = \Cartflows_Helper::get_page_builder_name( $page_builder );
436
437 $global_checkout_id = \Cartflows_Helper::get_global_setting( '_cartflows_store_checkout' );
438
439 $flow_action = 'wcf-edit-flow';
440 $step_action = 'wcf-edit-step';
441
442 $flows_and_steps = \Cartflows_Helper::get_instance()->get_flows_and_steps();
443
444 $cf_pro_status = $this->get_cartflows_pro_plugin_status();
445 $cf_pro_type_inactive = '';
446 if ( 'inactive' === $cf_pro_status || 'not-installed' === $cf_pro_status ) {
447
448 if ( ! function_exists( 'get_plugins' ) ) {
449 require_once ABSPATH . 'wp-admin/includes/plugin.php';
450 }
451
452 $plugin = get_plugins();
453 $cf_pro_type_inactive = isset( $plugin['cartflows-pro/cartflows-pro.php']['Name'] ) ? $plugin['cartflows-pro/cartflows-pro.php']['Name'] : '';
454 }
455
456 $order_url = '#';
457
458 if ( wcf()->is_woo_active && class_exists( '\Automattic\WooCommerce\Utilities\OrderUtil' ) ) {
459 $order_url = \Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled() ? admin_url( 'admin.php?page=wc-orders' ) : admin_url( 'edit.php?post_type=shop_order' );
460 }
461
462 $localize = apply_filters(
463 'cartflows_admin_localized_vars',
464 array(
465 'current_user' => ! empty( wp_get_current_user()->user_firstname ) ? wp_get_current_user()->user_firstname : wp_get_current_user()->display_name,
466 'cf_pro_status' => $cf_pro_status,
467 'cf_pro_type' => 'free',
468 'cf_pro_type_inactive' => $cf_pro_type_inactive,
469 'woocommerce_status' => $this->get_plugin_status( 'woocommerce/woocommerce.php' ),
470 'default_page_builder' => $page_builder,
471 'required_plugins' => \Cartflows_Helper::get_plugins_groupby_page_builders(),
472 'required_plugins_data' => $this->get_required_plugins_data(),
473 'is_any_required_plugins_missing' => $this->get_any_required_plugins_status(),
474 'admin_base_slug' => $this->menu_slug,
475 'admin_base_url' => admin_url(),
476 'title_length' => apply_filters(
477 'cartflows_flows_steps_title_length',
478 array(
479 'max' => 50,
480 'display_length' => 40,
481 )
482 ),
483 'plugin_dir' => CARTFLOWS_URL,
484 'admin_url' => admin_url( 'admin.php' ),
485 'ajax_url' => admin_url( 'admin-ajax.php' ),
486 'is_rtl' => is_rtl(),
487 'home_slug' => $this->menu_slug,
488 'is_pro' => _is_cartflows_pro(),
489 'is_file_mod_disabled' => function_exists( 'wcf_file_mod_disabled' ) ? wcf_file_mod_disabled() : false, // Keep false by default if function not exists.
490 'page_builder' => $page_builder,
491 'page_builder_name' => $page_builder_name,
492 'global_checkout' => \Cartflows_Helper::get_common_setting( 'global_checkout' ),
493 'flows_count' => 1, // Removing the flow count condition.
494 'currentFlowSteps' => $current_flow_steps,
495 // Delete this code after 3 major update. Added in 1.10.4.
496 'license_status' => \_is_cartflows_pro_license_activated(),
497 'license_popup_url' => admin_url( 'admin.php?page=cartflows&settings=1&tab=license' ),
498 'store_checkout_show_product_tab' => \Cartflows_Helper::display_product_tab_in_store_checkout(),
499 'cf_domain_url' => CARTFLOWS_DOMAIN_URL,
500 'cf_upgrade_to_pro_url' => \Cartflows_Helper::get_upgrade_to_pro_link(),
501 'logo_url' => esc_url_raw( CARTFLOWS_URL . 'assets/images/cartflows-logo.svg' ),
502 'create_product_src' => $product_src,
503 'cf_font_family' => AdminHelper::get_font_family(),
504 'flows_and_steps' => ! empty( $flows_and_steps ) ? $flows_and_steps : '',
505 'store_checkout_flows_and_steps' => \Cartflows_Helper::get_instance()->get_flows_and_steps( '', 'store-checkout' ),
506 'woo_currency' => function_exists( 'get_woocommerce_currency_symbol' ) ? get_woocommerce_currency_symbol() : '',
507 'template_library_url' => wcf()->get_site_url(),
508 'image_placeholder' => esc_url_raw( CARTFLOWS_URL . 'admin-legacy-core/assets/images/image-placeholder.png' ),
509 'google_fonts' => \CartFlows_Font_Families::get_google_fonts(),
510 'system_fonts' => \CartFlows_Font_Families::get_system_fonts(),
511 'font_weights' => array(
512 '100' => __( 'Thin 100', 'cartflows' ),
513 '200' => __( 'Extra-Light 200', 'cartflows' ),
514 '300' => __( 'Light 300', 'cartflows' ),
515 '400' => __( 'Normal 400', 'cartflows' ),
516 '500' => __( 'Medium 500', 'cartflows' ),
517 '600' => __( 'Semi-Bold 600', 'cartflows' ),
518 '700' => __( 'Bold 700', 'cartflows' ),
519 '800' => __( 'Extra-Bold 800', 'cartflows' ),
520 '900' => __( 'Ultra-Bold 900', 'cartflows' ),
521 ),
522 'global_checkout_id' => $global_checkout_id ? absint( $global_checkout_id ) : '',
523 'flow_action' => $flow_action,
524 'step_action' => $step_action,
525 'old_global_checkout' => get_option( '_cartflows_old_global_checkout', false ),
526 'woopayments_status' => $this->get_plugin_status( 'woocommerce-payments/woocommerce-payments.php' ),
527 'ca_status' => $this->get_plugin_status( 'woo-cart-abandonment-recovery/woo-cart-abandonment-recovery.php' ),
528 'suretriggers_status' => $this->get_plugin_status( 'suretriggers/suretriggers.php' ),
529 'moderncart_status' => $this->get_plugin_status( 'modern-cart/modern-cart.php' ),
530 'cpsw_connection_status' => 'success' === get_option( 'cpsw_test_con_status', false ) || 'success' === get_option( 'cpsw_con_status', false ),
531 'current_user_can_manage_cartflows' => current_user_can( 'cartflows_manage_settings' ),
532 'is_set_report_email_ids' => get_option( 'cartflows_stats_report_email_ids', false ),
533 'cf_docs_data' => get_option( 'cartflows_docs_data', false ),
534 'woo_order_url' => $order_url,
535 'integrations' => $this->get_recommendation_integrations(),
536 'plugin_installer_nonce' => wp_create_nonce( 'updates' ),
537 'instant_checkout_notice_status' => \Cartflows_Helper::get_admin_settings_option( 'wcf-instant-checkout-notice-skipped', false, false ),
538 'cartflows_admin_notices' => $this->cartflows_admin_notices(),
539 'whats_new_rss_feed' => $this->get_whats_new_rss_feeds_data(),
540 'cartflows_current_version' => CARTFLOWS_VER,
541 'cartflows_previous_versions' => \Cartflows_Helper::get_rollback_versions_options(),
542 'rollback_url' => esc_url( add_query_arg( 'version', 'VERSION', wp_nonce_url( admin_url( 'admin-post.php?action=cartflows_rollback' ), 'cartflows_rollback' ) ) ),
543 'utm_defaults' => \Cartflows_Helper::get_utm_defaults(),
544 'switch_ui_notice' => array(
545 // is_new_ui_notice_visible() already enforces the
546 // cartflows_manage_settings capability + CARTFLOWS_LEGACY_ADMIN
547 // + per-user dismissal — same gating the AJAX endpoints check.
548 'visible' => \Cartflows_Admin_Notices::get_instance()->is_new_ui_notice_visible(),
549 'switch_action' => 'cartflows_switch_to_new_ui',
550 'switch_nonce' => wp_create_nonce( 'cartflows_switch_to_new_ui' ),
551 'dismiss_action' => 'cartflows_dismiss_new_ui_notice',
552 'dismiss_nonce' => wp_create_nonce( 'cartflows_dismiss_new_ui_notice' ),
553 ),
554 )
555 );
556
557 // Load the codemirror for code editor.
558 wp_enqueue_code_editor(
559 array(
560 'type' => 'text/javascript',
561 )
562 );
563 wp_enqueue_code_editor(
564 array(
565 'type' => 'text/css',
566 )
567 );
568
569 wp_enqueue_script( 'wp-code-editor' );
570 wp_enqueue_style( 'wp-codemirror' );
571
572 if ( $this->is_current_page( $this->menu_slug ) ) {
573 $this->settings_app_scripts( $localize );
574 } elseif ( $this->is_current_page( 'cartflows', array( 'wcf-edit-flow' ) ) ) {
575 wp_enqueue_media();
576 wp_enqueue_editor(); // Require for Order Bump Desc WP Editor/ tinymce field.
577 $this->editor_app_scripts( $localize );
578 }
579 }
580
581 /**
582 * Get recommendation integrations.
583 *
584 * @since 1.11.8
585 *
586 * @return array
587 */
588 public function cartflows_admin_notices() {
589 $notices = array();
590
591 $notices = $this->page_builder_plugin_notices( $notices );
592 $notices = apply_filters( 'cartflows_admin_notices', $notices );
593
594 return $notices;
595 }
596
597 /**
598 * Get builder plugin notices.
599 *
600 * @since 1.11.8
601 * @param array $notices Notices array.
602 * @return array
603 */
604 public function page_builder_plugin_notices( $notices ) {
605 $required_plugins_missing = $this->get_any_required_plugins_status();
606 $default_page_builder = \Cartflows_Helper::get_common_setting( 'default_page_builder' );
607 $required_plugins = array();
608 if ( isset( \Cartflows_Helper::get_plugins_groupby_page_builders()[ $default_page_builder ] ) ) {
609 $required_plugins = \Cartflows_Helper::get_plugins_groupby_page_builders()[ $default_page_builder ];
610 }
611
612 $page_builder_plugins = isset( $required_plugins['plugins'] ) ? $required_plugins['plugins'] : array();
613 $any_inactive = false;
614 if ( ! empty( $page_builder_plugins ) ) {
615 foreach ( $page_builder_plugins as $plugin ) {
616 if ( 'activated' !== $plugin['status'] ) {
617 $any_inactive = true;
618 break; // Stop checking if we found an active plugin.
619 }
620 }
621 }
622
623 // Get the titles.
624 $titles = $this->generate_plugin_titles( $page_builder_plugins );
625
626 if ( 'yes' === $required_plugins_missing && $any_inactive ) {
627 $notices[] = '<div class="wcf-payment-gateway-notice--text"><p class="text-sm text-yellow-700">' . wp_kses_post(
628 sprintf(
629 // Translators: %1$s is the required page builder title, %2$s is the opening anchor tag to plugins.php, %3$s is the closing anchor tag, %4$s is the plugin title.
630 __( 'The default page builder is set to %1$s. Please %2$sinstall & activate%3$s the %4$s to start editing the steps.', 'cartflows' ), //phpcs:ignore
631 '<span class="capitalize">' . esc_html( $required_plugins['title'] ) . '</span>',
632 '<span class="font-medium"><a href="' . esc_url( admin_url() . 'plugins.php' ) . '" class="underline text-yellow-700 hover:text-yellow-600" target="_blank">',
633 '</a></span>',
634 '<span class="capitalize">' . esc_html( implode( ', ', $titles ) ) . '</span>'
635 )
636 ) . '</p></div>';
637
638 }
639 return $notices;
640 }
641
642 /**
643 * Get required plugin titles from their slugs.
644 *
645 * @since 2.1.6
646 * @param array $plugins plugins array.
647 * @return array
648 */
649 public function generate_plugin_titles( $plugins ) {
650 $titles = array();
651
652 if ( ! is_array( $plugins ) || empty( $plugins ) ) {
653 return $titles;
654 }
655
656 foreach ( $plugins as $plugin ) {
657
658 if ( 'ultimate-addons-for-gutenberg' === $plugin['slug'] ) {
659 $title = 'Spectra'; // Don't add this for translation as it is a plugin name.
660 } else {
661 $slug_parts = explode( '-', $plugin['slug'] );
662 $title = implode( ' ', array_map( 'ucfirst', $slug_parts ) ); // Convert each part to title case.
663 }
664
665 $titles[] = $title;
666 }
667
668 return $titles;
669 }
670
671
672 /**
673 * Get required plugin status.
674 */
675 public function get_required_plugins_data() {
676
677 $missing_plugins_data = array();
678
679 $page_builder_plugins = \Cartflows_Helper::get_plugins_groupby_page_builders();
680
681 foreach ( $page_builder_plugins as $slug => $data ) {
682
683 $missing_plugins_data[ $slug ] = 'no';
684 $current_page_builder_data = $page_builder_plugins[ $slug ];
685
686 foreach ( $current_page_builder_data['plugins'] as $plugin ) {
687 if ( 'activate' === $plugin['status'] || 'install' === $plugin['status'] ) {
688 $missing_plugins_data[ $slug ] = 'yes';
689 }
690 }
691
692 // Divi.
693 if ( 'divi' === $slug ) {
694 if ( 'activate' === $current_page_builder_data['theme-status'] ) {
695 $missing_plugins_data[ $slug ] = 'yes';
696 }
697 }
698 }
699
700 return $missing_plugins_data;
701 }
702 /**
703 * Get required plugin status
704 */
705 public function get_any_required_plugins_status() {
706
707 $default_page_builder = \Cartflows_Helper::get_common_setting( 'default_page_builder' );
708 $any_inactive = 'no';
709
710 $page_builder_plugins = \Cartflows_Helper::get_plugins_groupby_page_builders();
711
712 if ( isset( $page_builder_plugins[ $default_page_builder ] ) ) {
713
714 $current_page_builder_data = $page_builder_plugins[ $default_page_builder ];
715
716 foreach ( $current_page_builder_data['plugins'] as $plugin ) {
717 if ( 'activate' === $plugin['status'] || 'install' === $plugin['status'] ) {
718 $any_inactive = 'yes';
719 }
720 }
721
722 // Divi.
723 if ( 'divi' === $default_page_builder ) {
724 if ( 'activate' === $current_page_builder_data['theme-status'] ) {
725 $any_inactive = 'yes';
726 }
727 }
728 }
729
730 return $any_inactive;
731 }
732
733 /**
734 * Get CartFlows plugin status
735 *
736 * @since 1.11.8
737 *
738 * @return string
739 */
740 public function get_cartflows_pro_plugin_status() {
741
742 $status = $this->get_plugin_status( 'cartflows-pro/cartflows-pro.php' );
743
744 if ( 'active' === $status && ! _is_cartflows_pro() ) {
745
746 $status = 'inactive';
747 }
748
749 return $status;
750 }
751
752 /**
753 * Get plugin status
754 *
755 * @since 1.1.4
756 *
757 * @param string $plugin_init_file Plguin init file.
758 * @return mixed
759 */
760 public function get_plugin_status( $plugin_init_file ) {
761
762 $installed_plugins = get_plugins();
763
764 if ( ! isset( $installed_plugins[ $plugin_init_file ] ) ) {
765 return 'not-installed';
766 } elseif ( is_plugin_active( $plugin_init_file ) ) {
767 return 'active';
768 } else {
769 return 'inactive';
770 }
771 }
772
773 /**
774 * Get plugin status
775 *
776 * @since 1.1.4
777 *
778 * @param string $theme_name Theme slug file.
779 * @return string
780 */
781 public function get_themes_status( $theme_name ) {
782
783 $theme = wp_get_theme();
784
785 // Theme installed and activate.
786 if ( $theme_name === $theme->name || $theme_name === $theme->parent_theme ) {
787 return 'active';
788 }
789
790 // Theme installed but not activate.
791 foreach ( (array) wp_get_themes() as $theme_dir => $theme ) {
792 if ( $theme_name === $theme->name || $theme_name === $theme->parent_theme ) {
793 return 'inactive';
794 }
795 }
796
797 // If none of the above conditions are found then the theme is not installed.
798 return 'not-installed';
799 }
800
801 /**
802 * Settings app scripts
803 *
804 * @param array $localize Variable names.
805 */
806 public function settings_app_scripts( $localize ) {
807 $handle = 'wcf-react-settings';
808 $build_path = CARTFLOWS_ADMIN_CORE_DIR . 'assets/build/';
809 $build_url = CARTFLOWS_ADMIN_CORE_URL . 'assets/build/';
810 $script_asset_path = $build_path . 'settings-app.asset.php';
811 $script_info = file_exists( $script_asset_path )
812 ? include $script_asset_path
813 : array(
814 'dependencies' => array(),
815 'version' => CARTFLOWS_VER,
816 );
817
818 $script_dep = array_merge( $script_info['dependencies'], array( 'updates' ) );
819
820 wp_register_script(
821 $handle,
822 $build_url . 'settings-app.js',
823 $script_dep,
824 $script_info['version'],
825 true
826 );
827
828 wp_register_style(
829 $handle,
830 $build_url . 'settings-app.css',
831 array(),
832 CARTFLOWS_VER
833 );
834
835 wp_enqueue_script( $handle );
836
837 wp_set_script_translations( $handle, 'cartflows' );
838
839 wp_enqueue_style( $handle );
840 wp_style_add_data( $handle, 'rtl', 'replace' );
841
842 $localize['is_flows_limit'] = false; // Removed the flow count condition.
843
844 $localize = $this->debugger_scripts( $localize );
845
846 $localize['save_learn_completed_nonce'] = wp_create_nonce( 'cartflows_save_learn_completed' );
847 $localize['activate_plugin_nonce'] = wp_create_nonce( 'cartflows_activate_plugin' );
848
849 wp_localize_script( $handle, 'cartflows_admin', $localize );
850 }
851
852 /**
853 * Settings app scripts
854 *
855 * @param array $localize Variable names.
856 */
857 public function editor_app_scripts( $localize ) {
858 $handle = 'wcf-editor-app';
859 $build_path = CARTFLOWS_ADMIN_CORE_DIR . 'assets/build/';
860 $build_url = CARTFLOWS_ADMIN_CORE_URL . 'assets/build/';
861 $script_asset_path = $build_path . 'editor-app.asset.php';
862 $script_info = file_exists( $script_asset_path )
863 ? include $script_asset_path
864 : array(
865 'dependencies' => array(),
866 'version' => CARTFLOWS_VER,
867 );
868
869 wp_register_script(
870 $handle,
871 $build_url . 'editor-app.js',
872 $script_info['dependencies'],
873 $script_info['version'],
874 true
875 );
876
877 wp_register_style(
878 $handle,
879 $build_url . 'editor-app.css',
880 array(),
881 CARTFLOWS_VER
882 );
883
884 wp_register_style(
885 'wcf-canvas-base-style',
886 $build_url . 'style-editor-app.css',
887 array(),
888 CARTFLOWS_VER
889 );
890 // Enqueue the registered style.
891 wp_enqueue_style( 'wcf-canvas-base-style' );
892
893 wp_enqueue_script( $handle );
894
895 wp_set_script_translations( $handle, 'cartflows' );
896
897 wp_enqueue_style( $handle );
898 wp_style_add_data( $handle, 'rtl', 'replace' );
899
900 $localize['flow_id'] = isset( $_GET['flow_id'] ) ? intval( $_GET['flow_id'] ) : 0; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
901
902 $step_id = isset( $_GET['step_id'] ) ? intval( $_GET['step_id'] ) : false; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
903
904 if ( $step_id ) {
905
906 $meta_options = AdminHelper::get_step_meta_options( $step_id );
907 $localize['options'] = $meta_options['options'];
908 }
909
910 wp_localize_script( $handle, 'cartflows_admin', $localize );
911 }
912
913 /**
914 * Debugger scripts.
915 *
916 * @param array $localize Variable names.
917 */
918 public function debugger_scripts( $localize ) {
919
920 $logs = LogStatus::get_instance()->get_log_files();
921 $viewed_log = '';
922 $viewed_log_file = '';
923
924 // Calling this function on CartFlows action hook. Hence ignoring nonce.
925 if ( ! empty( $_REQUEST['log_file'] ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
926
927 $filename = sanitize_text_field( wp_unslash( $_REQUEST['log_file'] ) ); //phpcs:ignore WordPress.Security.NonceVerification.Recommended
928
929 if ( isset( $logs[ $filename ] ) ) {
930 $viewed_log = $filename;
931 $viewed_log_file = $viewed_log . '.log';
932 }
933 } elseif ( ! empty( $logs ) ) {
934 $viewed_log = current( $logs ) ? pathinfo( current( $logs ), PATHINFO_FILENAME ) : '';
935 $viewed_log_file = $viewed_log . '.log';
936 }
937
938 if ( ! empty( $viewed_log_file ) ) {
939 $file_content = file_get_contents( CARTFLOWS_LOG_DIR . $viewed_log_file );
940 $localize['file_content'] = $file_content;
941 $localize['log_key'] = $viewed_log;
942
943 }
944 $localize['logs'] = $logs;
945 return $localize;
946 }
947
948
949 /**
950 * CHeck if it is current page by parameters
951 *
952 * @param string $page_slug Menu name.
953 * @param string $action Menu name.
954 *
955 * @return string page url
956 */
957 public function is_current_page( $page_slug = '', $action = '' ) {
958
959 $page_matched = false;
960
961 if ( empty( $page_slug ) ) {
962 return false;
963 }
964
965 $current_page_slug = isset( $_GET['page'] ) ? sanitize_text_field( $_GET['page'] ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
966 $current_action = isset( $_GET['action'] ) ? sanitize_text_field( $_GET['action'] ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
967
968 if ( ! is_array( $action ) ) {
969 $action = explode( ' ', $action );
970 }
971
972 if ( $page_slug === $current_page_slug && in_array( $current_action, $action, true ) ) {
973 $page_matched = true;
974 }
975
976 return $page_matched;
977 }
978
979 /**
980 * Add footer link.
981 */
982 public function add_footer_link() {
983
984 $logs_page_url = add_query_arg(
985 array(
986 'page' => CARTFLOWS_SLUG,
987 'path' => 'wcf-log',
988 ),
989 admin_url( '/admin.php' )
990 );
991
992 return '<span id="footer-thankyou"> Thank you for using <a href="' . esc_url( \Cartflows_Helper::get_utm_url( 'https://cartflows.com/', array( 'utm_campaign' => 'footer-link' ) ) ) . '">CartFlows</a></span> | <a href="' . $logs_page_url . '">Logs</a>';
993 }
994
995 /**
996 * Get CartFlows recommended integrations.
997 *
998 * @return array
999 */
1000 public function get_recommendation_integrations() {
1001
1002 return array(
1003 'plugins' => apply_filters(
1004 'cartflows_admin_integrated_plugins',
1005 array(
1006 array(
1007 'title' => __( 'WooCommerce', 'cartflows' ),
1008 'subtitle' => __( 'WooCommerce is a customizable, open-source ecommerce platform built on WordPress.', 'cartflows' ),
1009 'isPro' => false,
1010 'status' => $this->get_plugin_status( 'woocommerce/woocommerce.php' ),
1011 'slug' => 'woocommerce',
1012 'path' => 'woocommerce/woocommerce.php',
1013 'redirection' => admin_url( 'admin.php?page=wc-admin' ),
1014 'logoPath' => array(
1015 'icon_path' => CARTFLOWS_ADMIN_CORE_URL . 'assets/images/plugins/woo.svg',
1016 ),
1017 ),
1018 array(
1019 'title' => __( 'Power Coupons', 'cartflows' ),
1020 'subtitle' => __( 'Create powerful coupon rules with advanced conditions, discount types, and usage restrictions for WooCommerce.', 'cartflows' ),
1021 'isPro' => false,
1022 'status' => $this->get_plugin_status( 'power-coupons/power-coupons.php' ),
1023 'slug' => 'power-coupons',
1024 'path' => 'power-coupons/power-coupons.php',
1025 'redirection' => admin_url( 'admin.php?page=power_coupons_settings' ),
1026 'logoPath' => array(
1027 'icon_path' => CARTFLOWS_ADMIN_CORE_URL . 'assets/images/plugins/power-coupons.svg',
1028 ),
1029 ),
1030 array(
1031 'title' => __( 'Modern Cart for WooCommerce', 'cartflows' ),
1032 'subtitle' => __( 'A fast, customizable cart built to boost conversions, maximise profits, and elevate the shopping experience.', 'cartflows' ),
1033 'isPro' => false,
1034 'status' => $this->get_plugin_status( 'modern-cart/modern-cart.php' ),
1035 'slug' => 'modern-cart',
1036 'path' => 'modern-cart/modern-cart.php',
1037 'redirection' => admin_url( 'admin.php?page=moderncart_settings' ),
1038 'logoPath' => array(
1039 'icon_path' => CARTFLOWS_ADMIN_CORE_URL . 'assets/images/plugins/modern-cart-for-woocommerce.svg',
1040 ),
1041 'hot_badge' => true,
1042 ),
1043 array(
1044 'title' => __( 'Cart Abandonment Recovery', 'cartflows' ),
1045 'subtitle' => __( 'Recover abandonded carts with ease in less than 10 minutes.', 'cartflows' ),
1046 'isPro' => false,
1047 'status' => $this->get_plugin_status( 'woo-cart-abandonment-recovery/woo-cart-abandonment-recovery.php' ),
1048 'slug' => 'woo-cart-abandonment-recovery',
1049 'path' => 'woo-cart-abandonment-recovery/woo-cart-abandonment-recovery.php',
1050 'redirection' => admin_url( 'admin.php?page=woo-cart-abandonment-recovery' ),
1051 'logoPath' => array(
1052 'icon_path' => CARTFLOWS_ADMIN_CORE_URL . 'assets/images/plugins/wcar.svg',
1053 ),
1054 'hot_badge' => true,
1055 ),
1056 array(
1057 'title' => __( 'Variation Swatches for WooCommerce', 'cartflows' ),
1058 'subtitle' => __( 'Convert dropdown boxes into highly engaging variation swatches.', 'cartflows' ),
1059 'isPro' => false,
1060 'status' => $this->get_plugin_status( 'variation-swatches-woo/variation-swatches-woo.php' ),
1061 'slug' => 'variation-swatches-woo',
1062 'path' => 'variation-swatches-woo/variation-swatches-woo.php',
1063 'redirection' => admin_url( 'admin.php?page=cfvsw_settings' ),
1064 'logoPath' => array(
1065 'icon_path' => CARTFLOWS_ADMIN_CORE_URL . 'assets/images/plugins/variation-swatches-woo.svg',
1066 ),
1067 'hot_badge' => true,
1068 ),
1069 array(
1070 'title' => __( 'WooPayments: Integrated WooCommerce Payments', 'cartflows' ),
1071 'subtitle' => __( 'Payments made simple, with no monthly fees – designed exclusively for WooCommerce stores.', 'cartflows' ),
1072 'isPro' => false,
1073 'status' => $this->get_plugin_status( 'woocommerce-payments/woocommerce-payments.php' ),
1074 'redirection' => admin_url( 'admin.php?page=wc-admin&path=/payments/connect' ),
1075 'slug' => 'woocommerce-payments',
1076 'path' => 'woocommerce-payments/woocommerce-payments.php',
1077 'logoPath' => array(
1078 'icon_path' => CARTFLOWS_ADMIN_CORE_URL . 'assets/images/plugins/woocommere-payments.png',
1079 ),
1080 ),
1081 array(
1082 'title' => __( 'OttoKit', 'cartflows' ),
1083 'subtitle' => __( 'OttoKit helps people automate their work by integrating multiple apps and plugins, allowing them to share data and perform tasks automatically.', 'cartflows' ),
1084 'isPro' => true,
1085 'status' => $this->get_plugin_status( 'suretriggers/suretriggers.php' ),
1086 'slug' => 'suretriggers',
1087 'path' => 'suretriggers/suretriggers.php',
1088 'link' => 'https://ottokit.com/pricing/',
1089 'redirection' => admin_url( 'admin.php?page=suretriggers' ),
1090 'logoPath' => array(
1091 'icon_path' => CARTFLOWS_ADMIN_CORE_URL . 'assets/images/plugins/suretriggers-emblem.svg',
1092 ),
1093 ),
1094 array(
1095 'title' => __( 'Ultimate addons for Elementor', 'cartflows' ),
1096 'subtitle' => __( 'Powerful Elementor addon with InfoCard, Fancy Heading, Before/After Slider, Price Box, FAQ Schema, WooCommerce widgets & Header-Footer builder.', 'cartflows' ),
1097 'isPro' => false,
1098 'status' => $this->get_plugin_status( 'header-footer-elementor/header-footer-elementor.php' ),
1099 'slug' => 'header-footer-elementor',
1100 'path' => 'header-footer-elementor/header-footer-elementor.php',
1101 'redirection' => admin_url( 'admin.php?page=hfe#dashboard' ),
1102 'logoPath' => array(
1103 'icon_path' => CARTFLOWS_ADMIN_CORE_URL . 'assets/images/plugins/uael.png',
1104 ),
1105 ),
1106 array(
1107 'title' => __( 'Spectra', 'cartflows' ),
1108 'subtitle' => __( 'Power-up the Gutenberg editor with advanced and powerful blocks.', 'cartflows' ),
1109 'isPro' => false,
1110 'status' => $this->get_plugin_status( 'ultimate-addons-for-gutenberg/ultimate-addons-for-gutenberg.php' ),
1111 'slug' => 'ultimate-addons-for-gutenberg',
1112 'path' => 'ultimate-addons-for-gutenberg/ultimate-addons-for-gutenberg.php',
1113 'redirection' => admin_url( 'options-general.php?page=spectra' ),
1114 'logoPath' => array(
1115 'icon_path' => CARTFLOWS_ADMIN_CORE_URL . 'assets/images/plugins/spectra.svg',
1116 ),
1117 ),
1118 array(
1119 'title' => __( 'SureForms', 'cartflows' ),
1120 'subtitle' => __( 'Transform your WordPress form-building experience with stunning designs, ai integration, and no-code flexibility.', 'cartflows' ),
1121 'isPro' => false,
1122 'status' => $this->get_plugin_status( 'sureforms/sureforms.php' ),
1123 'slug' => 'sureforms',
1124 'path' => 'sureforms/sureforms.php',
1125 'redirection' => admin_url( 'admin.php?page=sureforms_menu' ),
1126 'logoPath' => array(
1127 'icon_path' => CARTFLOWS_ADMIN_CORE_URL . 'assets/images/plugins/sureforms.svg',
1128 ),
1129 ),
1130 array(
1131 'title' => __( 'SureMembers', 'cartflows' ),
1132 'subtitle' => __( 'A simple yet powerful way to add content restriction to your website.', 'cartflows' ),
1133 'isPro' => true,
1134 'status' => $this->get_plugin_status( 'suremembers/suremembers.php' ),
1135 'slug' => 'suremembers',
1136 'path' => 'suremembers/suremembers.php',
1137 'link' => 'https://suremembers.com/pricing/',
1138 'redirection' => admin_url( 'edit.php?post_type=wsm_access_group' ),
1139 'logoPath' => array(
1140 'icon_path' => CARTFLOWS_ADMIN_CORE_URL . 'assets/images/plugins/suremembers.svg',
1141 ),
1142 ),
1143 )
1144 ),
1145 'themes' => apply_filters(
1146 'cartflows_admin_integrated_themes',
1147 array(
1148 array(
1149 'title' => __( 'Astra', 'cartflows' ),
1150 'subtitle' => __( 'Astra is fast, fully customizable & beautiful WordPress theme suitable for blog, personal portfolio, business website and WooCommerce storefront.', 'cartflows' ),
1151 'isPro' => false,
1152 'status' => $this->get_themes_status( 'Astra' ),
1153 'slug' => 'astra',
1154 'redirection' => admin_url( 'admin.php?page=wc-admin' ),
1155 'logoPath' => array(
1156 'icon_path' => CARTFLOWS_ADMIN_CORE_URL . 'assets/images/themes/astra-icon.svg',
1157 ),
1158 ),
1159 array(
1160 'title' => __( 'Spectra One', 'cartflows' ),
1161 'subtitle' => __( 'Spectra One is a beautiful and modern WordPress theme built with the Full Site Editing (FSE) feature. It\'s a versatile theme that can be used for blogs, portfolios, businesses, and more.', 'cartflows' ),
1162 'isPro' => false,
1163 'status' => $this->get_themes_status( 'Spectra One' ),
1164 'slug' => 'spectra-one',
1165 'redirection' => admin_url( 'admin.php?page=wc-admin' ),
1166 'logoPath' => array(
1167 'icon_path' => CARTFLOWS_ADMIN_CORE_URL . 'assets/images/themes/spectra-one.svg',
1168 ),
1169 ),
1170 )
1171 ),
1172 );
1173 }
1174
1175 /**
1176 * Prepare the array of RSS Feeds of CartFlows for Whats New slide-our pannel.
1177 *
1178 * @since 2.1.6
1179 * @return array The prepared array of RSS feeds.
1180 */
1181 public function get_whats_new_rss_feeds_data() {
1182 return array(
1183 array(
1184 'key' => 'cartflows',
1185 'label' => 'CartFlows',
1186 'url' => add_query_arg(
1187 array(
1188 'action' => 'cartflows_fetch_whats_new_data',
1189 'nonce' => wp_create_nonce( 'cartflows_fetch_whats_new_data' ),
1190 ),
1191 admin_url( 'admin-ajax.php' )
1192 ), // 'https://cartflows.com/whats-new/feed/'
1193 ),
1194 );
1195 }
1196
1197 /**
1198 * Fetch the Whats New RSS feed from the URL.
1199 *
1200 * @since 1.0.3
1201 * @return void
1202 */
1203 public function fetch_whats_new_data() {
1204 if ( ! isset( $_GET['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_GET['nonce'] ), 'cartflows_fetch_whats_new_data' ) ) {
1205 // Verify the nonce, if it fails, return an error.
1206 wp_send_json_error( array( 'message' => __( 'Nonce verification failed.', 'cartflows' ) ) );
1207 }
1208
1209 // Security: Require admin capability to access RSS feed proxy.
1210 if ( ! current_user_can( 'cartflows_manage_flows_steps' ) ) {
1211 wp_send_json_error( array( 'message' => __( 'Permission denied.', 'cartflows' ) ) );
1212 }
1213
1214 // Fetch the RSS feed from the URL. This saves us from the CORS issue.
1215 $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.
1216
1217 // Security: Set proper content type header and strip script tags to prevent XSS.
1218 echo $feed; // phpcs:ignore -- RSS feed content sanitized via wp_kses_post.
1219 exit;
1220 }
1221 }
1222
1223 AdminMenu::get_instance();
1224