PluginProbe
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell / 3.13.1
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell v3.13.1
3.13.1 3.13.0 3.12.13 3.12.12 3.12.11 3.12.10 3.12.9 3.12.8 3.12.7 3.12.6 3.12.5 3.12.4 3.12.3 3.12.1 3.12.2 3.12.0 3.11.1 3.11.0 3.10.9 3.10.8 3.10.7 3.10.6 2.8.16 2.8.17 2.8.18 All 259 releases
wpfunnels / includes / class-wpfnl.php

class-wpfnl.php in WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell 3.13.1, at includes/class-wpfnl.php

783 lines 22.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * The core plugin class.
4 *
5 * This is used to define internationalization, admin-specific hooks, and
6 * public-facing site hooks.
7 *
8 * Also maintains the unique identifier of this plugin as well as the current
9 * version of the plugin.
10 *
11 * @since 1.0.0
12 * @package Wpfnl
13 * @subpackage Wpfnl/includes
14 * @author RexTheme <support@rextheme.com>
15 */
16 namespace WPFunnels;
17
18 use Wpfnl_Activator;
19 use Wpfnl_i18n;
20 use Wpfnl_Loader;
21 use Wpfnl_Logger;
22 use WPFunnels\Admin\OptinField\OptinField;
23 use WPFunnels\Admin\SetupWizard;
24 use WPFunnels\Admin\Wpfnl_Admin as Admin;
25 use WPFunnels\Admin\Notices\Notice;
26 use WPFunnels\Admin\Banner\SpecialOccasionBanner;
27 use WPFunnels\Admin\Banner\SetupReminderBanner;
28 use WPFunnels\Ajax_Handler\Ajax_Handler;
29 use WPFunnels\Classes\OrderBumpActions\Wpfnl_Order_Bump_Action;
30 use WPFunnels\Classes\TestimonialActions\Wpfnl_Testimonial_Action;
31 use WPFunnels\Compatibility\CartLift\Wpfnl_Cart_Lift_Compatibility;
32 use WPFunnels\Compatibility\SlimSeo\Wpfnl_Slim_Seo_Compatibility;
33 use WPFunnels\Frontend\Wpfnl_Public;
34 use WPFunnels\Frontend\Wpfnl_Public as Frontend;
35 use WPFunnels\CPT\Wpfnl_CPT as CPT;
36 use WPFunnels\Data_Store\Wpfnl_Funnel_Store_Data as Funnel_Store;
37 use WPFunnels\Data_Store\Wpfnl_Steps_Store_Data as Step_Store;
38 use WPFunnels\Menu\Wpfnl_Menus as Menu;
39 use WPFunnels\Modules\Wpfnl_Modules_Manager as Module_Manager;
40 use WPFunnels\Report\OptinRecorder;
41 use WPFunnels\Report\StatHookHandler;
42 use WPFunnels\Rest\Server;
43 // use WPFunnels\Shortcodes\Wpfnl_Shortcode;
44 use WPFunnels\Shortcodes\Wpfnl_Shortcodes;
45 use WPFunnels\Widgets\Wpfnl_Widgets_Manager as Widget_Manager;
46 use WPFunnels\Batch\Elementor\Wpfnl_Batch;
47 use WPFunnels\Meta\Wpfnl_Default_Meta;
48 use WPFunnels\Compatibility\Wpfnl_Compatibility;
49 use WPFunnels\Export\Wpfnl_Export;
50 use WPFunnels\Import\Wpfnl_Import;
51 use WPFunnels\Report\Reporting;
52 /**
53 * The file that defines the core plugin class
54 *
55 * A class definition that includes attributes and functions used across both the
56 * public-facing side of the site and the admin area.
57 *
58 * @link https://rextheme.com
59 * @since 1.0.0
60 *
61 * @package Wpfnl
62 * @subpackage Wpfnl/includes
63 */
64
65 class Wpfnl
66 {
67
68 /**
69 * Instance.
70 *
71 * Holds the plugin instance.
72 *
73 * @since 1.0.0
74 * @access public
75 * @static
76 *
77 * @var Wpfnl
78 */
79 public static $instance = null;
80
81 public $module_manager;
82
83 public $admin;
84
85 public $plugin_public;
86
87 public $template_manager;
88
89 public $menu;
90
91 public $cpt;
92
93 public $funnel_store;
94
95 public $step_store;
96
97 public $batch;
98
99 public $helper;
100
101 public $widget_manager;
102
103 public $page_templates;
104
105
106 public $order_bump_actions;
107
108 public $testimonial_actions;
109
110 public $meta;
111
112 public $frontend;
113
114 public $log;
115
116 public $shortcodes;
117 public $shortcode;
118
119
120 public $export_funnel;
121
122 public $import_funnel;
123
124 /**
125 * Admin notice object
126 *
127 * @var string $admin_notice
128 */
129 protected $admin_notice;
130
131
132 /**
133 * Admin banner object
134 *
135 * @var string $admin_banner
136 */
137 protected $admin_banner;
138
139 /**
140 * Setup reminder banner object
141 *
142 * @var SetupReminderBanner $setup_reminder_banner
143 * @since 3.6.0
144 */
145 protected $setup_reminder_banner;
146
147 protected $optin_field;
148
149 /**
150 * Reporting object
151 *
152 * @var $reporting
153 *
154 * @since 3.2.0
155 */
156 protected $reporting;
157
158 /**
159 * The loader that's responsible for maintaining and registering all hooks that power
160 * the plugin.
161 *
162 * @since 1.0.0
163 * @access protected
164 * @var Wpfnl_Loader $loader Maintains and registers all hooks for the plugin.
165 */
166 protected $loader;
167
168 /**
169 * The unique identifier of this plugin.
170 *
171 * @since 1.0.0
172 * @access protected
173 * @var string $plugin_name The string used to uniquely identify this plugin.
174 */
175 protected $plugin_name;
176
177
178 /**
179 * Object variable for Compatibility class
180 *
181 * @since
182 * @access protected
183 * @var $compatibility
184 */
185 protected $compatibility;
186
187 /**
188 * The current version of the plugin.
189 *
190 * @since 1.0.0
191 * @access protected
192 * @var string $version The current version of the plugin.
193 */
194 protected $version;
195
196
197 /**
198 * Ajax handler
199 *
200 * @var $ajax_handler
201 */
202 protected $ajax_handler;
203
204
205 /**
206 * Object variable for Cart_Lift_Compatibility class
207 *
208 * @since
209 * @access protected
210 * @var $cart_lift
211 */
212 protected $cart_lift;
213
214
215 /**
216 * Object variable for Slim_Seo_Compatibility class
217 *
218 * @since
219 * @access protected
220 * @var $slim_seo
221 */
222 protected $slim_seo;
223
224
225 /**
226 * StatHookHandler Object
227 *
228 * @var $stat_hooks_handler
229 * @type StatHookHandler
230 * @since 3.2.0
231 */
232 protected $stat_hooks_handler;
233
234
235 /**
236 * OptinRecorder Object
237 *
238 * @var $optin_recorder
239 * @type OptinRecorder
240 * @since 3.2.0
241 */
242 protected $optin_recorder;
243
244 /**
245 * Instance.
246 *
247 * Ensures only one instance of the plugin class is loaded or can be loaded.
248 *
249 * @since 1.0.0
250 * @access public
251 * @static
252 *
253 * @return Wpfnl An instance of the class.
254 */
255 public static function get_instance()
256 {
257 if (is_null(self::$instance)) {
258 self::$instance = new self();
259 do_action('wpfunnels/loaded');
260 }
261 return self::$instance;
262 }
263
264
265 /**
266 * Define the core functionality of the plugin.
267 *
268 * Set the plugin name and the plugin version that can be used throughout the plugin.
269 * Load the dependencies, define the locale, and set the hooks for the admin area and
270 * the public-facing side of the site.
271 *
272 * @since 1.0.0
273 */
274 public function __construct()
275 {
276 if (defined('WPFNL_VERSION')) {
277 $this->version = WPFNL_VERSION;
278 } else {
279 $this->version = '1.0.0';
280 }
281
282 $this->plugin_name = 'wpfunnels';
283 $this->load_dependencies();
284 $this->init_rest_api();
285 $this->init_setup_wizard();
286
287
288 /*if( !Wpfnl_functions::is_plugin_activated('woocommerce/woocommerce.php') ) {
289 add_action( 'admin_enqueue_scripts', [$this, 'enqueue_scripts'] );
290 add_action( 'wp_ajax_plugin_install_success', array($this, 'plugin_install_success') );
291 add_action( 'admin_notices', array('WPFunnels\Admin\Notices\Notice', 'woocommerce_dependency_notice') );
292 return;
293 }*/
294
295 /**
296 * Store Checkout needs WooCommerce. While it is missing, keep the
297 * activation endpoint registered so the Store Checkout screen can
298 * install/activate WooCommerce without leaving the page.
299 *
300 * @since 3.13.1
301 */
302 if ( ! Wpfnl_functions::is_wc_active() ) {
303 add_action( 'wp_ajax_plugin_install_success', array( $this, 'plugin_install_success' ) );
304 }
305
306 // load core modules
307 add_action( 'admin_footer', array($this, 'admin_footer_style') );
308 add_action( 'wpfunnels/pro_init', array( $this, 'after_pro_plugin_init' ) );
309 add_action( 'plugins_loaded', array($this, 'load_plugin'), 9 );
310
311 $this->set_locale();
312 $this->init_hooks();
313 }
314
315
316 /**
317 * update funnel data response
318 *
319 * @param Array $response
320 *
321 * @since 1.7.8
322 * @return Array $response
323 */
324 public function update_mint_funnel_data_response( $response ){
325
326 $automation_steps = [];
327 if( is_array($response) && !empty($response['funnel_data']['drawflow']['Home']['data']) ){
328 $steps_order = $response['funnel_data']['drawflow']['Home']['data'];
329 if( is_array($steps_order) ){
330 foreach( $steps_order as $key=>$step ){
331 if( isset( $step['data']['step_id'] ) ){
332 $step_id = $step['data']['step_id'];
333 if( Wpfnl_functions::is_mint_mrm_active() ){
334 $automation_steps['step_'.$step_id]['data'] = [];
335 }
336 }
337 }
338 }
339 }
340 $response['automationSteps'] = $automation_steps;
341 return $response;
342 }
343
344
345 /**
346 * Enqueue funnel admin common scripts
347 */
348 public function enqueue_scripts() {
349 wp_enqueue_script($this->plugin_name . '-common', WPFNL_DIR_URL . 'admin/assets/js/wpfnl-admin-common.js', [ 'jquery', 'wp-i18n', 'wp-util', 'updates' ], $this->version, true);
350 wp_localize_script( $this->plugin_name. '-common', 'wpfnl_common_vars', array(
351 'ajaxurl' => admin_url( 'admin-ajax.php' ),
352 'wpfnl_activate_plugin_nonce' => wp_create_nonce('wpfnl_activate_plugin_nonce')
353 ));
354
355 $post_id = get_the_ID();
356 $custom_css = get_post_meta( $post_id, 'rex_gutenberg_css', true );
357
358 if ( $custom_css ) {
359 wp_register_style( 'rex-gutenberg-css', false );
360 wp_enqueue_style( 'rex-gutenberg-css' );
361 wp_add_inline_style( 'rex-gutenberg-css', $custom_css );
362 }
363 }
364
365
366 /**
367 * Plugin activation ajax
368 */
369 public function plugin_install_success() {
370
371 if ( ! current_user_can( 'manage_options' ) ) {
372 wp_send_json_error( array(
373 'message' => __('You are not authorize to activate plugins.', 'wpfnl')
374 ) );
375 }
376
377 if ( ! check_ajax_referer( 'wpfnl_activate_plugin_nonce', 'security', false ) ) {
378 $response_data = array( 'message' => __('Nonce verification failed', 'wpfnl') );
379 wp_send_json_error( $response_data );
380 }
381
382 \wp_clean_plugins_cache();
383 $plugin_init = ( isset( $_POST['plugin_init'] ) ) ? esc_attr( $_POST['plugin_init'] ) : '';
384 $activate = \activate_plugin( $plugin_init, '', false, true );
385
386 if ( is_wp_error( $activate ) ) {
387 wp_send_json_error(
388 array(
389 'success' => false,
390 'message' => $activate->get_error_message(),
391 )
392 );
393 }
394
395 wp_send_json_success(
396 array(
397 'message' => __('Plugin activated successfully.', 'wpfnl'),
398 )
399 );
400 }
401
402
403 public function init_hooks() {
404 $this->loader->add_action( 'init', $this, 'load_admin_modules' );
405 $shortcode = new Wpfnl_Shortcodes();
406 add_action( 'init', array( $shortcode, 'init') );
407 }
408
409 public function init_rest_api() {
410 $this->loader->add_action( 'init', $this, 'load_rest_api' );
411 }
412
413 public function load_admin_modules() {
414 $this->module_manager = new Module_Manager();
415 }
416
417 public function load_rest_api() {
418 Server::instance()->init();
419 }
420
421
422 /**
423 * Load plugin classes
424 */
425 public function load_plugin() {
426 $this->batch = new Wpfnl_Batch();
427 $this->init();
428
429 do_action( 'wpfunnels/init' );
430 }
431
432 public function init() {
433 $this->admin = new Admin( $this->get_plugin_name(), $this->get_version() );
434 $this->frontend = Wpfnl_Public::getInstance();
435 $this->cpt = new CPT();
436 $this->menu = new Menu();
437 $this->funnel_store = new Funnel_Store();
438 $this->step_store = new Step_Store();
439 $this->template_manager = new TemplateLibrary\Manager();
440
441 $this->widget_manager = Widget_Manager::getInstance()->init();
442 $this->page_templates = new PageTemplates\Manager();
443 $this->admin_notice = new Notice();
444 $this->admin_banner = new SpecialOccasionBanner('4thjuly', '2026-07-02 00:00:01', '2026-07-07 23:59:59', 'https://getwpfunnels.com/pricing/?utm_source=plugin&utm_medium=dashboard-banner-wpf&utm_campaign=4THJULY2026');
445 $this->setup_reminder_banner = new SetupReminderBanner();
446 $this->order_bump_actions = new Wpfnl_Order_Bump_Action();
447 $this->testimonial_actions = new Wpfnl_Testimonial_Action();
448 $this->meta = new Wpfnl_Default_Meta();
449 $this->shortcodes = Wpfnl_Shortcodes::getInstance()->init();
450 $this->ajax_handler = new Ajax_Handler();
451 $this->optin_field = new OptinField();
452 $this->log = Wpfnl_Logger::getInstance()->initialize_logging();
453 $this->compatibility = new Wpfnl_Compatibility();
454
455 $this->stat_hooks_handler = new StatHookHandler();
456 $this->optin_recorder = new OptinRecorder();
457
458 // Initialize Payment Gateway Factory
459 if ( Wpfnl_functions::is_wc_active() ) {
460 Gateway\Payment_Gateways_Factory::getInstance();
461
462 // Initialize Offer Module (upsell/downsell) only if Pro is not active
463 // When Pro is active, it handles offer functionality
464 if ( ! Wpfnl_functions::is_wpfnl_pro_activated() ) {
465 new Offer\Wpfnl_Offer();
466 }
467
468 // Store Checkout: override the WooCommerce default checkout with the
469 // WPFunnels Store Checkout step (only when a step is configured).
470 require_once WPFNL_DIR . 'includes/core/woocommerce/class-wpfnl-store-checkout-override.php';
471 \WPFunnels\WooCommerce\Wpfnl_Store_Checkout_Override::getInstance();
472 }
473
474 $this->export_funnel = Wpfnl_Export::getInstance()->init_ajax();
475 $this->import_funnel = new Wpfnl_Import();
476
477 $this->reporting = Reporting::get_instance();
478 $this->reporting->init();
479
480 // AI copilot module: settings migration + conversation tables.
481 \WPFunnels\AI\AIInit::init();
482
483 // Tool layer: WordPress Abilities (always, when available) + the MCP
484 // server for external agents (gated on the `_wpfnl_mcp_enabled` option).
485 // Ability registration must NOT depend on that option — the in-plugin
486 // AI copilot resolves its own tools through the same registry
487 // (ToolGateway -> wp_get_abilities()), so turning off the external
488 // MCP endpoint would otherwise silently leave the copilot with zero
489 // tools to call.
490 if ( \WPFunnels\MCP\MCPInit::abilitiesApiAvailable() ) {
491 $expose_mcp_server = 'no' !== get_option( '_wpfnl_mcp_enabled', 'yes' );
492 ( new \WPFunnels\MCP\MCPInit() )->init( $expose_mcp_server );
493 }
494
495 Wpfnl_Activator::init();
496 }
497
498
499
500 /**
501 * Load the required dependencies for this plugin.
502 *
503 * Include the following files that make up the plugin:
504 *
505 * - Wpfnl_Loader. Orchestrates the hooks of the plugin.
506 * - Wpfnl_i18n. Defines internationalization functionality.
507 * - Wpfnl_Admin. Defines all hooks for the admin area.
508 * - Wpfnl_Public. Defines all hooks for the public side of the site.
509 *
510 * Create an instance of the loader which will be used to register the hooks
511 * with WordPress.
512 *
513 * @since 1.0.0
514 * @access private
515 */
516 private function load_dependencies()
517 {
518
519 /**
520 * Require the action scheduler
521 */
522 require_once plugin_dir_path(dirname(__FILE__)) . 'vendor/woocommerce/action-scheduler/action-scheduler.php';
523
524 /**
525 * The class responsible for auto loading all files of the
526 * core plugin.
527 */
528 require_once plugin_dir_path(dirname(__FILE__)) . 'vendor/autoload.php';
529
530 /**
531 * The class responsible for orchestrating the actions and filters of the
532 * core plugin.
533 */
534 require_once plugin_dir_path(dirname(__FILE__)) . 'includes/utils/class-wpfnl-loader.php';
535
536 /**
537 * The class responsible for defining internationalization functionality
538 * of the plugin.
539 */
540 require_once plugin_dir_path(dirname(__FILE__)) . 'includes/utils/class-wpfnl-i18n.php';
541
542 /**
543 * The class responsible for defining all actions that occur in the admin area.
544 */
545 require_once plugin_dir_path(dirname(__FILE__)) . 'admin/class-wpfnl-admin.php';
546
547 /**
548 * The class responsible for defining all actions that occur in the public-facing
549 * side of the site.
550 */
551 require_once plugin_dir_path(dirname(__FILE__)) . 'public/class-wpfnl-public.php';
552
553 /**
554 * Require action scheduler for crm
555 */
556 //require_once plugin_dir_path(dirname(__FILE__)) . 'packages/action-scheduler/action-scheduler.php';
557
558 $this->loader = new Wpfnl_Loader();
559 }
560
561
562 /**
563 * After pro plugin init action
564 */
565 public function after_pro_plugin_init() {
566
567 if ( ! is_admin() ) {
568 return;
569 }
570
571 if ( version_compare( WPFNL_PRO_VERSION, WPFNL_PRO_REQUIRED_VERSION, '<' ) ) {
572 add_action( 'admin_notices', array( $this, 'required_wpf_pro_notice' ) );
573 add_action( 'after_plugin_row_'. WPFNL_BASE, 'wpfnl_pro_update_notice_after_plugin_row' );
574 }
575 }
576
577
578 /**
579 * Required pro plugin notice
580 */
581 public function required_wpf_pro_notice() {
582 $class = 'notice notice-error';
583 $message = sprintf(__("It appears you have an older version of <strong>WPFunnels Pro</strong>. This may cause some issues with the plugin's functionality. Please update <strong>WPFunnels Pro</strong> to v%s and above.","wpfnl"), WPFNL_PRO_REQUIRED_VERSION); // phpcs:ignore
584 printf( '<div class="%1$s"><p>%2$s</p></div>', $class, $message );
585 }
586
587
588 /**
589 * Show pro dependency notice
590 * after plugin row
591 */
592 public function wpfnl_pro_update_notice_after_plugin_row() {
593 $message = sprintf(__("It appears you have an older version of <strong>WPFunnels Pro</strong>. This may cause some issues with the plugin's functionality. Please update <strong>WPFunnels Pro</strong> to v%s and above.",'wpfnl'), WPFNL_PRO_REQUIRED_VERSION ); // phpcs:ignore
594 printf( '</tr><tr class="plugin-update-tr"><td colspan="5" class="plugin-update"><div class="update-message" style="background-color: #ffebe8;">%s</div></td>', $message );
595 }
596
597
598 /**
599 * Define the locale for this plugin for internationalization.
600 *
601 * Uses the Wpfnl_i18n class in order to set the domain and to register the hook
602 * with WordPress.
603 *
604 * @since 1.0.0
605 * @access private
606 */
607 private function set_locale()
608 {
609 $plugin_i18n = new Wpfnl_i18n();
610
611 $this->loader->add_action('init', $plugin_i18n, 'load_plugin_textdomain');
612
613 }
614
615
616 /**
617 * Run the loader to execute all of the hooks with WordPress.
618 *
619 * @since 1.0.0
620 */
621 public function run()
622 {
623 $this->loader->run();
624 }
625
626
627 /**
628 * The name of the plugin used to uniquely identify it within the context of
629 * WordPress and to define internationalization functionality.
630 *
631 * @since 1.0.0
632 * @return string The name of the plugin.
633 */
634 public function get_plugin_name()
635 {
636 return $this->plugin_name;
637 }
638
639
640 /**
641 * The reference to the class that orchestrates the hooks with the plugin.
642 *
643 * @since 1.0.0
644 * @return Wpfnl_Loader Orchestrates the hooks of the plugin.
645 */
646 public function get_loader()
647 {
648 return $this->loader;
649 }
650
651
652 /**
653 * Retrieve the version number of the plugin.
654 *
655 * @since 1.0.0
656 * @return string The version number of the plugin.
657 */
658 public function get_version()
659 {
660 return $this->version;
661 }
662
663
664 /**
665 * Render admin footer styles
666 */
667 public function admin_footer_style() {
668 echo '<style>
669 .wpfnl-notice {
670 border-left-color: #dba617;
671 }
672 .wpfnl-notice .wpfnl-notice__content {
673 padding: 10px 0;
674 }
675
676 .wpfnl-notice .notice-dismiss {
677 top: 11px;
678 }
679
680 .wpfnl-notice .wpfnl-notice__content > p {
681 font-weight: 600;
682 margin: 0;
683 }
684 .wpfnl-notice .wpfnl-notice__actions {
685 margin-top: 8px;
686 }
687
688 .wpfnl-notice .wpfnl-notice__content .wpfnl-notice-button {
689 height: 36px;
690 line-height: 36px;
691 border-radius: 6px;
692 color: #fff;
693 font-weight: 500;
694 padding: 0 20px;
695 background: #6e42d3;
696 display: inline-block;
697 text-decoration: none;
698 letter-spacing: 0.5px;
699 transition: all 0.3s ease;
700 }
701
702 .wpfnl-notice .wpfnl-notice__content .wpfnl-notice-button:hover {
703 background: #4C25A5;
704 }
705 .wpfnl-notice .wpfnl-notice__content .wpfnl-notice-button .notice-loader {
706 border: 2px solid #8265c5;
707 border-radius: 50%;
708 border-top: 2px solid #fff;
709 width: 10px;
710 height: 10px;
711 animation: spin 0.7s linear infinite;
712 display: none;
713 position: relative;
714 top: 3px;
715 margin-left: 9px;
716 }
717 @-webkit-keyframes spin {
718 0% { -webkit-transform: rotate(0deg); }
719 100% { -webkit-transform: rotate(360deg); }
720 }
721
722 @keyframes spin {
723 0% { transform: rotate(0deg); }
724 100% { transform: rotate(360deg); }
725 }
726 </style>';
727 }
728
729
730 /**
731 * Init setup wizard options
732 */
733 public function init_setup_wizard() {
734 add_action('init', array( $this, 'register_setup_wizard_page' ));
735 add_action('admin_init', array($this, 'admin_redirects'));
736
737 // Register AJAX handlers for setup wizard (needs to be available even when not on wizard page)
738 \WPFunnels\Admin\SetupWizard::register_ajax_handlers();
739 }
740
741
742 /**
743 * Register setup wizard
744 */
745 public function register_setup_wizard_page() {
746 if (!empty($_GET['page']) && 'wpfunnels-setup' == sanitize_text_field( $_GET['page'] )) {
747 add_action('admin_menu', function () {
748 add_dashboard_page('WPFunnels Setup', 'WPFunnels Setup', 'manage_options', 'wpfunnels-setup', function () {
749 return '';
750 });
751 });
752 add_action('current_screen', function () {
753 new SetupWizard();
754 }, 999);
755 }
756 }
757
758
759 /**
760 * Handle redirects to setup/welcome page after install and updates.
761 *
762 * For setup wizard, transient must be present, the user must have access rights, and we must ignore the network/bulk plugin updaters.
763 */
764 public function admin_redirects()
765 {
766 // Setup wizard redirect.
767 if (get_transient('_wpfunnels_activation_redirect')) {
768 $do_redirect = true;
769 // On these pages, or during these events, postpone the redirect.
770 if (wp_doing_ajax() || is_network_admin() || !current_user_can('manage_options')) {
771 $do_redirect = false;
772 }
773
774 if ( $do_redirect ) {
775 delete_transient('_wpfunnels_activation_redirect');
776 $url = admin_url('admin.php?page=wpfunnels-setup');
777 wp_safe_redirect( wp_sanitize_redirect( esc_url_raw( $url ) ) );
778 exit;
779 }
780 }
781 }
782 }
783