PluginProbe
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell / 3.13.0
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell v3.13.0
3.13.3 3.13.2 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 All 261 releases
wpfunnels / includes / class-wpfnl.php

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

772 lines 22.0 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 <[email protected]>
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 // load core modules
296 add_action( 'admin_footer', array($this, 'admin_footer_style') );
297 add_action( 'wpfunnels/pro_init', array( $this, 'after_pro_plugin_init' ) );
298 add_action( 'plugins_loaded', array($this, 'load_plugin'), 9 );
299
300 $this->set_locale();
301 $this->init_hooks();
302 }
303
304
305 /**
306 * update funnel data response
307 *
308 * @param Array $response
309 *
310 * @since 1.7.8
311 * @return Array $response
312 */
313 public function update_mint_funnel_data_response( $response ){
314
315 $automation_steps = [];
316 if( is_array($response) && !empty($response['funnel_data']['drawflow']['Home']['data']) ){
317 $steps_order = $response['funnel_data']['drawflow']['Home']['data'];
318 if( is_array($steps_order) ){
319 foreach( $steps_order as $key=>$step ){
320 if( isset( $step['data']['step_id'] ) ){
321 $step_id = $step['data']['step_id'];
322 if( Wpfnl_functions::is_mint_mrm_active() ){
323 $automation_steps['step_'.$step_id]['data'] = [];
324 }
325 }
326 }
327 }
328 }
329 $response['automationSteps'] = $automation_steps;
330 return $response;
331 }
332
333
334 /**
335 * Enqueue funnel admin common scripts
336 */
337 public function enqueue_scripts() {
338 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);
339 wp_localize_script( $this->plugin_name. '-common', 'wpfnl_common_vars', array(
340 'ajaxurl' => admin_url( 'admin-ajax.php' ),
341 'wpfnl_activate_plugin_nonce' => wp_create_nonce('wpfnl_activate_plugin_nonce')
342 ));
343
344 $post_id = get_the_ID();
345 $custom_css = get_post_meta( $post_id, 'rex_gutenberg_css', true );
346
347 if ( $custom_css ) {
348 wp_register_style( 'rex-gutenberg-css', false );
349 wp_enqueue_style( 'rex-gutenberg-css' );
350 wp_add_inline_style( 'rex-gutenberg-css', $custom_css );
351 }
352 }
353
354
355 /**
356 * Plugin activation ajax
357 */
358 public function plugin_install_success() {
359
360 if ( ! current_user_can( 'manage_options' ) ) {
361 wp_send_json_error( array(
362 'message' => __('You are not authorize to activate plugins.', 'wpfnl')
363 ) );
364 }
365
366 if ( ! check_ajax_referer( 'wpfnl_activate_plugin_nonce', 'security', false ) ) {
367 $response_data = array( 'message' => __('Nonce verification failed', 'wpfnl') );
368 wp_send_json_error( $response_data );
369 }
370
371 \wp_clean_plugins_cache();
372 $plugin_init = ( isset( $_POST['plugin_init'] ) ) ? esc_attr( $_POST['plugin_init'] ) : '';
373 $activate = \activate_plugin( $plugin_init, '', false, true );
374
375 if ( is_wp_error( $activate ) ) {
376 wp_send_json_error(
377 array(
378 'success' => false,
379 'message' => $activate->get_error_message(),
380 )
381 );
382 }
383
384 wp_send_json_success(
385 array(
386 'message' => __('Plugin activated successfully.', 'wpfnl'),
387 )
388 );
389 }
390
391
392 public function init_hooks() {
393 $this->loader->add_action( 'init', $this, 'load_admin_modules' );
394 $shortcode = new Wpfnl_Shortcodes();
395 add_action( 'init', array( $shortcode, 'init') );
396 }
397
398 public function init_rest_api() {
399 $this->loader->add_action( 'init', $this, 'load_rest_api' );
400 }
401
402 public function load_admin_modules() {
403 $this->module_manager = new Module_Manager();
404 }
405
406 public function load_rest_api() {
407 Server::instance()->init();
408 }
409
410
411 /**
412 * Load plugin classes
413 */
414 public function load_plugin() {
415 $this->batch = new Wpfnl_Batch();
416 $this->init();
417
418 do_action( 'wpfunnels/init' );
419 }
420
421 public function init() {
422 $this->admin = new Admin( $this->get_plugin_name(), $this->get_version() );
423 $this->frontend = Wpfnl_Public::getInstance();
424 $this->cpt = new CPT();
425 $this->menu = new Menu();
426 $this->funnel_store = new Funnel_Store();
427 $this->step_store = new Step_Store();
428 $this->template_manager = new TemplateLibrary\Manager();
429
430 $this->widget_manager = Widget_Manager::getInstance()->init();
431 $this->page_templates = new PageTemplates\Manager();
432 $this->admin_notice = new Notice();
433 $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');
434 $this->setup_reminder_banner = new SetupReminderBanner();
435 $this->order_bump_actions = new Wpfnl_Order_Bump_Action();
436 $this->testimonial_actions = new Wpfnl_Testimonial_Action();
437 $this->meta = new Wpfnl_Default_Meta();
438 $this->shortcodes = Wpfnl_Shortcodes::getInstance()->init();
439 $this->ajax_handler = new Ajax_Handler();
440 $this->optin_field = new OptinField();
441 $this->log = Wpfnl_Logger::getInstance()->initialize_logging();
442 $this->compatibility = new Wpfnl_Compatibility();
443
444 $this->stat_hooks_handler = new StatHookHandler();
445 $this->optin_recorder = new OptinRecorder();
446
447 // Initialize Payment Gateway Factory
448 if ( Wpfnl_functions::is_wc_active() ) {
449 Gateway\Payment_Gateways_Factory::getInstance();
450
451 // Initialize Offer Module (upsell/downsell) only if Pro is not active
452 // When Pro is active, it handles offer functionality
453 if ( ! Wpfnl_functions::is_wpfnl_pro_activated() ) {
454 new Offer\Wpfnl_Offer();
455 }
456
457 // Store Checkout: override the WooCommerce default checkout with the
458 // WPFunnels Store Checkout step (only when a step is configured).
459 require_once WPFNL_DIR . 'includes/core/woocommerce/class-wpfnl-store-checkout-override.php';
460 \WPFunnels\WooCommerce\Wpfnl_Store_Checkout_Override::getInstance();
461 }
462
463 $this->export_funnel = Wpfnl_Export::getInstance()->init_ajax();
464 $this->import_funnel = new Wpfnl_Import();
465
466 $this->reporting = Reporting::get_instance();
467 $this->reporting->init();
468
469 // AI copilot module: settings migration + conversation tables.
470 \WPFunnels\AI\AIInit::init();
471
472 // Tool layer: WordPress Abilities (always, when available) + the MCP
473 // server for external agents (gated on the `_wpfnl_mcp_enabled` option).
474 // Ability registration must NOT depend on that option — the in-plugin
475 // AI copilot resolves its own tools through the same registry
476 // (ToolGateway -> wp_get_abilities()), so turning off the external
477 // MCP endpoint would otherwise silently leave the copilot with zero
478 // tools to call.
479 if ( \WPFunnels\MCP\MCPInit::abilitiesApiAvailable() ) {
480 $expose_mcp_server = 'no' !== get_option( '_wpfnl_mcp_enabled', 'yes' );
481 ( new \WPFunnels\MCP\MCPInit() )->init( $expose_mcp_server );
482 }
483
484 Wpfnl_Activator::init();
485 }
486
487
488
489 /**
490 * Load the required dependencies for this plugin.
491 *
492 * Include the following files that make up the plugin:
493 *
494 * - Wpfnl_Loader. Orchestrates the hooks of the plugin.
495 * - Wpfnl_i18n. Defines internationalization functionality.
496 * - Wpfnl_Admin. Defines all hooks for the admin area.
497 * - Wpfnl_Public. Defines all hooks for the public side of the site.
498 *
499 * Create an instance of the loader which will be used to register the hooks
500 * with WordPress.
501 *
502 * @since 1.0.0
503 * @access private
504 */
505 private function load_dependencies()
506 {
507
508 /**
509 * Require the action scheduler
510 */
511 require_once plugin_dir_path(dirname(__FILE__)) . 'vendor/woocommerce/action-scheduler/action-scheduler.php';
512
513 /**
514 * The class responsible for auto loading all files of the
515 * core plugin.
516 */
517 require_once plugin_dir_path(dirname(__FILE__)) . 'vendor/autoload.php';
518
519 /**
520 * The class responsible for orchestrating the actions and filters of the
521 * core plugin.
522 */
523 require_once plugin_dir_path(dirname(__FILE__)) . 'includes/utils/class-wpfnl-loader.php';
524
525 /**
526 * The class responsible for defining internationalization functionality
527 * of the plugin.
528 */
529 require_once plugin_dir_path(dirname(__FILE__)) . 'includes/utils/class-wpfnl-i18n.php';
530
531 /**
532 * The class responsible for defining all actions that occur in the admin area.
533 */
534 require_once plugin_dir_path(dirname(__FILE__)) . 'admin/class-wpfnl-admin.php';
535
536 /**
537 * The class responsible for defining all actions that occur in the public-facing
538 * side of the site.
539 */
540 require_once plugin_dir_path(dirname(__FILE__)) . 'public/class-wpfnl-public.php';
541
542 /**
543 * Require action scheduler for crm
544 */
545 //require_once plugin_dir_path(dirname(__FILE__)) . 'packages/action-scheduler/action-scheduler.php';
546
547 $this->loader = new Wpfnl_Loader();
548 }
549
550
551 /**
552 * After pro plugin init action
553 */
554 public function after_pro_plugin_init() {
555
556 if ( ! is_admin() ) {
557 return;
558 }
559
560 if ( version_compare( WPFNL_PRO_VERSION, WPFNL_PRO_REQUIRED_VERSION, '<' ) ) {
561 add_action( 'admin_notices', array( $this, 'required_wpf_pro_notice' ) );
562 add_action( 'after_plugin_row_'. WPFNL_BASE, 'wpfnl_pro_update_notice_after_plugin_row' );
563 }
564 }
565
566
567 /**
568 * Required pro plugin notice
569 */
570 public function required_wpf_pro_notice() {
571 $class = 'notice notice-error';
572 $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
573 printf( '<div class="%1$s"><p>%2$s</p></div>', $class, $message );
574 }
575
576
577 /**
578 * Show pro dependency notice
579 * after plugin row
580 */
581 public function wpfnl_pro_update_notice_after_plugin_row() {
582 $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
583 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 );
584 }
585
586
587 /**
588 * Define the locale for this plugin for internationalization.
589 *
590 * Uses the Wpfnl_i18n class in order to set the domain and to register the hook
591 * with WordPress.
592 *
593 * @since 1.0.0
594 * @access private
595 */
596 private function set_locale()
597 {
598 $plugin_i18n = new Wpfnl_i18n();
599
600 $this->loader->add_action('init', $plugin_i18n, 'load_plugin_textdomain');
601
602 }
603
604
605 /**
606 * Run the loader to execute all of the hooks with WordPress.
607 *
608 * @since 1.0.0
609 */
610 public function run()
611 {
612 $this->loader->run();
613 }
614
615
616 /**
617 * The name of the plugin used to uniquely identify it within the context of
618 * WordPress and to define internationalization functionality.
619 *
620 * @since 1.0.0
621 * @return string The name of the plugin.
622 */
623 public function get_plugin_name()
624 {
625 return $this->plugin_name;
626 }
627
628
629 /**
630 * The reference to the class that orchestrates the hooks with the plugin.
631 *
632 * @since 1.0.0
633 * @return Wpfnl_Loader Orchestrates the hooks of the plugin.
634 */
635 public function get_loader()
636 {
637 return $this->loader;
638 }
639
640
641 /**
642 * Retrieve the version number of the plugin.
643 *
644 * @since 1.0.0
645 * @return string The version number of the plugin.
646 */
647 public function get_version()
648 {
649 return $this->version;
650 }
651
652
653 /**
654 * Render admin footer styles
655 */
656 public function admin_footer_style() {
657 echo '<style>
658 .wpfnl-notice {
659 border-left-color: #dba617;
660 }
661 .wpfnl-notice .wpfnl-notice__content {
662 padding: 10px 0;
663 }
664
665 .wpfnl-notice .notice-dismiss {
666 top: 11px;
667 }
668
669 .wpfnl-notice .wpfnl-notice__content > p {
670 font-weight: 600;
671 margin: 0;
672 }
673 .wpfnl-notice .wpfnl-notice__actions {
674 margin-top: 8px;
675 }
676
677 .wpfnl-notice .wpfnl-notice__content .wpfnl-notice-button {
678 height: 36px;
679 line-height: 36px;
680 border-radius: 6px;
681 color: #fff;
682 font-weight: 500;
683 padding: 0 20px;
684 background: #6e42d3;
685 display: inline-block;
686 text-decoration: none;
687 letter-spacing: 0.5px;
688 transition: all 0.3s ease;
689 }
690
691 .wpfnl-notice .wpfnl-notice__content .wpfnl-notice-button:hover {
692 background: #4C25A5;
693 }
694 .wpfnl-notice .wpfnl-notice__content .wpfnl-notice-button .notice-loader {
695 border: 2px solid #8265c5;
696 border-radius: 50%;
697 border-top: 2px solid #fff;
698 width: 10px;
699 height: 10px;
700 animation: spin 0.7s linear infinite;
701 display: none;
702 position: relative;
703 top: 3px;
704 margin-left: 9px;
705 }
706 @-webkit-keyframes spin {
707 0% { -webkit-transform: rotate(0deg); }
708 100% { -webkit-transform: rotate(360deg); }
709 }
710
711 @keyframes spin {
712 0% { transform: rotate(0deg); }
713 100% { transform: rotate(360deg); }
714 }
715 </style>';
716 }
717
718
719 /**
720 * Init setup wizard options
721 */
722 public function init_setup_wizard() {
723 add_action('init', array( $this, 'register_setup_wizard_page' ));
724 add_action('admin_init', array($this, 'admin_redirects'));
725
726 // Register AJAX handlers for setup wizard (needs to be available even when not on wizard page)
727 \WPFunnels\Admin\SetupWizard::register_ajax_handlers();
728 }
729
730
731 /**
732 * Register setup wizard
733 */
734 public function register_setup_wizard_page() {
735 if (!empty($_GET['page']) && 'wpfunnels-setup' == sanitize_text_field( $_GET['page'] )) {
736 add_action('admin_menu', function () {
737 add_dashboard_page('WPFunnels Setup', 'WPFunnels Setup', 'manage_options', 'wpfunnels-setup', function () {
738 return '';
739 });
740 });
741 add_action('current_screen', function () {
742 new SetupWizard();
743 }, 999);
744 }
745 }
746
747
748 /**
749 * Handle redirects to setup/welcome page after install and updates.
750 *
751 * For setup wizard, transient must be present, the user must have access rights, and we must ignore the network/bulk plugin updaters.
752 */
753 public function admin_redirects()
754 {
755 // Setup wizard redirect.
756 if (get_transient('_wpfunnels_activation_redirect')) {
757 $do_redirect = true;
758 // On these pages, or during these events, postpone the redirect.
759 if (wp_doing_ajax() || is_network_admin() || !current_user_can('manage_options')) {
760 $do_redirect = false;
761 }
762
763 if ( $do_redirect ) {
764 delete_transient('_wpfunnels_activation_redirect');
765 $url = admin_url('admin.php?page=wpfunnels-setup');
766 wp_safe_redirect( wp_sanitize_redirect( esc_url_raw( $url ) ) );
767 exit;
768 }
769 }
770 }
771 }
772