PluginProbe
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster / 2.6.0
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster v2.6.0
2.6.0 trunk 1.1.0 1.1.4 1.2.1 1.2.2 1.2.3 1.2.5 1.2.9 1.3.1 1.3.2 1.5.0 1.5.1 1.5.4 1.5.7 1.5.8 1.5.9 1.6.2 1.6.5 1.6.8 1.7.2 1.7.4 1.7.5 1.7.9 1.8.1 All 42 releases
sellkit / sellkit.php

sellkit.php in SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster 2.6.0, at sellkit.php

738 lines 16.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: SellKit - Funnel builder and checkout optimizer for WooCommerce to sell more, faster
4 * Plugin URI: https://getsellkit.com/
5 * Description: Build unlimited sales funnels, one-click order bumps and upsells, custom thank you pages, and more. The free version of SellKit also offers a huge round of features to optimize your WooCommerce store: build and style single or multi-step checkout pages with advanced styling options. Add, remove & reorder form fields. Fasten the form submission process with pre-populated form data, Instant form validation, and removing cart page. All this and more is 100% free and for an unlimited number of sites.
6 * Version: 2.6.0
7 * Author: Artbees
8 * Author URI: https://artbees.net
9 * Text Domain: sellkit
10 * License: GPLv2 or later
11 *
12 * @package Sellkit
13 */
14
15 use Sellkit\Admin\Funnel\Funnel;
16 use Sellkit\Admin\Settings\Sellkit_Admin_Settings;
17 use Sellkit\Contact_Segmentation\Conditions;
18 use Sellkit\Contact_Segmentation\Operators;
19 use Sellkit\Core\Install;
20 use Sellkit\Database;
21 use Sellkit\Product_Meta_Key\Sellkit_Product_Meta_Key;
22
23 defined( 'ABSPATH' ) || die();
24
25 /**
26 * Check If sellkit Class exists.
27 *
28 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
29 */
30 if ( ! class_exists( 'Sellkit' ) ) {
31
32 /**
33 * SellKit class.
34 *
35 * @since 1.1.0
36 */
37 class Sellkit {
38
39 /**
40 * Class instance.
41 *
42 * @since 1.1.0
43 * @var Sellkit
44 */
45 private static $instance = null;
46
47 /**
48 * The plugin version number.
49 *
50 * @since 1.1.0
51 *
52 * @access private
53 * @var string
54 */
55 private static $version;
56
57 /**
58 * The plugin basename.
59 *
60 * @since 1.1.0
61 *
62 * @access private
63 * @var string
64 */
65 private static $plugin_basename;
66
67 /**
68 * The plugin name.
69 *
70 * @since 1.1.0
71 *
72 * @access private
73 * @var string
74 */
75 private static $plugin_name;
76
77 /**
78 * The plugin directory.
79 *
80 * @since 1.1.0
81 *
82 * @access private
83 * @var string
84 */
85 public static $plugin_dir;
86
87 /**
88 * The plugin URL.
89 *
90 * @since 1.1.0
91 *
92 * @access private
93 * @var string
94 */
95 private static $plugin_url;
96
97 /**
98 * The plugin assets URL.
99 *
100 * @since 1.1.0
101 * @access public
102 *
103 * @var string
104 */
105 public static $plugin_assets_url;
106
107 /**
108 * Database object.
109 *
110 * @since 1.1.0
111 * @access public
112 * @var Database
113 */
114 public $db;
115
116 /**
117 * Sellkit menus.
118 *
119 * @since 1.1.0
120 * @var array Sellkit menus.
121 */
122 public $sellkit_menus = [
123 'sellkit-dashboard',
124 'sellkit-funnel',
125 'sellkit-settings',
126 'sellkit-checkout',
127 ];
128
129 /**
130 * Has pro plugin or not.
131 *
132 * @since 1.1.0
133 * @var array Checks if has pro or not.
134 */
135 public $has_pro = false;
136
137 /**
138 * Get a class instance.
139 *
140 * @since 1.1.0
141 *
142 * @return Sellkit Class
143 */
144 public static function get_instance() {
145 if ( is_null( self::$instance ) ) {
146 self::$instance = new self();
147 }
148
149 return self::$instance;
150 }
151
152 /**
153 * Class constructor.
154 *
155 * @since 1.1.0
156 */
157 public function __construct() {
158 $this->define_constants();
159
160 $this->load_files( [
161 'db',
162 'functions',
163 'funnel/redirect',
164 'funnel/homepage',
165 'funnel/analytics/data-updater',
166 'global-checkout/class',
167 'funnel/class',
168 'funnel/contacts/base-contacts',
169 'funnel/steps',
170 ] );
171
172 if ( class_exists( 'SitePress' ) ) {
173 $this->load_files([
174 'compatibility/wpml/module',
175 'compatibility/module',
176 ] );
177 }
178
179 $this->db = new Database();
180
181 add_action( 'plugins_loaded', [ $this, 'check_if_has_sellkit_pro' ], 11 );
182 add_action( 'plugins_loaded', [ $this, 'plugins_loaded' ] );
183 add_action( 'init', [ $this, 'init' ] );
184 add_action( 'admin_init', [ $this, 'admin_init' ] );
185 add_action( 'admin_menu', [ $this, 'register_admin_menu' ] );
186 add_action( 'admin_menu', [ $this, 'register_admin_settings_menu' ], 12 );
187
188 // Editor script.
189 add_action( 'elementor/editor/before_enqueue_scripts', [ $this, 'enqueue_editor_script' ] );
190
191 add_action( 'requests-curl.before_request', [ $this, 'actions_before_curl_requests' ], 9999 );
192
193 // Register activation hook.
194 register_activation_hook( __FILE__, array( $this, 'activation' ) );
195
196 if ( ! $this->is_sellkit_screen() ) {
197 return;
198 }
199
200 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_scripts' ] );
201 add_action( 'admin_head', [ $this, 'remove_notice_for_sellkit_pages' ] );
202 add_filter( 'admin_body_class', [ $this, 'sellkit_admin_body_class' ] );
203 }
204
205 /**
206 * Actions before all curl requests.
207 *
208 * @since 1.5.4
209 * @return void
210 */
211 public function actions_before_curl_requests() {
212 session_write_close();
213 }
214
215 /**
216 * Has sellKit pro.
217 *
218 * @since 1.1.0
219 */
220 public function check_if_has_sellkit_pro() {
221 if ( class_exists( 'Sellkit_Pro' ) && function_exists( 'sellkit_pro' ) ) {
222 if ( sellkit_pro()->is_active_sellkit_pro ) {
223 $this->has_pro = true;
224 }
225 }
226 }
227
228 /**
229 * Defines constants used by the plugin.
230 *
231 * @since 1.1.0
232 */
233 protected function define_constants() {
234 $plugin_data = get_file_data( __FILE__, array( 'Plugin Name', 'Version' ), 'sellkit' );
235
236 self::$plugin_basename = plugin_basename( __FILE__ );
237 self::$plugin_name = array_shift( $plugin_data );
238 self::$version = array_shift( $plugin_data );
239 self::$plugin_dir = trailingslashit( plugin_dir_path( __FILE__ ) );
240 self::$plugin_url = trailingslashit( plugin_dir_url( __FILE__ ) );
241 self::$plugin_assets_url = trailingslashit( self::$plugin_url . 'assets' );
242 }
243
244 /**
245 * Plugins loaded.
246 *
247 * @since 1.1.0
248 */
249 public function plugins_loaded() {
250 if ( 'elementor' === $this->page_builder() ) {
251 $this->load_files( [
252 'elementor/class',
253 ] );
254 }
255
256 $this->load_files( [
257 'admin/class-promote-sellkit-pro',
258 'admin/class-promotion-banner',
259 ] );
260
261 if ( class_exists( 'WooCommerce' ) && 'gutenberg' === $this->page_builder() ) {
262 $this->load_files( [
263 'block-editor/helper',
264 'block-editor/class',
265 ] );
266 }
267 }
268
269 /**
270 * Do some stuff on plugin activation.
271 *
272 * @since NEXT
273 * @return void
274 */
275 public function activation() {
276 $this->load_files( [
277 'core/libraries/wp-async-request',
278 'core/libraries/wp-background-process',
279 'core/install',
280 ] );
281
282 Install::check_database_tables();
283
284 if ( empty( sellkit_get_option( 'current_db_version' ) ) ) {
285 sellkit_update_option( 'current_db_version', '1.2.7' ); // @since 1.5.0
286 }
287
288 if ( ! wp_next_scheduled( 'sellkit_update_rfm_score' ) ) {
289 wp_schedule_event( time(), 'twicedaily', 'sellkit_update_rfm_score' );
290 }
291
292 $this->sellkit_installed_time();
293 }
294
295 /**
296 * Saves sellkit installation time.
297 *
298 * @since 1.5.9
299 */
300 private function sellkit_installed_time() {
301 update_option( 'sellkit-installed-time', time() );
302 }
303
304 /**
305 * Adds `sellkit` on the admin body so `.sellkit …` Bootstrap/Reboot selectors apply.
306 * wp-admin sidebar chrome is toned down in `src/style.scss` where Reboot bleeds through.
307 *
308 * @param string $classes Existing body classes.
309 * @return string
310 */
311 public function sellkit_admin_body_class( $classes ) {
312 return "{$classes} sellkit sellkit-admin-screen";
313 }
314
315 /**
316 * Initialize admin.
317 *
318 * @since 1.1.0
319 */
320 public function admin_init() {
321 $this->load_files( [
322 'admin/class-notices',
323 'admin/class',
324 ] );
325
326 $this->load_files( [
327 'admin/utilities',
328 'admin/class-components',
329 'admin/components/class-list-table',
330 'admin/components/class-filters',
331 'admin/components/class-analytics',
332 'admin/class-posts',
333 'admin/settings/class-settings',
334 'admin/class-custom-tables',
335 'admin/funnel/class',
336 'admin/class-global-checkout',
337 'core/install',
338 ] );
339 }
340
341 /**
342 * Initialize.
343 *
344 * @since 1.1.0
345 */
346 public function init() {
347 $this->load_files( [
348 'admin/class-steps',
349 'utilities/functions',
350 'contact-segmentation/class',
351 'dynamic-keywords/class',
352 'core/libraries/wp-async-request',
353 'core/libraries/wp-background-process',
354 'settings/class',
355 'contact-segmentation/rfm/class',
356 'admin/settings/integration/class',
357 ] );
358
359 // Register post types.
360 $post_types = [
361 // 'sellkit-analytics',
362 'sellkit-funnels',
363 ];
364
365 foreach ( $post_types as $post_type ) {
366 register_post_type( $post_type, [
367 'public' => false,
368 ] );
369 }
370
371 // Translations load automatically (WP 4.6+) from wp-content/languages/plugins/ and this plugin's languages directory.
372 }
373
374 /**
375 * Enqueue editor scripts.
376 *
377 * @since 1.1.0
378 * @return void
379 */
380 public function enqueue_editor_script() {
381 wp_enqueue_script(
382 'sellkit-editor',
383 sellkit()->plugin_url() . 'assets/dist/js/editor.min.js',
384 [ 'jquery' ],
385 self::$version,
386 true
387 );
388 }
389
390 /**
391 * Enqueue admin scripts.
392 *
393 * @since 1.1.0
394 */
395 public function enqueue_admin_scripts() {
396 $page = ! empty( $_GET['page'] ) ? $_GET['page'] : ''; // phpcs:ignore
397
398 if ( ! in_array( $page, $this->sellkit_menus, true ) ) {
399 return false;
400 }
401
402 wp_enqueue_editor();
403
404 wp_enqueue_script(
405 'sellkit',
406 sellkit()->plugin_url() . 'assets/dist/admin/sellkit.js',
407 [ 'lodash', 'wp-element', 'wp-i18n', 'wp-util' ],
408 sellkit()->version(),
409 true
410 );
411
412 wp_localize_script(
413 'sellkit',
414 'sellkit',
415 $this->get_localize_data()
416 );
417
418 wp_enqueue_style(
419 'sellkit',
420 sellkit()->plugin_url() . 'assets/dist/admin/sellkit.css',
421 [],
422 sellkit()->version()
423 );
424
425 wp_set_script_translations( 'sellkit', 'sellkit', sellkit()->plugin_dir() . 'languages' );
426 }
427
428 /**
429 * Register admin menu.
430 *
431 * @since 1.1.0
432 * @SuppressWarnings(PHPMD.NPathComplexity)
433 */
434 public function register_admin_menu() {
435 $menu_name = esc_html__( 'Sellkit', 'sellkit' );
436 $initial_page = 'sellkit-dashboard';
437 $submenu = [
438 'sellkit-dashboard' => esc_html__( 'Dashboard', 'sellkit' ),
439 'sellkit-funnel' => esc_html__( 'Funnels', 'sellkit' ),
440 'sellkit-checkout' => esc_html__( 'Global Checkout', 'sellkit' ),
441 ];
442
443 $submenu = apply_filters( 'sellkit_sub_menu', $submenu );
444
445 // Load SVG from disk. wp_remote_get() to the plugin URL often fails on local/SSL sites and yields an empty icon.
446 $icon_path = sellkit()->plugin_dir() . 'assets/img/icons/sellkit-dashboard.svg';
447 $menu_icon = 'dashicons-cart';
448
449 if ( is_readable( $icon_path ) ) {
450 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Reading a bundled asset from the filesystem.
451 $svg_contents = file_get_contents( $icon_path );
452 if ( false !== $svg_contents && '' !== $svg_contents ) {
453 $menu_icon = 'data:image/svg+xml;base64,' . base64_encode( $svg_contents );
454 }
455 }
456
457 add_menu_page(
458 $menu_name,
459 $menu_name,
460 'manage_options',
461 $initial_page,
462 [ $this, 'register_admin_menu_callback' ],
463 $menu_icon,
464 '58.1'
465 );
466
467 foreach ( $submenu as $slug => $title ) {
468 add_submenu_page(
469 $initial_page,
470 "{$menu_name} {$title}",
471 $title,
472 'edit_theme_options',
473 $slug,
474 [ $this, 'register_admin_menu_callback' ]
475 );
476 }
477 }
478
479 /**
480 * Adds settings menu.
481 *
482 * @since 1.1.0
483 */
484 public function register_admin_settings_menu() {
485 add_submenu_page(
486 'sellkit-dashboard',
487 esc_html__( 'Sellkit', 'sellkit' ) . ' ' . esc_html__( 'Settings', 'sellkit' ),
488 esc_html__( 'Settings', 'sellkit' ),
489 'edit_theme_options',
490 'sellkit-settings',
491 [ $this, 'register_admin_menu_callback' ]
492 );
493 }
494
495 /**
496 * Register admin menu callback.
497 *
498 * @since 1.1.0
499 */
500 public function register_admin_menu_callback() {
501 ?>
502 <div id="wrap" class="wrap">
503 <!-- It's required for notices, otherwise WP adds the notices wherever it finds the first heading element. -->
504 <h1></h1>
505 <div id="sellkit-root"></div>
506 </div>
507 <?php
508 }
509
510 /**
511 * Check if in SellKit pages.
512 *
513 * @since 1.1.0
514 *
515 * @return boolean SellKit screen.
516 */
517 private function is_sellkit_screen() {
518 $page = sellkit_htmlspecialchars( INPUT_GET, 'page' );
519
520 return (
521 is_admin() &&
522 isset( $page ) &&
523 strpos( $page, 'sellkit' ) !== false
524 );
525 }
526
527 /**
528 * Get localize data.
529 *
530 * @since 1.1.0
531 *
532 * @return array
533 */
534 public function get_localize_data() {
535 return [
536 'nonce' => wp_create_nonce( 'sellkit' ),
537 'assetsUrl' => self::$plugin_assets_url,
538 'dynamicKeywords' => Sellkit_Dynamic_Keywords::$keywords['contact_segmentation'],
539 'defaultFunnelSteps' => Sellkit_Admin_Steps::get_default_funnel_steps(),
540 'woocommerceSettings' => $this->get_woocommerce_settings_data(),
541 'contactSegmentation' => [
542 'conditionsOperators' => Operators::$condition_operator_names,
543 'operators' => Operators::$names,
544 'conditionsData' => Conditions::$data,
545 'browserLanguages' => Conditions\Browser_Language::browser_languages_array(),
546 ],
547 'adminUrl' => admin_url(),
548 'url' => site_url(),
549 'timezones' => timezone_identifiers_list(),
550 'defaultSettings' => [
551 'defaultTimezone' => get_option( 'timezone_string' ),
552 ],
553 'elementorActivation' => class_exists( 'Elementor\Plugin' ) ? true : false,
554 'funnelsTemplateSource' => Funnel::SELLKIT_FUNNELS_TEMPLATE_SOURCE,
555 'removedContentBoxes' => Sellkit_Admin_Settings::get_removed_content_box(),
556 'sellkitProIsActive' => $this->has_pro,
557 'sellkitProPluginInstalled' => class_exists( 'Sellkit_Pro' ) && function_exists( 'sellkit_pro' ),
558 'sellkitLicensePageUrl' => ( class_exists( 'Sellkit_Pro' ) && function_exists( 'sellkit_pro' ) )
559 ? ( is_multisite() ? network_admin_url( 'admin.php?page=sellkit-license' ) : admin_url( 'admin.php?page=sellkit-license' ) )
560 : '',
561 'wcIsActivated' => $this->has_valid_dependencies(),
562 'activeTheme' => wp_get_theme()->get( 'Name' ),
563 'pageBuilder' => $this->page_builder(),
564 ];
565 }
566
567 /**
568 * Get page builder.
569 *
570 * @since 2.3.0
571 * @return string
572 */
573 public function page_builder() {
574 $default = 'gutenberg';
575
576 if ( class_exists( 'Elementor\Plugin' ) ) {
577 $default = 'elementor';
578 }
579
580 $page_builder = sellkit_get_option( 'page_builder', '' );
581
582 if ( empty( $page_builder ) ) {
583 sellkit_update_option( 'page_builder', $default );
584
585 return $default;
586 }
587
588 return $page_builder;
589 }
590
591 /**
592 * Get woocommerce settings data.
593 *
594 * @since 1.1.0
595 *
596 * @return array|boolean
597 */
598 public function get_woocommerce_settings_data() {
599 if ( ! class_exists( 'WooCommerce' ) ) {
600 return false;
601 }
602
603 return [
604 'currencyFormatNumDecimals' => wc_get_price_decimals(),
605 'currencySymbol' => html_entity_decode( get_woocommerce_currency_symbol() ),
606 'currencyFormatDecimalSep' => wc_get_price_decimal_separator(),
607 'currencyFormatThousandSep' => wc_get_price_thousand_separator(),
608 'currencyPosition' => get_option( 'woocommerce_currency_pos' ),
609 'productDefaultThumbnail' => wc_placeholder_img_src(),
610 ];
611 }
612
613 /**
614 * Remove notices.
615 *
616 * @since 1.1.0
617 */
618 public function remove_notice_for_sellkit_pages() {
619 remove_all_actions( 'admin_notices' );
620 }
621
622 /**
623 * Sellkit dependencies.
624 *
625 * @since 1.1.0
626 */
627 public function has_valid_dependencies() {
628 if ( ! class_exists( 'woocommerce' ) ) {
629 return false;
630 }
631
632 return true;
633 }
634
635 /**
636 * Loads specified PHP files from the plugin includes directory.
637 *
638 * @since 1.1.0
639 *
640 * @param array $file_names The names of the files to be loaded in the includes directory.
641 */
642 public function load_files( $file_names = array() ) {
643
644 foreach ( $file_names as $file_name ) {
645 $path = self::plugin_dir() . 'includes/' . $file_name . '.php';
646
647 if ( file_exists( $path ) ) {
648 require_once $path;
649 }
650 }
651 }
652
653 /**
654 * Returns the version number of the plugin.
655 *
656 * @since 1.1.0
657 *
658 * @return string
659 */
660 public function version() {
661 return self::$version;
662 }
663
664 /**
665 * Returns the plugin basename.
666 *
667 * @since 1.1.0
668 *
669 * @return string
670 */
671 public function plugin_basename() {
672 return self::$plugin_basename;
673 }
674
675 /**
676 * Returns the plugin name.
677 *
678 * @since 1.1.0
679 *
680 * @return string
681 */
682 public function plugin_name() {
683 return self::$plugin_name;
684 }
685
686 /**
687 * Returns the plugin directory.
688 *
689 * @since 1.1.0
690 *
691 * @return string
692 */
693 public function plugin_dir() {
694 return self::$plugin_dir;
695 }
696
697 /**
698 * Returns the plugin URL.
699 *
700 * @since 1.1.0
701 *
702 * @return string
703 */
704 public function plugin_url() {
705 return self::$plugin_url;
706 }
707
708 /**
709 * Returns the plugin assets URL.
710 *
711 * @since 1.1.0
712 *
713 * @return string
714 */
715 public function plugin_assets_url() {
716 return self::$plugin_assets_url;
717 }
718 }
719 }
720
721 if ( ! function_exists( 'sellkit' ) ) {
722 /**
723 * Initialize the Sellkit.
724 *
725 * @since 1.1.0
726 */
727 function sellkit() {
728 return Sellkit::get_instance();
729 }
730 }
731
732 /**
733 * Initialize the Sellkit application.
734 *
735 * @since 1.1.0
736 */
737 sellkit();
738