Completed
Push — master ( 6395bc...9c520e )
by Julien
02:45
created

BetterOptin::instance()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 14
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 6
Bugs 1 Features 1
Metric Value
c 6
b 1
f 1
dl 0
loc 14
rs 9.4285
cc 3
eloc 5
nc 2
nop 0
1
<?php
2
/**
3
 * Better Optin.
4
 *
5
 * @package   BetterOptin
6
 * @author    ThemeAvenue <[email protected]>
7
 * @license   GPL-2.0+
8
 * @link      http://themeavenue.net
9
 * @copyright 2014 ThemeAvenue
10
 *
11
 * @wordpress-plugin
12
 * Plugin Name:       BetterOptin
13
 * Plugin URI:        https://betteropt.in/
14
 * Description:       BetterOptin helps you convert your visitors in subscribers and fill up your mailing lists.
15
 * Version:           2.0.2
16
 * Author:            ThemeAvenue
17
 * Author URI:        https://themeavenue.net
18
 * Text Domain:       betteroptin
19
 * License:           GPL-2.0+
20
 * License URI:       http://www.gnu.org/licenses/gpl-2.0.txt
21
 * Domain Path:       /languages
22
 */
23
24
// If this file is called directly, abort.
25
if ( ! defined( 'WPINC' ) ) {
26
	die;
27
}
28
29
if ( ! class_exists( 'BetterOptin' ) ):
30
31
	/**
32
	 * Main BetterOptin class
33
	 *
34
	 * This class is the one and only instance of the plugin. It is used
35
	 * to load the core and all its components.
36
	 *
37
	 * @since 2.0
38
	 */
39
	final class BetterOptin {
40
41
		/**
42
		 * @var BetterOptin Holds the unique instance of BetterOptin
43
		 * @since 2.0
44
		 */
45
		private static $instance;
46
47
		/**
48
		 * Possible error message.
49
		 *
50
		 * @since 2.0
51
		 * @var null|WP_Error
52
		 */
53
		protected $error = null;
54
55
		/**
56
		 * Instantiate and return the unique BetterOptin object
57
		 *
58
		 * @since     2.0
59
		 * @return object BetterOptin Unique instance of BetterOptin
60
		 */
61
		public static function instance() {
62
63
			if ( ! isset( self::$instance ) && ! ( self::$instance instanceof BetterOptin ) ) {
64
65
				// Instantiate
66
				self::$instance = new BetterOptin;
67
				self::$instance->init();
68
69
70
			}
71
72
			return self::$instance;
73
74
		}
75
76
		/**
77
		 * Instantiate the plugin
78
		 *
79
		 * @since 2.0
80
		 * @return void
81
		 */
82
		private function init() {
83
84
			self::$instance->setup_constants();
85
86
			// Make sure the WordPress version is recent enough
87
			if ( ! self::$instance->are_dependencies_loaded() ) {
88
				self::$instance->add_error( wp_kses_post( sprintf( __( 'BetterOptin cannot load because its dependencies are missing. If you don&#039;t know what this means, please purchase the pro version on %s', 'betteroptin' ), '<a href="https://betteropt.in/?utm_source=plugin&utm_medium=dependencies_nag&utm_campaign=upsell" target="_blank">https://betteropt.in</a>' ) ) );
89
			}
90
91
			// If we have any error, don't load the plugin
92
			if ( is_a( self::$instance->error, 'WP_Error' ) ) {
93
				add_action( 'admin_notices', array( self::$instance, 'display_error' ), 10, 0 );
94
				return;
95
			}
96
97
			self::$instance->setup_database_constants();
98
			self::$instance->includes();
99
			self::$instance->load_providers();
100
101
			if ( is_admin() ) {
102
				self::$instance->includes_admin();
103
			}
104
105
			add_action( 'plugins_loaded', array( self::$instance, 'load_plugin_textdomain' ) );
106
			add_action( 'init', array( self::$instance, 'license_notification' ) );
107
			add_action( 'init', array( self::$instance, 'check_provider_ready' ) );
108
			add_filter( 'pre_set_site_transient_update_plugins', array( self::$instance, 'maybe_disable_wordpress_updates' ) );
109
		}
110
111
		/**
112
		 * Throw error on object clone
113
		 *
114
		 * The whole idea of the singleton design pattern is that there is a single
115
		 * object therefore, we don't want the object to be cloned.
116
		 *
117
		 * @since 2.0
118
		 * @return void
119
		 */
120
		public function __clone() {
121
			// Cloning instances of the class is forbidden
122
			_doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'betteroptin' ), '2.0' );
123
		}
124
125
		/**
126
		 * Disable unserializing of the class
127
		 *
128
		 * @since 2.0
129
		 * @return void
130
		 */
131
		public function __wakeup() {
132
			// Unserializing instances of the class is forbidden
133
			_doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'betteroptin' ), '2.0' );
134
		}
135
136
		/**
137
		 * Setup all plugin constants
138
		 *
139
		 * @since 2.0
140
		 * @return void
141
		 */
142
		private function setup_constants() {
143
			define( 'WPBO_URL', trailingslashit( plugin_dir_url( __FILE__ ) ) );
144
			define( 'WPBO_PATH', trailingslashit( plugin_dir_path( __FILE__ ) ) );
145
			define( 'WPBO_BASENAME', plugin_basename( __FILE__ ) );
146
			define( 'WPBO_PLUGIN_FILE', __FILE__ );
147
			define( 'WPBO_VERSION', '2.0.2' );
148
			define( 'WPBO_DB_VERSION', '1' );
149
		}
150
151
		private function are_dependencies_loaded() {
152
			return is_dir( WPBO_PATH . 'vendor' );
153
		}
154
155
		/**
156
		 * Add error.
157
		 *
158
		 * Add a new error to the WP_Error object
159
		 * and create the object if it doesn't exist yet.
160
		 *
161
		 * @since  2.0
162
		 *
163
		 * @param string $message Error message to add
164
		 *
165
		 * @return void
166
		 */
167
		private function add_error( $message ) {
168
169
			if ( ! is_object( $this->error ) || ! is_a( $this->error, 'WP_Error' ) ) {
170
				$this->error = new WP_Error();
171
			}
172
173
			$this->error->add( 'addon_error', $message );
174
175
		}
176
177
		/**
178
		 * Display error.
179
		 *
180
		 * Get all the error messages and display them
181
		 * in the admin notices.
182
		 *
183
		 * @since  2.0
184
		 * @return void
185
		 */
186
		public function display_error() {
187
			if ( ! is_a( $this->error, 'WP_Error' ) ) {
188
				return;
189
			}
190
			$message = self::$instance->error->get_error_messages(); ?>
191
192
			<div class="error">
193
				<p>
194
					<?php
195
					if ( count( $message ) > 1 ) {
196
						echo '<ul>';
197
						foreach ( $message as $msg ) {
198
							echo "<li>$msg</li>";
199
						}
200
						echo '</li>';
201
					} else {
202
						echo $message[0];
203
					}
204
					?>
205
				</p>
206
			</div>
207
			<?php
208
		}
209
210
		/**
211
		 * Setup the custom database table constants
212
		 *
213
		 * @since 2.0
214
		 * @return void
215
		 */
216
		private function setup_database_constants() {
217
218
			global $wpdb;
219
220
			define( 'wpbo_analytics_table_name', 'wpbo_analytics' );
221
			define( 'wpbo_failsafe_table_name', 'wpbo_failsafe' );
222
			define( 'wpbo_analytics_table', $wpdb->prefix . wpbo_analytics_table_name );
223
			define( 'wpbo_failsafe_table', $wpdb->prefix . wpbo_failsafe_table_name );
224
225
		}
226
227
		/**
228
		 * Include all files used sitewide
229
		 *
230
		 * @since 2.0
231
		 * @return void
232
		 */
233
		private function includes() {
234
235
			if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) {
236
237
				require( WPBO_PATH . 'includes/scripts.php' );
238
				require( WPBO_PATH . 'includes/shortcode.php' );
239
				require( WPBO_PATH . 'includes/functions-templating.php' );
240
				require( WPBO_PATH . 'includes/functions-dummy.php' );
241
242
			}
243
244
			require( WPBO_PATH . 'includes/class-popup.php' );
245
			require( WPBO_PATH . 'includes/functions-post-type.php' );
246
			require( WPBO_PATH . 'includes/functions-analytics.php' );
247
			require( WPBO_PATH . 'includes/functions-failsafe.php' );
248
			require( WPBO_PATH . 'includes/functions-popup.php' );
249
			require( WPBO_PATH . 'includes/functions-misc.php' );
250
			require( WPBO_PATH . 'includes/functions-ajax.php' );
251
252
		}
253
254
		/**
255
		 * Include all files used in admin only
256
		 *
257
		 * @since 2.0
258
		 * @return void
259
		 */
260
		private function includes_admin() {
261
262
			require( WPBO_PATH . 'includes/admin/functions-misc.php' );
263
			require( WPBO_PATH . 'vendor/julien731/wp-dismissible-notices-handler/handler.php' );
264
265
			if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) {
266
				require( WPBO_PATH . 'includes/admin/EDD_SL_Plugin_Updater.php' ); // Load before Titan Framework to override the one bundled with the framework
267
				require( WPBO_PATH . 'includes/admin/class-titan-framework.php' );
268
				require( WPBO_PATH . 'includes/admin/settings/settings-general.php' );
269
				require( WPBO_PATH . 'includes/admin/functions-menu.php' );
270
				require( WPBO_PATH . 'includes/admin/functions-metabox.php' );
271
				require( WPBO_PATH . 'includes/admin/functions-list-table.php' );
272
				require( WPBO_PATH . 'includes/install.php' );
273
			}
274
275
		}
276
277
		/**
278
		 * Load all the providers from the providers directory
279
		 *
280
		 * @since 2.0
281
		 * @return void
282
		 */
283
		private function load_providers() {
284
			require( WPBO_PATH . 'includes/providers/wordpress/load.php' );
285
			require( WPBO_PATH . 'includes/providers/mailchimp/load.php' );
286
			require( WPBO_PATH . 'includes/providers/mailpoet/load.php' );
287
			require( WPBO_PATH . 'includes/providers/aweber/load.php' );
288
		}
289
290
		/**
291
		 * Load the plugin text domain for translation.
292
		 *
293
		 * @since    1.0.0
294
		 */
295
		public function load_plugin_textdomain() {
296
297
			apply_filters( 'plugin_locale', get_locale(), 'betteroptin' );
298
299
			load_plugin_textdomain( 'betteroptin', false, basename( plugin_dir_path( dirname( __FILE__ ) ) ) . '/languages/' );
300
301
		}
302
303
		/**
304
		 * Display an admin notice if license key is missing
305
		 *
306
		 * @since 2.0
307
		 * @return void
308
		 */
309
		public function license_notification() {
310
311
			if ( ! function_exists( 'DNH' ) ) {
312
				return;
313
			}
314
315
			$license = wpbo_get_option( 'license_key', '' );
316
317
			/**
318
			 * Do not show the notice if the license key has already been entered.
319
			 */
320
			if ( ! empty( $license ) ) {
321
				return;
322
			}
323
324
			$license_page = wpbo_get_settings_page_link();
325
326
			dnh_register_notice( 'wpbo_no_license', 'error', sprintf( __( 'You haven&#039;t entered your BetterOptin license key. This means that you will not get automatic updates and you will not get technical support. <a %s>Click here to enter your license key</a>.', 'betteroptin' ), "href='$license_page'" ), array( 'cap' => 'administrator' ) );
327
328
		}
329
330
		/**
331
		 * Make sure a provider is selected for the lead collection
332
		 *
333
		 * @since 2.0
334
		 * @return void
335
		 */
336
		public function check_provider_ready() {
337
338
			if ( ! function_exists( 'DNH' ) ) {
339
				return;
340
			}
341
342
			if ( false !== wpbo_is_provider_ready() ) {
343
				return;
344
			}
345
346
			$license_page = wpbo_get_settings_page_link();
347
348
			dnh_register_notice( 'wpbo_no_provider', 'error', sprintf( __( 'You haven&#039;t selected your provider for catching leads. <strong>BetterOptin will not work until you do so!</strong> <a %s>Click here to select your provider</a>.', 'betteroptin' ), "href='$license_page'" ) );
349
350
		}
351
352
		/**
353
		 * Disable WordPress auto-update if the user has the pro version
354
		 *
355
		 * For pro version, the updates will come directly from our server.
356
		 * With the custom EDD SL Updater updates should only come through https://betteropt.in
357
		 * but just to make sure nobody gets downgraded to the lite version
358
		 * we double check that no update comes from WP.org for BetterOptin.
359
		 *
360
		 * @since 2.0.3
361
		 *
362
		 * @param object $value Auto-update object
363
		 *
364
		 * @return object
365
		 */
366
		public function maybe_disable_wordpress_updates( $value ) {
367
368
			// Get the product license
369
			$license = wpbo_get_option( 'license_key', '' );
370
371
			// If no license is entered we're on the lite version and need WP.org updates
372
			if ( empty( $license ) ) {
373
				return $value;
374
			}
375
376
			// Get the license hash/ID
377
			$key = substr( md5( $license ), 0, 10 );
378
379
			// Try and get the activation status from the transient
380
			// @see TitanFrameworkOptionEddLicense::check()
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
381
			$status = get_transient( "tf_edd_license_status_$key" );
382
383
			if ( false === $status ) {
384
385
				$edd_license = new TitanFrameworkOptionEddLicense( array(
386
					'server'  => esc_url( 'https://betteropt.in' ),
387
					'item_id' => 81877,
388
					'file'    => WPBO_PLUGIN_FILE
389
				), 'me' );
390
391
				$status = $edd_license->check( $license );
392
393
			}
394
395
			// This is a pro version, we make sure no auto-update comes from WP.org
396
			if ( 'valid' === $status && is_object( $value ) && is_array( $value->response ) && array_key_exists( plugin_basename( __FILE__ ), $value->response ) ) {
397
398
				// Remove the download package if it comes from WP.org
399
				if ( false === strpos( $value->response[ plugin_basename( __FILE__ ) ]->url, 'betteropt.in' ) ) {
400
					unset( $value->response[ plugin_basename( __FILE__ ) ] );
401
				}
402
403
			}
404
405
			return $value;
406
407
		}
408
409
	}
410
411
endif;
412
413
/**
414
 * The main function responsible for returning the unique BetterOptin instance
415
 *
416
 * Use this function like you would a global variable, except without needing
417
 * to declare the global.
418
 *
419
 * @since 2.0
420
 * @return object BetterOptin
421
 */
422
function BO() {
423
	return BetterOptin::instance();
424
}
425
426
// Get BetterOptin Running
427
BO();