Passed
Push — master ( 59650c...0b7aa3 )
by Chris
11:04 queued 06:15
created

MonsterInsights_Onboarding_Wizard::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 12
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 21
rs 9.8666
1
<?php
2
/**
3
 * MonsterInsights Onboarding Wizard
4
 *
5
 * @since 7.3
6
 *
7
 * @package MonsterInsights
8
 */
9
10
// Exit if accessed directly.
11
if ( ! defined( 'ABSPATH' ) ) {
12
	exit;
13
}
14
15
/**
16
 * Class MonsterInsights_Dashboard_Widget
17
 */
18
class MonsterInsights_Onboarding_Wizard {
19
20
21
	/**
22
	 * MonsterInsights_Onboarding_Wizard constructor.
23
	 */
24
	public function __construct() {
25
26
		add_action( 'admin_init', array( $this, 'maybe_load_onboarding_wizard' ) );
27
28
		add_action( 'admin_menu', array( $this, 'add_dashboard_page' ) );
29
		add_action( 'network_admin_menu', array( $this, 'add_dashboard_page' ) );
30
31
		add_action( 'wp_ajax_monsterinsights_onboarding_wpforms_install', array(
32
			$this,
33
			'install_and_activate_wpforms',
34
		) );
35
36
		add_action( 'wp_ajax_monsterinsights_onboarding_get_errors', array(
37
			$this,
38
			'get_install_errors',
39
		) );
40
41
		// This will only be called in the Onboarding Wizard context because of previous checks.
42
		add_filter( 'monsterinsights_maybe_authenticate_siteurl', array( $this, 'change_return_url' ) );
43
		add_filter( 'monsterinsights_auth_success_redirect_url', array( $this, 'change_success_url' ) );
44
		add_filter( 'monsterinsights_reauth_success_redirect_url', array( $this, 'change_success_url' ) );
45
46
	}
47
48
	/**
49
	 * Checks if the Wizard should be loaded in current context.
50
	 */
51
	public function maybe_load_onboarding_wizard() {
52
53
		// Check for wizard-specific parameter
54
		// Allow plugins to disable the onboarding wizard
55
		// Check if current user is allowed to save settings.
56
		if ( ! ( isset( $_GET['page'] ) || 'monsterinsights-onboarding' !== $_GET['page'] || apply_filters( 'monsterinsights_enable_onboarding_wizard', true ) || ! current_user_can( 'monsterinsights_save_settings' ) ) ) { // WPCS: CSRF ok, input var ok.
57
			return;
58
		}
59
60
		// Don't load the interface if doing an ajax call.
61
		if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
62
			return;
63
		}
64
65
		set_current_screen();
66
67
		// Remove an action in the Gutenberg plugin ( not core Gutenberg ) which throws an error.
68
		remove_action( 'admin_print_styles', 'gutenberg_block_editor_admin_print_styles' );
69
70
		$this->load_onboarding_wizard();
71
72
	}
73
74
	/**
75
	 * Register page through WordPress's hooks.
76
	 */
77
	public function add_dashboard_page() {
78
		add_dashboard_page( '', '', 'monsterinsights_save_settings', 'monsterinsights-onboarding', '' );
79
	}
80
81
	/**
82
	 * Load the Onboarding Wizard template.
83
	 */
84
	private function load_onboarding_wizard() {
85
86
		$this->enqueue_scripts();
87
88
		$this->onboarding_wizard_header();
89
		$this->onboarding_wizard_content();
90
		$this->onboarding_wizard_footer();
91
92
		exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
93
94
	}
95
96
	/**
97
	 * Load the scripts needed for the Onboarding Wizard.
98
	 */
99
	public function enqueue_scripts() {
100
101
		global $wp_version;
102
		$version_path = monsterinsights_is_pro_version() ? 'pro' : 'lite';
103
		$rtl          = is_rtl() ? '.rtl' : '';
104
		if ( ! defined( 'MONSTERINSIGHTS_LOCAL_WIZARD_JS_URL' ) ) {
105
			wp_enqueue_style( 'monsterinsights-vue-style-vendors', plugins_url( $version_path . '/assets/vue/css/chunk-vendors' . $rtl . '.css', MONSTERINSIGHTS_PLUGIN_FILE ), array(), monsterinsights_get_asset_version() );
106
			wp_enqueue_style( 'monsterinsights-vue-style-common', plugins_url( $version_path . '/assets/vue/css/chunk-common' . $rtl . '.css', MONSTERINSIGHTS_PLUGIN_FILE ), array(), monsterinsights_get_asset_version() );
107
			wp_enqueue_style( 'monsterinsights-vue-style', plugins_url( $version_path . '/assets/vue/css/wizard' . $rtl . '.css', MONSTERINSIGHTS_PLUGIN_FILE ), array(), monsterinsights_get_asset_version() );
108
			wp_enqueue_script( 'monsterinsights-vue-vendors', plugins_url( $version_path . '/assets/vue/js/chunk-vendors.js', MONSTERINSIGHTS_PLUGIN_FILE ), array(), monsterinsights_get_asset_version(), true );
109
			wp_enqueue_script( 'monsterinsights-vue-common', plugins_url( $version_path . '/assets/vue/js/chunk-common.js', MONSTERINSIGHTS_PLUGIN_FILE ), array(), monsterinsights_get_asset_version(), true );
110
			wp_register_script( 'monsterinsights-vue-script', plugins_url( $version_path . '/assets/vue/js/wizard.js', MONSTERINSIGHTS_PLUGIN_FILE ), array(
111
				'monsterinsights-vue-vendors',
112
				'monsterinsights-vue-common',
113
			), monsterinsights_get_asset_version(), true );
114
		} else {
115
			wp_enqueue_script( 'monsterinsights-vue-vendors', MONSTERINSIGHTS_LOCAL_VENDORS_JS_URL, array(), monsterinsights_get_asset_version(), true );
0 ignored issues
show
Bug introduced by
The constant MONSTERINSIGHTS_LOCAL_VENDORS_JS_URL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
116
			wp_enqueue_script( 'monsterinsights-vue-common', MONSTERINSIGHTS_LOCAL_COMMON_JS_URL, array(), monsterinsights_get_asset_version(), true );
0 ignored issues
show
Bug introduced by
The constant MONSTERINSIGHTS_LOCAL_COMMON_JS_URL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
117
			wp_register_script( 'monsterinsights-vue-script', MONSTERINSIGHTS_LOCAL_WIZARD_JS_URL, array(
0 ignored issues
show
Bug introduced by
The constant MONSTERINSIGHTS_LOCAL_WIZARD_JS_URL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
118
				'monsterinsights-vue-vendors',
119
				'monsterinsights-vue-common',
120
			), monsterinsights_get_asset_version(), true );
121
		}
122
		wp_enqueue_script( 'monsterinsights-vue-script' );
123
124
		$settings_page = is_network_admin() ? add_query_arg( 'page', 'monsterinsights_network', network_admin_url( 'admin.php' ) ) : add_query_arg( 'page', 'monsterinsights_settings', admin_url( 'admin.php' ) );
125
126
		wp_localize_script(
127
			'monsterinsights-vue-script',
128
			'monsterinsights',
129
			array(
130
				'ajax'                 => add_query_arg( 'page', 'monsterinsights-onboarding', admin_url( 'admin-ajax.php' ) ),
131
				'nonce'                => wp_create_nonce( 'mi-admin-nonce' ),
132
				'network'              => is_network_admin(),
133
				'translations'         => wp_get_jed_locale_data( 'mi-vue-app' ),
134
				'assets'               => plugins_url( $version_path . '/assets/vue', MONSTERINSIGHTS_PLUGIN_FILE ),
135
				'roles'                => monsterinsights_get_roles(),
136
				'roles_manage_options' => monsterinsights_get_manage_options_roles(),
137
				'wizard_url'           => is_network_admin() ? network_admin_url( 'index.php?page=monsterinsights-onboarding' ) : admin_url( 'index.php?page=monsterinsights-onboarding' ),
138
				'is_eu'                => $this->should_include_eu_addon(),
139
				'activate_nonce'       => wp_create_nonce( 'monsterinsights-activate' ),
140
				'install_nonce'        => wp_create_nonce( 'monsterinsights-install' ),
141
				'exit_url'             => $settings_page,
142
				'shareasale_id'        => monsterinsights_get_shareasale_id(),
143
				'shareasale_url'       => monsterinsights_get_shareasale_url( monsterinsights_get_shareasale_id(), '' ),
144
				// Used to add notices for future deprecations.
145
				'versions'             => array(
146
					'php_version'          => phpversion(),
147
					'php_version_below_54' => apply_filters( 'monsterinsights_temporarily_hide_php_52_and_53_upgrade_warnings', version_compare( phpversion(), '5.4', '<' ) ),
148
					'php_version_below_56' => apply_filters( 'monsterinsights_temporarily_hide_php_54_and_55_upgrade_warnings', version_compare( phpversion(), '5.6', '<' ) ),
149
					'php_update_link'      => monsterinsights_get_url( 'settings-notice', 'settings-page', 'https://www.monsterinsights.com/docs/update-php/' ),
150
					'wp_version'           => $wp_version,
151
					'wp_version_below_46'  => version_compare( $wp_version, '4.6', '<' ),
152
					'wp_version_below_49'  => version_compare( $wp_version, '4.9', '<' ),
153
					'wp_update_link'       => monsterinsights_get_url( 'settings-notice', 'settings-page', 'https://www.monsterinsights.com/docs/update-wordpress/' ),
154
				),
155
				'plugin_version'       => MONSTERINSIGHTS_VERSION,
156
				'migrated'             => monsterinsights_get_option( 'gadwp_migrated', false ),
157
			)
158
		);
159
160
	}
161
162
	/**
163
	 * Outputs the simplified header used for the Onboarding Wizard.
164
	 */
165
	public function onboarding_wizard_header() {
166
		?>
167
		<!DOCTYPE html>
168
		<html <?php language_attributes(); ?>>
169
		<head>
170
			<meta name="viewport" content="width=device-width"/>
171
			<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
172
			<title><?php esc_html_e( 'MonsterInsights &rsaquo; Onboarding Wizard', 'google-analytics-for-wordpress' ); ?></title>
173
			<?php do_action( 'admin_print_styles' ); ?>
174
			<?php do_action( 'admin_print_scripts' ); ?>
175
			<?php do_action( 'admin_head' ); ?>
176
		</head>
177
		<body class="monsterinsights-onboarding">
178
		<?php
179
	}
180
181
	/**
182
	 * Outputs the content of the current step.
183
	 */
184
	public function onboarding_wizard_content() {
185
		$admin_url = is_network_admin() ? network_admin_url() : admin_url();
186
187
		monsterinsights_settings_error_page( 'monsterinsights-vue-onboarding-wizard', '<a href="' . $admin_url . '">' . esc_html__( 'Return to Dashboard', 'google-analytics-for-wordpress' ) . '</a>' );
188
		monsterinsights_settings_inline_js();
189
	}
190
191
	/**
192
	 * Outputs the simplified footer used for the Onboarding Wizard.
193
	 */
194
	public function onboarding_wizard_footer() {
195
		?>
196
		<?php wp_print_scripts( 'monsterinsights-vue-script' ); ?>
197
		</body>
198
		</html>
199
		<?php
200
	}
201
202
	/**
203
	 * Check if we should suggest the EU Compliance addon by attempting to determine the website's location.
204
	 *
205
	 * @return bool
206
	 */
207
	public function should_include_eu_addon() {
208
209
		// Is WooCommerce installed and the countries class installed.
210
		if ( class_exists( 'WooCommerce' ) && class_exists( 'WC_Countries' ) ) {
211
			$wc_countries = new WC_Countries();
0 ignored issues
show
Bug introduced by
The type WC_Countries was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
212
			$country      = $wc_countries->get_base_country();
213
			$continent    = $wc_countries->get_continent_code_for_country( $country );
214
215
			if ( 'EU' === $continent ) {
216
				return true;
217
			}
218
		}
219
220
		// Is EDD installed?
221
		if ( class_exists( 'Easy_Digital_Downloads' ) && function_exists( 'edd_get_shop_country' ) ) {
222
			$country      = strtoupper( edd_get_shop_country() );
223
			$eu_countries = self::get_eu_countries();
224
225
			// Check if the country code is in the list of EU countries we have stored.
226
			if ( in_array( $country, $eu_countries, true ) ) {
227
				return true;
228
			}
229
		}
230
231
		// If no store installed, check the timezone setting.
232
		$timezone_string = get_option( 'timezone_string' );
233
		if ( 0 === strpos( strtolower( $timezone_string ), 'europe' ) ) {
0 ignored issues
show
Bug introduced by
It seems like $timezone_string can also be of type false; however, parameter $str of strtolower() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

233
		if ( 0 === strpos( strtolower( /** @scrutinizer ignore-type */ $timezone_string ), 'europe' ) ) {
Loading history...
234
			// If the timezone is set to Europe, assume the website is based in Europe.
235
			return true;
236
		}
237
238
		return false;
239
240
	}
241
242
	/**
243
	 * Install WPForms lite and activate it, prevent initial setup step.
244
	 *
245
	 * @return null|string
246
	 */
247
	public function install_and_activate_wpforms() {
248
249
		check_ajax_referer( 'monsterinsights-install', 'nonce' );
250
251
		if ( ! current_user_can( 'install_plugins' ) ) {
252
			wp_send_json( array(
253
				'message' => esc_html__( 'You are not allowed to install plugins', 'google-analytics-for-wordpress' ),
254
			) );
255
		}
256
257
		include_once ABSPATH . 'wp-admin/includes/plugin-install.php';
258
259
		$api = plugins_api( 'plugin_information', array(
260
			'slug'   => 'wpforms-lite',
261
			'fields' => array(
262
				'short_description' => false,
263
				'sections'          => false,
264
				'requires'          => false,
265
				'rating'            => false,
266
				'ratings'           => false,
267
				'downloaded'        => false,
268
				'last_updated'      => false,
269
				'added'             => false,
270
				'tags'              => false,
271
				'compatibility'     => false,
272
				'homepage'          => false,
273
				'donate_link'       => false,
274
			),
275
		) );
276
277
		if ( is_wp_error( $api ) ) {
278
			return $api->get_error_message();
279
		}
280
281
		$download_url = $api->download_link;
282
283
		$method = '';
284
		$url    = is_network_admin() ? add_query_arg( 'page', 'monsterinsights_network', network_admin_url( 'admin.php' ) ) : add_query_arg( 'page', 'monsterinsights_settings', admin_url( 'admin.php' ) );
285
		$url    = esc_url( $url );
286
287
		ob_start();
288
		if ( false === ( $creds = request_filesystem_credentials( $url, $method, false, false, null ) ) ) {
289
			$form = ob_get_clean();
290
291
			wp_send_json( array( 'form' => $form ) );
292
		}
293
294
		// If we are not authenticated, make it happen now.
295
		if ( ! WP_Filesystem( $creds ) ) {
296
			ob_start();
297
			request_filesystem_credentials( $url, $method, true, false, null );
298
			$form = ob_get_clean();
299
300
			wp_send_json( array( 'form' => $form ) );
301
302
		}
303
304
		// We do not need any extra credentials if we have gotten this far, so let's install the plugin.
305
		require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
306
		$base = MonsterInsights();
307
		require_once plugin_dir_path( $base->file ) . '/includes/admin/licensing/skin.php';
308
309
		// Create the plugin upgrader with our custom skin.
310
		$installer = new Plugin_Upgrader( new MonsterInsights_Skin() );
311
		$installer->install( $download_url );
312
313
		// Flush the cache and return the newly installed plugin basename.
314
		wp_cache_flush();
315
		if ( $installer->plugin_info() ) {
316
			// Set this option to prevent WP Forms setup from showing up after the wizard completes.
317
			update_option( 'wpforms_activation_redirect', true );
318
			activate_plugin( $installer->plugin_info() );
319
			wp_send_json_success();
320
		}
321
322
		wp_die();
323
324
	}
325
326
	/**
327
	 * Update the redirect url so the user returns to the Onboarding Wizard after auth.
328
	 *
329
	 * @param string $siteurl The url to which the user is redirected for auth.
330
	 *
331
	 * @return mixed
332
	 */
333
	public function change_return_url( $siteurl ) {
334
335
		$url       = wp_parse_url( $siteurl );
336
		$admin_url = is_network_admin() ? network_admin_url() : admin_url();
337
338
		if ( isset( $url['query'] ) ) {
339
340
			parse_str( $url['query'], $parameters );
341
342
			$parameters['return'] = rawurlencode( add_query_arg( array(
343
				'page' => 'monsterinsights-onboarding',
344
			), $admin_url ) );
345
346
			$siteurl = str_replace( $url['query'], '', $siteurl );
347
348
			$siteurl = add_query_arg( $parameters, $siteurl );
349
350
			$siteurl .= '#/authenticate';
351
352
		}
353
354
		return $siteurl;
355
356
	}
357
358
	/**
359
	 * Update the success redirect URL so if all is well we get to the next step.
360
	 *
361
	 * @param string $siteurl The url to which the user is redirected after a successful auth.
362
	 *
363
	 * @return mixed
364
	 */
365
	public function change_success_url( $siteurl ) {
366
367
		$admin_url   = is_network_admin() ? network_admin_url() : admin_url();
368
		$return_step = is_network_admin() ? 'recommended_addons' : 'recommended_settings';
369
370
		$siteurl = add_query_arg( array(
371
			'page' => 'monsterinsights-onboarding',
372
		), $admin_url );
373
374
		$siteurl .= '#/' . $return_step;
375
376
		return $siteurl;
377
378
	}
379
380
	/**
381
	 * Retrieve an array of European countries.
382
	 *
383
	 * @return array
384
	 */
385
	public static function get_eu_countries() {
386
		return array(
387
			'AD',
388
			'AL',
389
			'AT',
390
			'AX',
391
			'BA',
392
			'BE',
393
			'BG',
394
			'BY',
395
			'CH',
396
			'CY',
397
			'CZ',
398
			'DE',
399
			'DK',
400
			'EE',
401
			'ES',
402
			'FI',
403
			'FO',
404
			'FR',
405
			'GB',
406
			'GG',
407
			'GI',
408
			'GR',
409
			'HR',
410
			'HU',
411
			'IE',
412
			'IM',
413
			'IS',
414
			'IT',
415
			'JE',
416
			'LI',
417
			'LT',
418
			'LU',
419
			'LV',
420
			'MC',
421
			'MD',
422
			'ME',
423
			'MK',
424
			'MT',
425
			'NL',
426
			'NO',
427
			'PL',
428
			'PT',
429
			'RO',
430
			'RS',
431
			'RU',
432
			'SE',
433
			'SI',
434
			'SJ',
435
			'SK',
436
			'SM',
437
			'TR',
438
			'UA',
439
			'VA',
440
		);
441
	}
442
443
	/**
444
	 * Ajax handler for grabbing the installed code status.
445
	 */
446
	public function get_install_errors() {
447
448
		wp_send_json( monsterinsights_is_code_installed_frontend() );
449
450
	}
451
452
}
453
454
new MonsterInsights_Onboarding_Wizard();
455