PluginProbe
FunnelKit – Funnel Builder for WooCommerce Checkout / trunk
FunnelKit – Funnel Builder for WooCommerce Checkout vtrunk
3.16.0.5 3.16.0.4 3.16.0.3 3.16.0.2 3.16.0 3.16.0.1 3.15.0.9 3.15.0.8 3.0.0.1 3.0.1.1 3.0.2.1 3.1.0.1 3.1.1.1 3.1.2.1 3.10.0.1 3.10.1.1 3.10.2.1 3.11.0.0.1 3.11.0.1.1 3.11.0.2.1 3.11.1.1 3.12.0.0.1 3.12.0.1.1 3.13.0.0.1 3.13.1.0.1 All 219 releases
funnel-builder / funnel-builder.php

funnel-builder.php in FunnelKit – Funnel Builder for WooCommerce Checkout trunk, at funnel-builder.php

584 lines 19.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: FunnelKit Funnel Builder
4 * Plugin URI: https://funnelkit.com/wordpress-funnel-builder/
5 * Description: Create high-converting sales funnels on WordPress that look professional by following a well-guided step-by-step process.
6 * Version: 3.16.0.5
7 * Author: FunnelKit
8 * Author URI: https://funnelkit.com
9 * License: GPLv3 or later
10 * License URI: http://www.gnu.org/licenses/gpl-3.0.html
11 * Text Domain: funnel-builder
12 *
13 * Requires at least: 6.2
14 * Tested up to: 7.1
15 * Requires PHP: 7.4
16 * WooFunnels: true
17 *
18 * Funnel Builder is free software.
19 * You can redistribute it and/or modify it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation, either version 3 of the License, or
21 * any later version.
22 *
23 * Funnel Builder is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with Funnel Builder. If not, see <http://www.gnu.org/licenses/>.
30 */
31
32 defined( 'ABSPATH' ) || exit; // Exit if accessed directly
33
34 if ( ! class_exists( 'WFFN_Core' ) ) {
35
36 /**
37 * Class WFFN_Core
38 */
39 #[AllowDynamicProperties]
40 class WFFN_Core {
41
42 /**
43 * @var null
44 */
45 public static $_instance = null;
46
47 /**
48 * @var array
49 */
50 private static $_registered_entity = array(
51 'active' => array(),
52 'inactive' => array(),
53 );
54
55 /**
56 * @var WFFN_Admin
57 */
58 public $admin;
59
60 public $assets;
61
62 /**
63 * @var WFFN_Steps
64 */
65 public $steps;
66
67 /**
68 * @var WFFN_Substeps
69 */
70 public $substeps;
71 /**
72 * @var WFFN_Data
73 */
74 public $data;
75
76 /**
77 * @var WFFN_Logger
78 */
79 public $logger;
80
81 /**
82 * @var WFFN_Importer
83 */
84 public $import;
85
86 /**
87 * @var WFFN_Remote_Template_Importer
88 */
89 public $remote_importer;
90
91 /**
92 * @var WFFN_Page_Builder_Manager
93 */
94 public $page_builders;
95
96 /**
97 * @var WFFN_Landing_Pages
98 */
99 public $landing_pages;
100
101 /**
102 * @var WFFN_Funnel_Contacts
103 */
104 public $wffn_contacts;
105
106 /**
107 * @var WFFN_Thank_You_WC_Pages
108 */
109 public $thank_you_pages;
110
111 /** @var WFFN_Funnels_DB */
112 public $funnels_db = null;
113
114 /** @var WFFN_Template_Importer */
115 public $importer = null;
116
117 /** @var WFFN_Public */
118 public $public = null;
119
120 /** @var WFFN_WP_User_AutoLogin */
121 public $autologin = null;
122
123 /** @var WFFN_Role_Capability */
124 public $role = null;
125
126 /** @var WFFN_Admin_Notifications */
127 public $admin_notifications = null;
128
129 /**
130 * WFFN_Core constructor.
131 */
132 public function __construct() {
133
134 /**
135 * Load important variables and constants
136 */
137 $this->define_plugin_properties();
138 require_once __DIR__ . '/start.php';
139 require __DIR__ . '/includes/wffn-functions.php';
140 /**
141 * Wire Funnel Builder's own framework classes (subcore/) into the core kernel.
142 * subcore/load.php only registers them onto the kernel's bwf_kernel_* filters --
143 * the core kernel does the actual loading, and only when FB's own dismantled core
144 * is the copy that wins arbitration (a full core carries these classes itself).
145 * subcore/ sits at the FB plugin root, NOT inside the shared woofunnels core:
146 * nothing plugin-specific remains in woofunnels/, and no other FunnelKit plugin
147 * references this folder. Its files are all __DIR__-relative, so it can live
148 * anywhere FB ships it.
149 */
150 require_once __DIR__ . '/subcore/load.php';
151 /**
152 * Transition arbitration: withdraw our dismantled core if an un-dismantled
153 * full core is present, so it wins include_core() below. See
154 * WooFunnel_WFFN::maybe_yield_to_full_core().
155 *
156 * MUST run before the FIRST include_core() of the request. include_core is
157 * triggered by many sibling plugins at assorted plugins_loaded priorities
158 * (some as early as -99, e.g. via a Pro/checkout module), not just our own
159 * -1 below -- and whoever fires it first locks WooFunnel_Loader::$loaded, so
160 * a late withdrawal is a no-op. No sibling calls include_core at file-load
161 * (all are inside plugins_loaded callbacks), so PHP_INT_MIN guarantees we
162 * withdraw first. (Cannot live in register()/file-load: sibling full cores
163 * that register at file-load load AFTER us, so the pool is not yet complete
164 * there; and the automation registers even later, on plugins_loaded:1 -- the
165 * hook force-registers those via file-probe.)
166 */
167 add_action( 'plugins_loaded', array( 'WooFunnel_WFFN', 'maybe_yield_to_full_core' ), PHP_INT_MIN );
168 add_action( 'plugins_loaded', array( 'WooFunnel_Loader', 'include_core' ), - 1 );
169
170 /**
171 * Loads hooks
172 */
173 $this->load_hooks();
174 }
175
176 /**
177 * Defining constants
178 */
179 public function define_plugin_properties() {
180
181 define( 'WFFN_VERSION', '3.16.0.5' );
182 define( 'WFFN_BWF_VERSION', '1.10.12.84' );
183
184 define( 'WFFN_MIN_WC_VERSION', '3.5.0' );
185 define( 'WFFN_MIN_WP_VERSION', '5.4.0' );
186 /**
187 * Lowest Funnel Builder Pro build that pairs with this release. Older Pro
188 * builds keep loading, but features whose code moved out of this plugin
189 * stop working, so an admin notice asks for a Pro update.
190 * Bump on every release that moves or removes code Pro depends on.
191 */
192 define( 'WFFN_MIN_PRO_VERSION', '3.16.0' );
193 define( 'WFFN_DB_VERSION', '4.0.0' );
194 define( 'WFFN_REVIEW_RATING_COUNT', 897 );
195 define( 'WFFN_SLUG', 'wffn' );
196 define( 'WFFN_PLUGIN_FILE', __FILE__ );
197 define( 'WFFN_PLUGIN_DIR', __DIR__ );
198 define( 'WFFN_PLUGIN_URL', untrailingslashit( plugin_dir_url( WFFN_PLUGIN_FILE ) ) );
199 define( 'WFFN_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
200 define( 'WFFN_TEMPLATE_UPLOAD_DIR', $this->get_content_dir() . '/wffn_templates/' );
201 ( defined( 'WFFN_IS_DEV' ) && true === WFFN_IS_DEV ) ? define( 'WFFN_VERSION_DEV', time() ) : define( 'WFFN_VERSION_DEV', WFFN_VERSION );
202 ( ! defined( 'WFFN_REACT_ENVIRONMENT' ) ) ? define( 'WFFN_REACT_ENVIRONMENT', 1 ) : '';
203 }
204
205 public function get_content_dir() {
206 return wp_upload_dir()['basedir'];
207 }
208
209 /**
210 * Load classes on plugins_loaded hook
211 */
212 public function load_hooks() {
213 add_action( 'plugins_loaded', array( $this, 'load_classes' ), 1 );
214 add_action( 'plugins_loaded', array( $this, 'register_classes' ), 1 );
215
216 register_activation_hook( __FILE__, array( $this, 'plugin_activation_hook' ) );
217
218 add_action( 'activated_plugin', array( $this, 'on_activated_plugin' ) );
219
220 if ( ! class_exists( 'WFACP_Core' ) ) {
221
222 require __DIR__ . '/modules/checkouts/woofunnels-aero-checkout-lite.php';
223 }
224 if ( ! class_exists( 'WFOPP_Core' ) ) {
225 require __DIR__ . '/modules/optins/woofunnels-optins.php';
226 }
227 add_action( 'plugins_loaded', array( $this, 'init_oxygen' ), 10 );
228 add_action( 'wp_loaded', array( $this, 'load_divi_importer' ), 150 );
229 add_action( 'activated_plugin', array( $this, 'check_activation' ) );
230
231 // Define a constant for the plugin file, if not already defined.
232 define( 'FUNNELKIT_BRICKS_INTEGRATION_FILE', __DIR__ . '/includes/bricks-builder/' );
233 // Require the class file for Funnelkit Bricks Integration.
234 require_once __DIR__ . '/includes/bricks-builder/includes/class-bricks-integration.php';
235 }
236
237 /**
238 *
239 */
240 public function load_classes() {
241
242 try {
243 /**
244 * Loads all the admin
245 */
246 $this->load_autoloader();
247 $this->load_admin();
248 $this->load_includes();
249 $this->load_modules();
250 $this->load_steps();
251 $this->load_commons();
252 $this->load_analytics();
253
254 /**
255 * Deferred activation hook: fires only after all classes are
256 * loaded, unlike activated_plugin.
257 */
258 $activated_plugin = get_transient( 'wffn_activated_plugin' );
259 if ( $activated_plugin ) {
260 delete_transient( 'wffn_activated_plugin' );
261 do_action( 'wffn_activated_plugin', $activated_plugin );
262 }
263 } catch ( Exception |Error $e ) {
264 // do nothing here
265 }
266 }
267
268 /**
269 * Loads the admin
270 */
271 public function load_admin() {
272 include_once __DIR__ . '/admin/class-wffn-admin.php';
273 include_once __DIR__ . '/admin/class-bwf-admin-breadcrumbs.php';
274 include_once __DIR__ . '/admin/class-bwf-admin-settings.php';
275 include_once __DIR__ . '/admin/class-wffn-page-builder-manager.php';
276 include_once __DIR__ . '/admin/class-wffn-admin-notifications.php';
277 include_once __DIR__ . '/admin/rest-api/class-wffn-rest-funnels.php';
278 include_once __DIR__ . '/admin/rest-api/class-wffn-rest-steps.php';
279 include_once __DIR__ . '/admin/rest-api/class-wffn-rest-substeps.php';
280 include_once __DIR__ . '/admin/rest-api/class-wffn-rest-funnel-settings.php';
281 include_once __DIR__ . '/admin/rest-api/class-wffn-api-update-user-preference.php';
282 include_once __DIR__ . '/admin/rest-api/class-wffn-rest-tools.php';
283 include_once __DIR__ . '/admin/rest-api/class-wffn-rest-funnel-canvas.php';
284 include_once __DIR__ . '/admin/rest-api/class-wffn-rest-user-preferences.php';
285 include_once __DIR__ . '/admin/rest-api/class-wffn-rest-notifications.php';
286 include_once __DIR__ . '/admin/rest-api/class-wffn-rest-get-recipes.php';
287 include_once __DIR__ . '/admin/rest-api/class-wffn-rest-setup.php';
288 include_once __DIR__ . '/admin/rest-api/class-wffn-rest-store-checkout.php';
289 include_once __DIR__ . '/admin/rest-api/class-wffn-rest-funnel-modules.php';
290 include_once __DIR__ . '/admin/rest-api-helpers/class-wffn-rest-api-helpers.php';
291 include_once __DIR__ . '/admin/rest-api/class-wffn-rest-optin-api-endpoint.php';
292 include_once __DIR__ . '/admin/rest-api/class-wffn-rest-checkout-api-endpoint.php';
293 include_once __DIR__ . '/admin/rest-api/class-wffn-rest-wizard.php';
294 include_once __DIR__ . '/admin/rest-api/class-wffn-funnel-contacts.php';
295 include_once __DIR__ . '/admin/rest-api/class-wffn-funnel-orders.php';
296 include_once __DIR__ . '/admin/rest-api/class-wffn-rest-api-dashboard-endpoint.php';
297 require_once __DIR__ . '/admin/rest-api/class-wffn-api-send-test-notification.php';
298
299 /*
300 * Order Bump Preview
301 */
302
303 include_once __DIR__ . '/admin/rest-api/class-wfob-bump-rest-api.php';
304
305 /***Global settings*/
306
307 include_once __DIR__ . '/admin/rest-api/class-wffn-rest-global-settings.php';
308
309 /**Global Header */
310 include_once __DIR__ . '/admin/includes/class-wffn-header.php';
311
312 /** JS translations chunk combiner */
313 include_once __DIR__ . '/admin/class-wffn-translations.php';
314 WFFN_Translations::get_instance();
315 }
316
317 /**
318 * Load includes folder
319 */
320 public function load_includes() {
321
322 require __DIR__ . '/includes/class-wffn-logger.php';
323 require __DIR__ . '/includes/class-wffn-session-handler.php';
324 require __DIR__ . '/includes/class-wffn-data.php';
325 require __DIR__ . '/includes/class-wffn-funnels-db.php';
326 require __DIR__ . '/includes/class-wffn-public.php';
327 require __DIR__ . '/includes/class-wffn-funnel.php';
328 require __DIR__ . '/includes/class-wffn-woofunnels-support.php';
329 require __DIR__ . '/merge-tags/class-bwf-contact-tags.php';
330 }
331
332 /**
333 * Include Modules (Landing & thankyou)
334 */
335 public function load_modules() {
336 require __DIR__ . '/includes/class-wffn-module-common.php';
337 require __DIR__ . '/modules/landing-pages/class-wffn-landing-pages.php';
338 require __DIR__ . '/modules/thankyou-pages/class-wffn-thank-you-wc-pages.php';
339 do_action( 'wffn_core_modules_loaded' );
340 }
341
342 /**
343 * Include steps and substeps
344 */
345 public function load_steps() {
346 require __DIR__ . '/includes/class-wffn-step-base.php';
347 require __DIR__ . '/includes/class-wffn-step.php';
348 require __DIR__ . '/includes/class-wffn-steps.php';
349 require __DIR__ . '/includes/class-wffn-substep.php';
350 require __DIR__ . '/includes/class-wffn-substeps.php';
351 }
352
353 /**
354 * Includes common functions.
355 */
356 public function load_commons() {
357
358 require __DIR__ . '/includes/class-wffn-common.php';
359
360 require __DIR__ . '/importer/interface-import-export.php';
361 require __DIR__ . '/importer/class-wffn-template-importer.php';
362 require __DIR__ . '/importer/class-wffn-background-importer.php';
363 require __DIR__ . '/admin/db/wffn-updater-functions.php';
364
365 include_once __DIR__ . '/admin/class-wffn-importer.php';
366
367 $response = WFFN_Common::check_builder_status( 'elementor' );
368 if ( true === $response['found'] && empty( $response['error'] ) ) {
369 require __DIR__ . '/importer/class-wffn-elementor-importer.php';
370 }
371
372 require __DIR__ . '/importer/class-wffn-wp-editor-importer.php';
373 require __DIR__ . '/compatibilities/class-wffn-plugin-compatibilities.php';
374 require __DIR__ . '/includes/class-wffn-conversion-tracking-migrator.php';
375 WFFN_Common::init();
376 }
377
378
379 public function load_divi_importer() {
380
381 try {
382 $response = WFFN_Common::check_builder_status( 'divi' );
383 if ( true === $response['found'] && empty( $response['error'] ) ) {
384 require __DIR__ . '/importer/class-wffn-divi-importer.php';
385 require __DIR__ . '/importer/class-wffn-divi5-importer.php';
386 }
387 $response = WFFN_Common::check_builder_status( 'oxy' );
388 if ( true === $response['found'] && empty( $response['error'] ) ) {
389 require __DIR__ . '/importer/class-wffn-oxygen-importer.php';
390 }
391 require __DIR__ . '/importer/class-wffn-gutenberg-importer.php';
392 } catch ( Exception $e ) {
393 // do nothing here
394 }
395 }
396
397 public function load_analytics() {
398 if ( class_exists( 'WFACP_Core' ) && wffn_is_wc_active() && ! class_exists( 'WFACP_Contacts_Analytics' ) ) {
399 require_once __DIR__ . '/contact-analytics/class-wfacp-contacts-analytics.php';
400 }
401 if ( class_exists( 'WFOPP_Core' ) && ! class_exists( 'WFFN_Optin_Contacts_Analytics' ) ) {
402 require_once __DIR__ . '/contact-analytics/class-wffn-optin-contacts-analytics.php';
403 }
404
405 // Tracking system will be lazy-loaded on demand via autoloader
406 // No need to load classes here - they'll be loaded when tracking data is collected
407 }
408
409 /**
410 * @return WFFN_Core|null
411 */
412 public static function get_instance() {
413 if ( null === self::$_instance ) {
414 self::$_instance = new self();
415 }
416
417 return self::$_instance;
418 }
419
420
421 /**
422 * Register classes
423 */
424 public function register_classes() {
425
426 try {
427 $load_classes = self::get_registered_class();
428 if ( is_array( $load_classes ) && count( $load_classes ) > 0 ) {
429 foreach ( $load_classes as $access_key => $class ) {
430
431 $this->$access_key = $class::get_instance();
432 }
433 do_action( 'wffn_loaded' );
434 }
435 } catch ( Exception $e ) {
436 // do nothing here
437 }
438 }
439
440 /**
441 * @return mixed
442 */
443 public static function get_registered_class() {
444 return self::$_registered_entity['active'];
445 }
446
447 public static function register( $short_name, $class ) { //phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedParameter
448
449 self::$_registered_entity['active'][ $short_name ] = $class;
450 }
451
452 /**
453 * @return WFFN_Funnels_DB
454 */
455 public function get_dB() {
456 if ( empty( $this->funnels_db ) ) {
457 $class = apply_filters( 'wffn_funnels_db_class', 'WFFN_Funnels_DB' );
458 $this->funnels_db = new $class();
459 }
460
461 return $this->funnels_db;
462 }
463
464 public function plugin_activation_hook() {
465 update_option( 'bwf_needs_rewrite', 'yes', true );
466
467 /** Save the plugin first version when the plugin was activated, if not already present */
468 $first_version = get_option( 'wffn_first_v', '' );
469 if ( empty( $first_version ) ) {
470 update_option( 'wffn_first_v', WFFN_VERSION, false );
471
472 }
473 }
474
475 public function get_plugin_url() {
476 return untrailingslashit( plugin_dir_url( WFFN_PLUGIN_FILE ) );
477 }
478
479 public function load_autoloader() {
480 spl_autoload_register( array( $this, 'autoload' ) );
481 /**
482 * The license classes live in the premium plugin now; the free plugin only
483 * carries inert fallbacks so premium builds released before the relocation
484 * don't fatal. Their autoloader registers once every plugin has finished
485 * booting, so it sits BEHIND every premium loader in the spl queue: the
486 * premium copy always gets the first chance to supply the real classes,
487 * and the fallback fires only when nothing else has defined them.
488 */
489 add_action( 'plugins_loaded', array( $this, 'load_license_fallback_autoloader' ), 9999 );
490 }
491
492 public function load_license_fallback_autoloader() {
493 spl_autoload_register( array( $this, 'autoload_license_fallbacks' ) );
494 }
495
496 public function autoload_license_fallbacks( $class_name ) {
497 $license_classes = array( 'woofunnels_licenses', 'woofunnels_license_check', 'woofunnels_license_controller' );
498 if ( in_array( strtolower( $class_name ), $license_classes, true ) ) {
499 require_once WFFN_PLUGIN_DIR . '/includes/class-woofunnels-licenses.php'; // phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingCustomConstant
500 }
501 }
502
503 public function autoload( $class_name ) {
504 if ( false !== strpos( $class_name, 'WFFN_' ) ) {
505 $filename = basename( 'class-' . $this->slugify_classname( $class_name ) . '.php' );
506 $file_path = WFFN_PLUGIN_DIR . '/includes/' . $filename;
507
508 if ( file_exists( $file_path ) ) {
509 $real_path = realpath( $file_path );
510 $real_includes = realpath( WFFN_PLUGIN_DIR . '/includes/' );
511
512 if ( false !== $real_path && false !== $real_includes && 0 === strpos( $real_path, $real_includes ) ) {
513 require_once $real_path; // phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingCustomConstant
514 }
515 }
516 }
517 }
518
519 /**
520 * Stores a transient on activation so wffn_activated_plugin can fire
521 * later in plugins_loaded, once classes exist.
522 *
523 * @param string $filename Activated plugin filename.
524 */
525 public function on_activated_plugin( $filename ) {
526 if ( '/funnel-builder.php' === substr( $filename, -19 ) ) {
527 set_transient( 'wffn_activated_plugin', $filename );
528 }
529 }
530
531 public function slugify_classname( $class_name ) {
532 $classname = $this->custom_sanitize_title( $class_name );
533 $classname = str_replace( '_', '-', $classname );
534
535 return $classname;
536 }
537
538 private function custom_sanitize_title( $title ) {
539 $title = remove_accents( $title );
540 $title = sanitize_title_with_dashes( $title );
541
542 return $title;
543 }
544
545 public function init_oxygen() {
546 if ( class_exists( 'OxygenElement' ) ) {
547 require_once __DIR__ . '/includes/class-abstract-wffn-oxygen-fields.php';
548 }
549 }
550
551 /**
552 * Added redirection on plugin activation
553 *
554 * @param $plugin
555 */
556 public function check_activation( $plugin ) {
557 if ( $plugin === plugin_basename( WFFN_PLUGIN_FILE ) ) {
558 $pro_first_active = get_option( 'fk_fb_active_date', array() );
559 if ( empty( $pro_first_active ) || ! isset( $pro_first_active['lite'] ) ) {
560 $pro_first_active['lite'] = current_time( 'timestamp' );
561 update_option( 'fk_fb_active_date', $pro_first_active, false );
562 }
563 }
564 if ( ( defined( 'WFFN_PRO_FILE' ) && $plugin === plugin_basename( WFFN_PRO_FILE ) ) || ( defined( 'WFFN_BASIC_FILE' ) && $plugin === plugin_basename( WFFN_BASIC_FILE ) ) ) {
565 $pro_first_active = get_option( 'fk_fb_active_date', array() );
566 if ( empty( $pro_first_active ) || ! isset( $pro_first_active['pro'] ) ) {
567 $pro_first_active['pro'] = current_time( 'timestamp' );
568 update_option( 'fk_fb_active_date', $pro_first_active, false );
569 }
570 }
571 }
572 }
573 }
574 if ( ! function_exists( 'WFFN_Core' ) ) {
575 /**
576 * @return WFFN_Core|null
577 */
578 function WFFN_Core() { //@codingStandardsIgnoreLine
579 return WFFN_Core::get_instance();
580 }
581 }
582
583 $GLOBALS['WFFN_Core'] = WFFN_Core();
584