Passed
Push — master ( 8403c0...3ede7f )
by Chris
08:42
created

MonsterInsights_Rest_Routes::update_manual_v4()   D

Complexity

Conditions 21
Paths 73

Size

Total Lines 48
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 21
eloc 29
c 1
b 0
f 0
nc 73
nop 0
dl 0
loc 48
rs 4.1666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Routes for VUE are registered here.
4
 *
5
 * @package monsterinsights
6
 */
7
8
/**
9
 * Class MonsterInsights_Rest_Routes
10
 */
11
class MonsterInsights_Rest_Routes {
12
13
	/**
14
	 * MonsterInsights_Rest_Routes constructor.
15
	 */
16
	public function __construct() {
17
18
		add_action( 'wp_ajax_monsterinsights_vue_get_license', array( $this, 'get_license' ) );
19
		add_action( 'wp_ajax_monsterinsights_vue_get_profile', array( $this, 'get_profile' ) );
20
		add_action( 'wp_ajax_monsterinsights_vue_get_settings', array( $this, 'get_settings' ) );
21
		add_action( 'wp_ajax_monsterinsights_vue_update_settings', array( $this, 'update_settings' ) );
22
		add_action( 'wp_ajax_monsterinsights_vue_update_settings_bulk', array( $this, 'update_settings_bulk' ) );
23
		add_action( 'wp_ajax_monsterinsights_vue_get_addons', array( $this, 'get_addons' ) );
24
		add_action( 'wp_ajax_monsterinsights_update_manual_ua', array( $this, 'update_manual_ua' ) );
25
		add_action( 'wp_ajax_monsterinsights_update_manual_v4', array( $this, 'update_manual_v4' ) );
26
		add_action( 'wp_ajax_monsterinsights_update_dual_tracking_id', array( $this, 'update_dual_tracking_id' ) );
27
		add_action( 'wp_ajax_monsterinsights_update_measurement_protocol_secret', array( $this, 'update_measurement_protocol_secret' ) );
28
		add_action( 'wp_ajax_monsterinsights_vue_get_report_data', array( $this, 'get_report_data' ) );
29
		add_action( 'wp_ajax_monsterinsights_vue_install_plugin', array( $this, 'install_plugin' ) );
30
		add_action( 'wp_ajax_monsterinsights_vue_notice_status', array( $this, 'get_notice_status' ) );
31
		add_action( 'wp_ajax_monsterinsights_vue_notice_dismiss', array( $this, 'dismiss_notice' ) );
32
		add_action( 'wp_ajax_monsterinsights_vue_grab_popular_posts_report', array(
33
			$this,
34
			'check_popular_posts_report'
35
		) );
36
		add_action( 'wp_ajax_monsterinsights_vue_popular_posts_update_theme_setting', array(
37
			$this,
38
			'update_popular_posts_theme_setting'
39
		) );
40
41
		// TODO: remove function from Google Optimize Addon.
42
		add_action( 'wp_ajax_monsterinsights_get_posts', array( $this, 'get_posts' ) );
43
44
		// Search for taxonomies.
45
		add_action( 'wp_ajax_monsterinsights_get_terms', array( $this, 'get_taxonomy_terms' ) );
46
47
		add_action( 'wp_ajax_monsterinsights_get_post_types', array( $this, 'get_post_types' ) );
48
49
		add_action( 'wp_ajax_monsterinsights_handle_settings_import', array( $this, 'handle_settings_import' ) );
50
51
		add_action( 'admin_notices', array( $this, 'hide_old_notices' ), 0 );
52
53
		add_action( 'wp_ajax_monsterinsights_vue_dismiss_first_time_notice', array(
54
			$this,
55
			'dismiss_first_time_notice'
56
		) );
57
	}
58
59
	/**
60
	 * Ajax handler for grabbing the license
61
	 */
62
	public function get_license() {
63
64
		check_ajax_referer( 'mi-admin-nonce', 'nonce' );
65
66
		if ( ! current_user_can( 'monsterinsights_view_dashboard' ) || ! monsterinsights_is_pro_version() ) {
67
			return;
68
		}
69
70
		$site_license    = array(
71
			'key'         => MonsterInsights()->license->get_site_license_key(),
72
			'type'        => MonsterInsights()->license->get_site_license_type(),
73
			'is_disabled' => MonsterInsights()->license->site_license_disabled(),
74
			'is_expired'  => MonsterInsights()->license->site_license_expired(),
75
			'is_invalid'  => MonsterInsights()->license->site_license_invalid(),
76
		);
77
		$network_license = array(
78
			'key'         => MonsterInsights()->license->get_network_license_key(),
79
			'type'        => MonsterInsights()->license->get_network_license_type(),
80
			'is_disabled' => MonsterInsights()->license->network_license_disabled(),
81
			'is_expired'  => MonsterInsights()->license->network_license_expired(),
82
			'is_invalid'  => MonsterInsights()->license->network_license_disabled(),
83
		);
84
85
		wp_send_json( array(
86
			'site'    => $site_license,
87
			'network' => $network_license,
88
		) );
89
90
	}
91
92
	/**
93
	 * Ajax handler for grabbing the current authenticated profile.
94
	 */
95
	public function get_profile() {
96
		check_ajax_referer( 'mi-admin-nonce', 'nonce' );
97
98
		if ( ! current_user_can( 'monsterinsights_save_settings' ) ) {
99
			return;
100
		}
101
102
		$auth = MonsterInsights()->auth;
103
104
		wp_send_json( array(
105
			'ua'                                  => $auth->get_ua(),
106
			'v4'                                  => $auth->get_v4_id(),
107
			'viewname'                            => $auth->get_viewname(),
108
			'manual_ua'                           => $auth->get_manual_ua(),
109
			'manual_v4'                           => $auth->get_manual_v4_id(),
110
			'measurement_protocol_secret'         => $auth->get_measurement_protocol_secret(),
111
			'network_ua'                          => $auth->get_network_ua(),
112
			'network_v4'                          => $auth->get_network_v4_id(),
113
			'network_viewname'                    => $auth->get_network_viewname(),
114
			'network_manual_ua'                   => $auth->get_network_manual_ua(),
115
			'network_measurement_protocol_secret' => $auth->get_network_measurement_protocol_secret(),
116
			'connected_type'                      => $auth->get_connected_type(),
117
		) );
118
119
	}
120
121
	/**
122
	 * Ajax handler for grabbing the settings.
123
	 */
124
	public function get_settings() {
125
126
		check_ajax_referer( 'mi-admin-nonce', 'nonce' );
127
128
		if ( ! current_user_can( 'monsterinsights_view_dashboard' ) ) {
129
			return;
130
		}
131
132
		$options = monsterinsights_get_options();
133
134
		// Array fields are needed even if empty.
135
		$array_fields = array( 'view_reports', 'save_settings', 'ignore_users' );
136
		foreach ( $array_fields as $array_field ) {
137
			if ( ! isset( $options[ $array_field ] ) ) {
138
				$options[ $array_field ] = array();
139
			}
140
		}
141
		if ( isset( $options['custom_code'] ) ) {
142
			$options['custom_code'] = stripslashes( $options['custom_code'] );
143
		}
144
145
		//add email summaries options
146
		if ( monsterinsights_is_pro_version() ) {
147
			$default_email = array(
148
				'email' => get_option( 'admin_email' ),
149
			);
150
151
			if ( ! isset( $options['email_summaries'] ) ) {
152
				$options['email_summaries'] = 'on';
153
			}
154
155
			if ( ! isset( $options['summaries_email_addresses'] ) ) {
156
				$options['summaries_email_addresses'] = array(
157
					$default_email,
158
				);
159
			}
160
161
			if ( ! isset( $options['summaries_html_template'] ) ) {
162
				$options['summaries_html_template'] = 'yes';
163
			}
164
165
166
			if ( ! isset( $options['summaries_carbon_copy'] ) ) {
167
				$options['summaries_carbon_copy'] = 'no';
168
			}
169
170
171
			if ( ! isset( $options['summaries_header_image'] ) ) {
172
				$options['summaries_header_image'] = '';
173
			}
174
175
			if ( ! isset( $options['local_gtag_file_modified_at'] ) ) {
176
				$options['local_gtag_file_modified_at'] = '';
177
			}
178
		}
179
180
		wp_send_json( $options );
181
182
	}
183
184
	/**
185
	 * Ajax handler for updating the settings.
186
	 */
187
	public function update_settings() {
188
189
		check_ajax_referer( 'mi-admin-nonce', 'nonce' );
190
191
		if ( ! current_user_can( 'monsterinsights_save_settings' ) ) {
192
			return;
193
		}
194
195
		if ( isset( $_POST['setting'] ) ) {
196
			$setting = sanitize_text_field( wp_unslash( $_POST['setting'] ) );
197
			if ( isset( $_POST['value'] ) ) {
198
				$value = $this->handle_sanitization( $setting, $_POST['value'] );
199
				monsterinsights_update_option( $setting, $value );
200
				do_action( 'monsterinsights_after_update_settings', $setting, $value );
201
			} else {
202
				monsterinsights_update_option( $setting, false );
203
				do_action( 'monsterinsights_after_update_settings', $setting, false );
204
			}
205
		}
206
207
		wp_send_json_success();
208
209
	}
210
211
	/**
212
	 * Ajax handler for updating the settings.
213
	 */
214
	public function update_settings_bulk() {
215
216
		check_ajax_referer( 'mi-admin-nonce', 'nonce' );
217
218
		if ( ! current_user_can( 'monsterinsights_save_settings' ) ) {
219
			return;
220
		}
221
222
		if ( isset( $_POST['settings'] ) ) {
223
			$settings = json_decode( sanitize_text_field( wp_unslash( $_POST['settings'] ) ), true );
224
			foreach ( $settings as $setting => $value ) {
225
				$value = $this->handle_sanitization( $setting, $value );
226
				monsterinsights_update_option( $setting, $value );
227
				do_action( 'monsterinsights_after_update_settings', $setting, $value );
228
			}
229
		}
230
231
		wp_send_json_success();
232
233
	}
234
235
	/**
236
	 * Sanitization specific to each field.
237
	 *
238
	 * @param string $field The key of the field to sanitize.
239
	 * @param string $value The value of the field to sanitize.
240
	 *
241
	 * @return mixed The sanitized input.
242
	 */
243
	private function handle_sanitization( $field, $value ) {
244
245
		$value = wp_unslash( $value );
246
247
		// Textarea fields.
248
		$textarea_fields = array(
249
			'custom_code',
250
		);
251
252
		if ( in_array( $field, $textarea_fields, true ) ) {
253
			if ( function_exists( 'sanitize_textarea_field' ) ) {
254
				return sanitize_textarea_field( $value );
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type array; however, parameter $str of sanitize_textarea_field() 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

254
				return sanitize_textarea_field( /** @scrutinizer ignore-type */ $value );
Loading history...
255
			} else {
256
				return wp_kses( $value, array() );
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type array; however, parameter $string of wp_kses() 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

256
				return wp_kses( /** @scrutinizer ignore-type */ $value, array() );
Loading history...
257
			}
258
		}
259
260
		$array_value = json_decode( $value, true );
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type array; however, parameter $json of json_decode() 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

260
		$array_value = json_decode( /** @scrutinizer ignore-type */ $value, true );
Loading history...
261
		if ( is_array( $array_value ) ) {
262
			$value = $array_value;
263
			// Don't save empty values.
264
			foreach ( $value as $key => $item ) {
265
				if ( is_array( $item ) ) {
266
					$empty = true;
267
					foreach ( $item as $item_value ) {
268
						if ( ! empty( $item_value ) ) {
269
							$empty = false;
270
						}
271
					}
272
					if ( $empty ) {
273
						unset( $value[ $key ] );
274
					}
275
				}
276
			}
277
278
			// Reset array keys because JavaScript can't handle arrays with non-sequential keys.
279
			$value = array_values( $value );
280
281
			return $value;
282
		}
283
284
		return sanitize_text_field( $value );
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type array; however, parameter $str of sanitize_text_field() 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

284
		return sanitize_text_field( /** @scrutinizer ignore-type */ $value );
Loading history...
285
286
	}
287
288
	/**
289
	 * Return the state of the addons ( installed, activated )
290
	 */
291
	public function get_addons() {
292
293
		check_ajax_referer( 'mi-admin-nonce', 'nonce' );
294
295
		if ( ! current_user_can( 'monsterinsights_save_settings' ) ) {
296
			return;
297
		}
298
299
		if ( isset( $_POST['network'] ) && intval( $_POST['network'] ) > 0 ) {
300
			define( 'WP_NETWORK_ADMIN', true );
301
		}
302
303
		$addons_data       = monsterinsights_get_addons();
304
		$parsed_addons     = array();
305
		$installed_plugins = get_plugins();
306
307
		if ( ! is_array( $addons_data ) ) {
308
			$addons_data = array();
309
		}
310
311
		foreach ( $addons_data as $addons_type => $addons ) {
312
			foreach ( $addons as $addon ) {
313
				$slug = 'monsterinsights-' . $addon->slug;
314
				if ( 'monsterinsights-ecommerce' === $slug && 'm' === $slug[0] ) {
315
					$addon = $this->get_addon( $installed_plugins, $addons_type, $addon, $slug );
316
					if ( empty( $addon->installed ) ) {
317
						$slug  = 'ga-ecommerce';
318
						$addon = $this->get_addon( $installed_plugins, $addons_type, $addon, $slug );
319
					}
320
				} else {
321
					$addon = $this->get_addon( $installed_plugins, $addons_type, $addon, $slug );
322
				}
323
				$parsed_addons[ $addon->slug ] = $addon;
324
			}
325
		}
326
327
		// Include data about the plugins needed by some addons ( WooCommerce, EDD, Google AMP, CookieBot, etc ).
328
		// WooCommerce.
329
		$parsed_addons['woocommerce'] = array(
330
			'active' => class_exists( 'WooCommerce' ),
331
		);
332
		// Edd.
333
		$parsed_addons['easy_digital_downloads'] = array(
334
			'active' => class_exists( 'Easy_Digital_Downloads' ),
335
		);
336
		// MemberPress.
337
		$parsed_addons['memberpress'] = array(
338
			'active' => defined( 'MEPR_VERSION' ) && version_compare( MEPR_VERSION, '1.3.43', '>' ),
0 ignored issues
show
Bug introduced by
The constant MEPR_VERSION was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
339
		);
340
		// LifterLMS.
341
		$parsed_addons['lifterlms'] = array(
342
			'active' => function_exists( 'LLMS' ) && version_compare( LLMS()->version, '3.32.0', '>=' ),
343
		);
344
		// Restrict Content Pro.
345
		$parsed_addons['rcp'] = array(
346
			'active' => class_exists( 'Restrict_Content_Pro' ) && version_compare( RCP_PLUGIN_VERSION, '3.5.4', '>=' ),
0 ignored issues
show
Bug introduced by
The constant RCP_PLUGIN_VERSION was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
347
		);
348
		// GiveWP.
349
		$parsed_addons['givewp'] = array(
350
			'active' => function_exists( 'Give' ),
351
		);
352
		// GiveWP Analytics.
353
		$parsed_addons['givewp_google_analytics'] = array(
354
			'active' => function_exists( 'Give_Google_Analytics' ),
355
		);
356
		// Cookiebot.
357
		$parsed_addons['cookiebot'] = array(
358
			'active' => function_exists( 'cookiebot_active' ) && cookiebot_active(),
359
		);
360
		// Cookie Notice.
361
		$parsed_addons['cookie_notice'] = array(
362
			'active' => class_exists( 'Cookie_Notice' ),
363
		);
364
		// Fb Instant Articles.
365
		$parsed_addons['instant_articles'] = array(
366
			'active' => defined( 'IA_PLUGIN_VERSION' ) && version_compare( IA_PLUGIN_VERSION, '3.3.4', '>' ),
0 ignored issues
show
Bug introduced by
The constant IA_PLUGIN_VERSION was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
367
		);
368
		// Google AMP.
369
		$parsed_addons['google_amp'] = array(
370
			'active' => defined( 'AMP__FILE__' ),
371
		);
372
		// Yoast SEO.
373
		$parsed_addons['yoast_seo'] = array(
374
			'active' => defined( 'WPSEO_VERSION' ),
375
		);
376
		// WPForms.
377
		$parsed_addons['wpforms-lite'] = array(
378
			'active'    => function_exists( 'wpforms' ),
379
			'icon'      => plugin_dir_url( MONSTERINSIGHTS_PLUGIN_FILE ) . 'assets/images/plugin-wpforms.png',
380
			'title'     => 'WPForms',
381
			'excerpt'   => __( 'The best drag & drop WordPress form builder. Easily create beautiful contact forms, surveys, payment forms, and more with our 150+ form templates. Trusted by over 4 million websites as the best forms plugin', 'google-analytics-for-wordpress' ),
382
			'installed' => array_key_exists( 'wpforms-lite/wpforms.php', $installed_plugins ),
383
			'basename'  => 'wpforms-lite/wpforms.php',
384
			'slug'      => 'wpforms-lite',
385
		);
386
		// AIOSEO.
387
		$parsed_addons['aioseo'] = array(
388
			'active'    => function_exists( 'aioseo' ),
389
			'icon'      => plugin_dir_url( MONSTERINSIGHTS_PLUGIN_FILE ) . 'assets/images/plugin-all-in-one-seo.png',
390
			'title'     => 'AIOSEO',
391
			'excerpt'   => __( 'The original WordPress SEO plugin and toolkit that improves your website’s search rankings. Comes with all the SEO features like Local SEO, WooCommerce SEO, sitemaps, SEO optimizer, schema, and more.', 'google-analytics-for-wordpress' ),
392
			'installed' => array_key_exists( 'all-in-one-seo-pack/all_in_one_seo_pack.php', $installed_plugins ),
393
			'basename'  => ( monsterinsights_is_installed_aioseo_pro() ) ? 'all-in-one-seo-pack-pro/all_in_one_seo_pack.php' : 'all-in-one-seo-pack/all_in_one_seo_pack.php',
394
			'slug'      => 'all-in-one-seo-pack',
395
		);
396
		// OptinMonster.
397
		$parsed_addons['optinmonster'] = array(
398
			'active'    => class_exists( 'OMAPI' ),
399
			'icon'      => plugin_dir_url( MONSTERINSIGHTS_PLUGIN_FILE ) . 'assets/images/plugin-om.png',
400
			'title'     => 'OptinMonster',
401
			'excerpt'   => __( 'Instantly get more subscribers, leads, and sales with the #1 conversion optimization toolkit. Create high converting popups, announcement bars, spin a wheel, and more with smart targeting and personalization.', 'google-analytics-for-wordpress' ),
402
			'installed' => array_key_exists( 'optinmonster/optin-monster-wp-api.php', $installed_plugins ),
403
			'basename'  => 'optinmonster/optin-monster-wp-api.php',
404
			'slug'      => 'optinmonster',
405
		);
406
		// WP Mail Smtp.
407
		$parsed_addons['wp-mail-smtp'] = array(
408
			'active'    => function_exists( 'wp_mail_smtp' ),
409
			'icon'      => plugin_dir_url( MONSTERINSIGHTS_PLUGIN_FILE ) . 'assets/images/plugin-smtp.png',
410
			'title'     => 'WP Mail SMTP',
411
			'excerpt'   => __( 'Improve your WordPress email deliverability and make sure that your website emails reach user’s inbox with the #1 SMTP plugin for WordPress. Over 2 million websites use it to fix WordPress email issues.', 'google-analytics-for-wordpress' ),
412
			'installed' => array_key_exists( 'wp-mail-smtp/wp_mail_smtp.php', $installed_plugins ),
413
			'basename'  => 'wp-mail-smtp/wp_mail_smtp.php',
414
			'slug'      => 'wp-mail-smtp',
415
		);
416
		// SeedProd.
417
		$parsed_addons['coming-soon']    = array(
418
			'active'    => function_exists( 'seed_csp4_activation' ),
419
			'icon'      => plugin_dir_url( MONSTERINSIGHTS_PLUGIN_FILE ) . 'assets/images/plugin-seedprod.png',
420
			'title'     => 'SeedProd',
421
			'excerpt'   => __( 'The fastest drag & drop landing page builder for WordPress. Create custom landing pages without writing code, connect them with your CRM, collect subscribers, and grow your audience. Trusted by 1 million sites.', 'google-analytics-for-wordpress' ),
422
			'installed' => array_key_exists( 'coming-soon/coming-soon.php', $installed_plugins ),
423
			'basename'  => 'coming-soon/coming-soon.php',
424
			'slug'      => 'coming-soon',
425
		);
426
		// RafflePress
427
		$parsed_addons['rafflepress']    = array(
428
			'active'    => function_exists( 'rafflepress_lite_activation' ),
429
			'icon'      => plugin_dir_url( MONSTERINSIGHTS_PLUGIN_FILE ) . 'assets/images/pluign-rafflepress.png',
430
			'title'     => 'RafflePress',
431
			'excerpt'   => __( 'Turn your website visitors into brand ambassadors! Easily grow your email list, website traffic, and social media followers with the most powerful giveaways & contests plugin for WordPress.', 'google-analytics-for-wordpress' ),
432
			'installed' => array_key_exists( 'rafflepress/rafflepress.php', $installed_plugins ),
433
			'basename'  => 'rafflepress/rafflepress.php',
434
			'slug'      => 'rafflepress',
435
		);
436
		// TrustPulse
437
		$parsed_addons['trustpulse-api'] = array(
438
			'active'    => class_exists( 'TPAPI' ),
439
			'icon'      => plugin_dir_url( MONSTERINSIGHTS_PLUGIN_FILE ) . 'assets/images/plugin-trust-pulse.png',
440
			'title'     => 'TrustPulse',
441
			'excerpt'   => __( 'Boost your sales and conversions by up to 15% with real-time social proof notifications. TrustPulse helps you show live user activity and purchases to help convince other users to purchase.', 'google-analytics-for-wordpress' ),
442
			'installed' => array_key_exists( 'trustpulse-api/trustpulse.php', $installed_plugins ),
443
			'basename'  => 'trustpulse-api/trustpulse.php',
444
			'slug'      => 'trustpulse-api',
445
		);
446
		// Smash Balloon (Instagram)
447
		$parsed_addons['smash-balloon-instagram'] = array(
448
			'active'    => class_exists( 'sb_instagram_feed_init' ),
449
			'icon'      => plugin_dir_url( MONSTERINSIGHTS_PLUGIN_FILE ) . 'assets/images/plugin-smash-balloon.png',
450
			'title'     => 'Smash Balloon Instagram Feeds',
451
			'excerpt'   => __( 'Easily display Instagram content on your WordPress site without writing any code. Comes with multiple templates, ability to show content from multiple accounts, hashtags, and more. Trusted by 1 million websites.', 'google-analytics-for-wordpress' ),
452
			'installed' => array_key_exists( 'instagram-feed/instagram-feed.php', $installed_plugins ),
453
			'basename'  => 'instagram-feed/instagram-feed.php',
454
			'slug'      => 'instagram-feed',
455
		);
456
		// PushEngage
457
		$parsed_addons['pushengage'] = array(
458
			'active'    => method_exists( 'Pushengage', 'init' ),
459
			'icon'      => plugin_dir_url( MONSTERINSIGHTS_PLUGIN_FILE ) . 'assets/images/plugin-pushengage.svg',
460
			'title'     => 'PushEngage',
461
			'excerpt'   => __( 'Connect with your visitors after they leave your website with the leading web push notification software. Over 10,000+ businesses worldwide use PushEngage to send 9 billion notifications each month.', 'google-analytics-for-wordpress' ),
462
			'installed' => array_key_exists( 'pushengage/main.php', $installed_plugins ),
463
			'basename'  => 'pushengage/main.php',
464
			'slug'      => 'pushengage',
465
		);
466
		// Pretty Links
467
		$parsed_addons['pretty-link'] = array(
468
			'active'    => class_exists( 'PrliBaseController' ),
469
			'icon'      => '',
470
			'title'     => 'Pretty Links',
471
			'excerpt'   => __( 'Pretty Links helps you shrink, beautify, track, manage and share any URL on or off of your WordPress website. Create links that look how you want using your own domain name!', 'google-analytics-for-wordpress' ),
472
			'installed' => array_key_exists( 'pretty-link/pretty-link.php', $installed_plugins ),
473
			'basename'  => 'pretty-link/pretty-link.php',
474
			'slug'      => 'pretty-link',
475
		);
476
		// Gravity Forms.
477
		$parsed_addons['gravity_forms'] = array(
478
			'active' => class_exists( 'GFCommon' ),
479
		);
480
		// Formidable Forms.
481
		$parsed_addons['formidable_forms'] = array(
482
			'active' => class_exists( 'FrmHooksController' ),
483
		);
484
		// Manual UA Addon.
485
		if ( ! isset( $parsed_addons['manual_ua'] ) ) {
486
			$parsed_addons['manual_ua'] = array(
487
				'active' => class_exists( 'MonsterInsights_Manual_UA' ),
488
			);
489
		}
490
491
		wp_send_json( $parsed_addons );
492
	}
493
494
	public function get_addon( $installed_plugins, $addons_type, $addon, $slug ) {
495
		$active          = false;
496
		$installed       = false;
497
		$plugin_basename = monsterinsights_get_plugin_basename_from_slug( $slug );
498
499
		if ( isset( $installed_plugins[ $plugin_basename ] ) ) {
500
			$installed = true;
501
502
			if ( is_multisite() && is_network_admin() ) {
503
				$active = is_plugin_active_for_network( $plugin_basename );
504
			} else {
505
				$active = is_plugin_active( $plugin_basename );
506
			}
507
		}
508
		if ( empty( $addon->url ) ) {
509
			$addon->url = '';
510
		}
511
512
		$active_version = false;
513
		if ( $active ) {
514
			if ( ! empty( $installed_plugins[ $plugin_basename ]['Version'] ) ) {
515
				$active_version = $installed_plugins[ $plugin_basename ]['Version'];
516
			}
517
		}
518
519
		$addon->type           = $addons_type;
520
		$addon->installed      = $installed;
521
		$addon->active_version = $active_version;
522
		$addon->active         = $active;
523
		$addon->basename       = $plugin_basename;
524
525
		return $addon;
526
	}
527
528
	/**
529
	 * Use custom notices in the Vue app on the Settings screen.
530
	 */
531
	public function hide_old_notices() {
532
533
		global $wp_version;
534
		if ( version_compare( $wp_version, '4.6', '<' ) ) {
535
			// remove_all_actions triggers an infinite loop on older versions.
536
			return;
537
		}
538
539
		$screen = get_current_screen();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $screen is correct as get_current_screen() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
540
		// Bail if we're not on a MonsterInsights screen.
541
		if ( empty( $screen->id ) || strpos( $screen->id, 'monsterinsights' ) === false ) {
542
			return;
543
		}
544
545
		// Hide admin notices on the settings screen.
546
		if ( monsterinsights_is_settings_page() ) {
547
			remove_all_actions( 'admin_notices' );
548
		}
549
550
	}
551
552
	/**
553
	 * Update manual ua.
554
	 */
555
	public function update_manual_ua() {
556
557
		check_ajax_referer( 'mi-admin-nonce', 'nonce' );
558
559
		if ( ! current_user_can( 'monsterinsights_save_settings' ) ) {
560
			return;
561
		}
562
563
		$manual_ua_code = isset( $_POST['manual_ua_code'] ) ? sanitize_text_field( wp_unslash( $_POST['manual_ua_code'] ) ) : '';
564
		$manual_ua_code = monsterinsights_is_valid_ua( $manual_ua_code ); // Also sanitizes the string.
565
		if ( ! empty( $_REQUEST['isnetwork'] ) && sanitize_text_field( wp_unslash( $_REQUEST['isnetwork'] ) ) ) {
566
			define( 'WP_NETWORK_ADMIN', true );
567
		}
568
		$manual_ua_code_old = is_network_admin() ? MonsterInsights()->auth->get_network_manual_ua() : MonsterInsights()->auth->get_manual_ua();
569
570
		if ( $manual_ua_code && $manual_ua_code_old && $manual_ua_code_old === $manual_ua_code ) {
571
			// Same code we had before
572
			// Do nothing.
573
			wp_send_json_success();
574
		} else if ( $manual_ua_code && $manual_ua_code_old && $manual_ua_code_old !== $manual_ua_code ) {
575
			// Different UA code.
576
			if ( is_network_admin() ) {
577
				MonsterInsights()->auth->set_network_manual_ua( $manual_ua_code );
578
			} else {
579
				MonsterInsights()->auth->set_manual_ua( $manual_ua_code );
580
			}
581
		} else if ( $manual_ua_code && empty( $manual_ua_code_old ) ) {
582
			// Move to manual.
583
			if ( is_network_admin() ) {
584
				MonsterInsights()->auth->set_network_manual_ua( $manual_ua_code );
585
			} else {
586
				MonsterInsights()->auth->set_manual_ua( $manual_ua_code );
587
			}
588
		} else if ( empty( $manual_ua_code ) && $manual_ua_code_old ) {
589
			// Deleted manual.
590
			if ( is_network_admin() ) {
591
				MonsterInsights()->auth->delete_network_manual_ua();
592
			} else {
593
				MonsterInsights()->auth->delete_manual_ua();
594
			}
595
		} else if ( isset( $_POST['manual_ua_code'] ) && empty( $manual_ua_code ) ) {
596
			wp_send_json_error( array(
597
				'error' => __( 'Invalid UA code', 'google-analytics-for-wordpress' ),
598
			) );
599
		}
600
601
		wp_send_json_success();
602
	}
603
604
	/**
605
	 * Update manual v4.
606
	 */
607
	public function update_manual_v4() {
608
609
		check_ajax_referer( 'mi-admin-nonce', 'nonce' );
610
611
		if ( ! current_user_can( 'monsterinsights_save_settings' ) ) {
612
			return;
613
		}
614
615
		$manual_v4_code = isset( $_POST['manual_v4_code'] ) ? sanitize_text_field( wp_unslash( $_POST['manual_v4_code'] ) ) : '';
616
		$manual_v4_code = monsterinsights_is_valid_v4_id( $manual_v4_code ); // Also sanitizes the string.
617
618
		if ( ! empty( $_REQUEST['isnetwork'] ) && sanitize_text_field( wp_unslash( $_REQUEST['isnetwork'] ) ) ) {
619
			define( 'WP_NETWORK_ADMIN', true );
620
		}
621
		$manual_v4_code_old = is_network_admin() ? MonsterInsights()->auth->get_network_manual_v4_id() : MonsterInsights()->auth->get_manual_v4_id();
622
623
		if ( $manual_v4_code && $manual_v4_code_old && $manual_v4_code_old === $manual_v4_code ) {
624
			// Same code we had before
625
			// Do nothing.
626
			wp_send_json_success();
627
		} else if ( $manual_v4_code && $manual_v4_code_old && $manual_v4_code_old !== $manual_v4_code ) {
628
			// Different UA code.
629
			if ( is_network_admin() ) {
630
				MonsterInsights()->auth->set_network_manual_v4_id( $manual_v4_code );
631
			} else {
632
				MonsterInsights()->auth->set_manual_v4_id( $manual_v4_code );
633
			}
634
		} else if ( $manual_v4_code && empty( $manual_v4_code_old ) ) {
635
			// Move to manual.
636
			if ( is_network_admin() ) {
637
				MonsterInsights()->auth->set_network_manual_v4_id( $manual_v4_code );
638
			} else {
639
				MonsterInsights()->auth->set_manual_v4_id( $manual_v4_code );
640
			}
641
		} else if ( empty( $manual_v4_code ) && $manual_v4_code_old ) {
642
			// Deleted manual.
643
			if ( is_network_admin() ) {
644
				MonsterInsights()->auth->delete_network_manual_v4_id();
645
			} else {
646
				MonsterInsights()->auth->delete_manual_v4_id();
647
			}
648
		} else if ( isset( $_POST['manual_v4_code'] ) && empty( $manual_v4_code ) ) {
649
			wp_send_json_error( array(
650
				'error' => __( 'Invalid UA code', 'google-analytics-for-wordpress' ),
651
			) );
652
		}
653
654
		wp_send_json_success();
655
	}
656
657
	public function update_dual_tracking_id() {
658
		check_ajax_referer( 'mi-admin-nonce', 'nonce' );
659
660
		if ( ! current_user_can( 'monsterinsights_save_settings' ) ) {
661
			return;
662
		}
663
664
		if ( ! empty( $_REQUEST['isnetwork'] ) && sanitize_text_field( wp_unslash( $_REQUEST['isnetwork'] ) ) ) {
665
			define( 'WP_NETWORK_ADMIN', true );
666
		}
667
668
		$value = empty( $_REQUEST['value'] ) ? '' : sanitize_text_field( wp_unslash( $_REQUEST['value'] ) );
669
		$sanitized_ua_value = monsterinsights_is_valid_ua( $value );
670
		$sanitized_v4_value = monsterinsights_is_valid_v4_id( $value );
671
672
		if ( $sanitized_v4_value ) {
673
			$value = $sanitized_v4_value;
674
		} elseif ( $sanitized_ua_value ) {
675
			$value = $sanitized_ua_value;
676
		} elseif ( ! empty( $value ) ) {
677
			wp_send_json_error( array(
678
				'error' => __( 'Invalid dual tracking code', 'google-analytics-for-wordpress' ),
679
			) );
680
		}
681
682
		$auth = MonsterInsights()->auth;
683
684
		if ( is_network_admin() ) {
685
			$auth->set_network_dual_tracking_id( $value );
686
		} else {
687
			$auth->set_dual_tracking_id( $value );
688
		}
689
690
		wp_send_json_success();
691
	}
692
693
	public function update_measurement_protocol_secret() {
694
		check_ajax_referer( 'mi-admin-nonce', 'nonce' );
695
696
		if ( ! current_user_can( 'monsterinsights_save_settings' ) ) {
697
			return;
698
		}
699
700
		if ( ! empty( $_REQUEST['isnetwork'] ) && sanitize_text_field( wp_unslash( $_REQUEST['isnetwork'] ) ) ) {
701
			define( 'WP_NETWORK_ADMIN', true );
702
		}
703
704
		$value = empty( $_REQUEST['value'] ) ? '' : sanitize_text_field( wp_unslash( $_REQUEST['value'] ) );
705
706
		$auth = MonsterInsights()->auth;
707
708
		if ( is_network_admin() ) {
709
			$auth->set_network_measurement_protocol_secret( $value );
710
		} else {
711
			$auth->set_measurement_protocol_secret( $value );
712
		}
713
714
		// Send API request to Relay
715
		// TODO: Remove when token automation API is ready
716
		$api = new MonsterInsights_API_Request( 'auth/mp-token/', 'POST' );
717
		$api->set_additional_data( array(
718
			'mp_token' => $value,
719
		) );
720
721
		// Even if there's an error from Relay, we can still return a successful json
722
		// payload because we can try again with Relay token push in the future
723
		$data   = array();
724
		$result = $api->request();
725
		if ( is_wp_error( $result ) ) {
726
			// Just need to output the error in the response for debugging purpose
727
			$data['error'] = array(
728
				'message' => $result->get_error_message(),
729
				'code'    => $result->get_error_code(),
730
			);
731
		}
732
733
		wp_send_json_success( $data );
734
	}
735
736
737
	/**
738
	 *
739
	 */
740
	public function handle_settings_import() {
741
742
		check_ajax_referer( 'mi-admin-nonce', 'nonce' );
743
744
		if ( ! current_user_can( 'monsterinsights_save_settings' ) ) {
745
			return;
746
		}
747
748
		if ( ! isset( $_FILES['import_file'] ) ) {
749
			return;
750
		}
751
752
		$extension = explode( '.', sanitize_text_field( wp_unslash( $_FILES['import_file']['name'] ) ) );
753
		$extension = end( $extension );
754
755
		if ( 'json' !== $extension ) {
756
			wp_send_json_error( array(
757
				'message' => esc_html__( 'Please upload a valid .json file', 'google-analytics-for-wordpress' ),
758
			) );
759
		}
760
761
		$import_file = sanitize_text_field( wp_unslash( $_FILES['import_file']['tmp_name'] ) );
762
763
		$file = file_get_contents( $import_file );
764
		if ( empty( $file ) ) {
765
			wp_send_json_error( array(
766
				'message' => esc_html__( 'Please upload a file to import', 'google-analytics-for-wordpress' ),
767
			) );
768
		}
769
770
		// Retrieve the settings from the file and convert the json object to an array.
771
		$new_settings = json_decode( wp_json_encode( json_decode( $file ) ), true );
772
		$settings     = monsterinsights_get_options();
773
		$exclude      = array(
774
			'analytics_profile',
775
			'analytics_profile_code',
776
			'analytics_profile_name',
777
			'oauth_version',
778
			'cron_last_run',
779
			'monsterinsights_oauth_status',
780
		);
781
782
		foreach ( $exclude as $e ) {
783
			if ( ! empty( $new_settings[ $e ] ) ) {
784
				unset( $new_settings[ $e ] );
785
			}
786
		}
787
788
		if ( ! is_super_admin() ) {
789
			if ( ! empty( $new_settings['custom_code'] ) ) {
790
				unset( $new_settings['custom_code'] );
791
			}
792
		}
793
794
		foreach ( $exclude as $e ) {
795
			if ( ! empty( $settings[ $e ] ) ) {
796
				$new_settings = $settings[ $e ];
797
			}
798
		}
799
800
		global $monsterinsights_settings;
801
		$monsterinsights_settings = $new_settings;
802
803
		update_option( monsterinsights_get_option_name(), $new_settings );
804
805
		wp_send_json_success( $new_settings );
806
807
	}
808
809
	/**
810
	 * Generic Ajax handler for grabbing report data in JSON.
811
	 */
812
	public function get_report_data() {
813
814
		check_ajax_referer( 'mi-admin-nonce', 'nonce' );
815
816
		if ( ! current_user_can( 'monsterinsights_view_dashboard' ) ) {
817
			wp_send_json_error( array( 'message' => __( "You don't have permission to view MonsterInsights reports.", 'google-analytics-for-wordpress' ) ) );
818
		}
819
820
		if ( ! empty( $_REQUEST['isnetwork'] ) && $_REQUEST['isnetwork'] ) {
821
			define( 'WP_NETWORK_ADMIN', true );
822
		}
823
		$settings_page = admin_url( 'admin.php?page=monsterinsights_settings' );
824
825
		// Only for Pro users, require a license key to be entered first so we can link to things.
826
		if ( monsterinsights_is_pro_version() ) {
827
			if ( ! MonsterInsights()->license->is_site_licensed() && ! MonsterInsights()->license->is_network_licensed() ) {
828
				wp_send_json_error( array(
829
					'message' => __( "You can't view MonsterInsights reports because you are not licensed.", 'google-analytics-for-wordpress' ),
830
					'footer'  => '<a href="' . $settings_page . '">' . __( 'Add your license', 'google-analytics-for-wordpress' ) . '</a>',
831
				) );
832
			} else if ( MonsterInsights()->license->is_site_licensed() && ! MonsterInsights()->license->site_license_has_error() ) {
833
				// Good to go: site licensed.
834
			} else if ( MonsterInsights()->license->is_network_licensed() && ! MonsterInsights()->license->network_license_has_error() ) {
835
				// Good to go: network licensed.
836
			} else {
837
				wp_send_json_error( array( 'message' => __( "You can't view MonsterInsights reports due to license key errors.", 'google-analytics-for-wordpress' ) ) );
838
			}
839
		}
840
841
		// We do not have a current auth.
842
		$site_auth = MonsterInsights()->auth->get_viewname();
843
		$ms_auth   = is_multisite() && MonsterInsights()->auth->get_network_viewname();
844
		if ( ! $site_auth && ! $ms_auth ) {
845
			wp_send_json_error( array( 'message' => __( 'You must authenticate with MonsterInsights before you can view reports.', 'google-analytics-for-wordpress' ) ) );
846
		}
847
848
		$report_name = isset( $_POST['report'] ) ? sanitize_text_field( wp_unslash( $_POST['report'] ) ) : '';
849
850
		if ( empty( $report_name ) ) {
851
			wp_send_json_error( array( 'message' => __( 'Unknown report. Try refreshing and retrying. Contact support if this issue persists.', 'google-analytics-for-wordpress' ) ) );
852
		}
853
854
		$report = MonsterInsights()->reporting->get_report( $report_name );
855
856
		$isnetwork = ! empty( $_REQUEST['isnetwork'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['isnetwork'] ) ) : '';
857
		$start     = ! empty( $_POST['start'] ) ? sanitize_text_field( wp_unslash( $_POST['start'] ) ) : $report->default_start_date();
858
		$end       = ! empty( $_POST['end'] ) ? sanitize_text_field( wp_unslash( $_POST['end'] ) ) : $report->default_end_date();
859
860
		$args = array(
861
			'start' => $start,
862
			'end'   => $end,
863
		);
864
865
		if ( $isnetwork ) {
866
			$args['network'] = true;
867
		}
868
869
		if ( monsterinsights_is_pro_version() && ! MonsterInsights()->license->license_can( $report->level ) ) {
870
			$data = array(
871
				'success' => false,
872
				'error'   => 'license_level',
873
			);
874
		} else {
875
			$data = apply_filters( 'monsterinsights_vue_reports_data', $report->get_data( $args ), $report_name, $report );
876
		}
877
878
		if ( ! empty( $data['success'] ) && ! empty( $data['data'] ) ) {
879
			wp_send_json_success( $data['data'] );
880
		} else if ( isset( $data['success'] ) && false === $data['success'] && ! empty( $data['error'] ) ) {
881
			// Use a custom handler for invalid_grant errors.
882
			if ( strpos( $data['error'], 'invalid_grant' ) > 0 ) {
883
				wp_send_json_error(
884
					array(
885
						'message' => 'invalid_grant',
886
						'footer'  => '',
887
					)
888
				);
889
			}
890
891
			wp_send_json_error(
892
				array(
893
					'message' => $data['error'],
894
					'footer'  => isset( $data['data']['footer'] ) ? $data['data']['footer'] : '',
895
				)
896
			);
897
		}
898
899
		wp_send_json_error( array( 'message' => __( 'We encountered an error when fetching the report data.', 'google-analytics-for-wordpress' ) ) );
900
901
	}
902
903
	/**
904
	 * Install plugins which are not addons.
905
	 */
906
	public function install_plugin() {
907
		check_ajax_referer( 'mi-admin-nonce', 'nonce' );
908
909
		if ( ! monsterinsights_can_install_plugins() ) {
910
			wp_send_json( array(
911
				'error' => esc_html__( 'You are not allowed to install plugins', 'google-analytics-for-wordpress' ),
912
			) );
913
		}
914
915
		$slug = isset( $_POST['slug'] ) ? sanitize_text_field( wp_unslash( $_POST['slug'] ) ) : false;
916
917
		if ( ! $slug ) {
918
			wp_send_json( array(
919
				'message' => esc_html__( 'Missing plugin name.', 'google-analytics-for-wordpress' ),
920
			) );
921
		}
922
923
		include_once ABSPATH . 'wp-admin/includes/plugin-install.php';
924
925
		$api = plugins_api( 'plugin_information', array(
926
			'slug'   => $slug,
927
			'fields' => array(
928
				'short_description' => false,
929
				'sections'          => false,
930
				'requires'          => false,
931
				'rating'            => false,
932
				'ratings'           => false,
933
				'downloaded'        => false,
934
				'last_updated'      => false,
935
				'added'             => false,
936
				'tags'              => false,
937
				'compatibility'     => false,
938
				'homepage'          => false,
939
				'donate_link'       => false,
940
			),
941
		) );
942
943
		if ( is_wp_error( $api ) ) {
944
			return $api->get_error_message();
945
		}
946
947
		$download_url = $api->download_link;
948
949
		$method = '';
950
		$url    = add_query_arg(
951
			array(
952
				'page' => 'monsterinsights-settings',
953
			),
954
			admin_url( 'admin.php' )
955
		);
956
		$url    = esc_url( $url );
957
958
		ob_start();
959
		if ( false === ( $creds = request_filesystem_credentials( $url, $method, false, false, null ) ) ) {
960
			$form = ob_get_clean();
961
962
			wp_send_json( array( 'form' => $form ) );
963
		}
964
965
		// If we are not authenticated, make it happen now.
966
		if ( ! WP_Filesystem( $creds ) ) {
967
			ob_start();
968
			request_filesystem_credentials( $url, $method, true, false, null );
969
			$form = ob_get_clean();
970
971
			wp_send_json( array( 'form' => $form ) );
972
973
		}
974
975
		// We do not need any extra credentials if we have gotten this far, so let's install the plugin.
976
		monsterinsights_require_upgrader();
977
978
		// Prevent language upgrade in ajax calls.
979
		remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 );
980
		// Create the plugin upgrader with our custom skin.
981
		$installer = new MonsterInsights_Plugin_Upgrader( new MonsterInsights_Skin() );
982
		$installer->install( $download_url );
983
984
		// Flush the cache and return the newly installed plugin basename.
985
		wp_cache_flush();
986
		wp_send_json_success();
987
988
		wp_die();
989
	}
990
991
	/**
992
	 * Store that the first run notice has been dismissed so it doesn't show up again.
993
	 */
994
	public function dismiss_first_time_notice() {
995
996
		monsterinsights_update_option( 'monsterinsights_first_run_notice', true );
0 ignored issues
show
Bug introduced by
true of type true is incompatible with the type string expected by parameter $value of monsterinsights_update_option(). ( Ignorable by Annotation )

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

996
		monsterinsights_update_option( 'monsterinsights_first_run_notice', /** @scrutinizer ignore-type */ true );
Loading history...
997
998
		wp_send_json_success();
999
	}
1000
1001
	/**
1002
	 * Get the notice status by id.
1003
	 */
1004
	public function get_notice_status() {
1005
1006
		check_ajax_referer( 'mi-admin-nonce', 'nonce' );
1007
1008
		$notice_id = empty( $_POST['notice'] ) ? false : sanitize_text_field( wp_unslash( $_POST['notice'] ) );
1009
		if ( ! $notice_id ) {
1010
			wp_send_json_error();
1011
		}
1012
		$is_dismissed = MonsterInsights()->notices->is_dismissed( $notice_id );
1013
1014
		wp_send_json_success( array(
1015
			'dismissed' => $is_dismissed,
1016
		) );
1017
	}
1018
1019
	/**
1020
	 * Dismiss notices by id.
1021
	 */
1022
	public function dismiss_notice() {
1023
1024
		check_ajax_referer( 'mi-admin-nonce', 'nonce' );
1025
1026
		$notice_id = empty( $_POST['notice'] ) ? false : sanitize_text_field( wp_unslash( $_POST['notice'] ) );
1027
		if ( ! $notice_id ) {
1028
			wp_send_json_error();
1029
		}
1030
		MonsterInsights()->notices->dismiss( $notice_id );
1031
1032
		wp_send_json_success();
1033
	}
1034
1035
	/**
1036
	 * Retrieve posts/pages
1037
	 *
1038
	 * @access admin
1039
	 * @since 3.0.0
1040
	 */
1041
	public function get_posts() {
1042
1043
		// Run a security check first.
1044
		check_ajax_referer( 'mi-admin-nonce', 'nonce' );
1045
1046
		$post_type = isset( $_POST['post_type'] ) ? sanitize_text_field( wp_unslash( $_POST['post_type'] ) ) : 'any';
1047
1048
		$args = array(
1049
			's'              => isset( $_POST['keyword'] ) ? sanitize_text_field( wp_unslash( $_POST['keyword'] ) ) : '',
1050
			'post_type'      => $post_type,
1051
			'posts_per_page' => isset( $_POST['numberposts'] ) ? sanitize_text_field( wp_unslash( $_POST['numberposts'] ) ) : 10,
1052
			'orderby'        => 'relevance',
1053
		);
1054
1055
		$array = array();
1056
		$posts = get_posts( $args );
1057
1058
		if ( in_array( $post_type, array( 'page', 'any' ), true ) ) {
1059
			$homepage = get_option( 'page_on_front' );
1060
			if ( ! $homepage ) {
1061
				$array[] = array(
1062
					'id'    => - 1,
1063
					'title' => __( 'Homepage', 'google-analytics-for-wordpress' ),
1064
				);
1065
			}
1066
		}
1067
1068
		if ( $posts ) {
1069
			foreach ( $posts as $post ) {
1070
				$array[] = array(
1071
					'id'    => $post->ID,
1072
					'title' => $post->post_title,
1073
				);
1074
			}
1075
		}
1076
1077
		wp_send_json_success( $array );
1078
	}
1079
1080
	/**
1081
	 * Search for taxonomy terms.
1082
	 *
1083
	 * @access admin
1084
	 * @since 3.0.0
1085
	 */
1086
	public function get_taxonomy_terms() {
1087
1088
		// Run a security check first.
1089
		check_ajax_referer( 'mi-admin-nonce', 'nonce' );
1090
1091
		$keyword  = isset( $_POST['keyword'] ) ? sanitize_text_field( wp_unslash( $_POST['keyword'] ) ) : '';
1092
		$taxonomy = isset( $_POST['taxonomy'] ) ? sanitize_text_field( wp_unslash( $_POST['taxonomy'] ) ) : 'category';
1093
1094
		$args = array(
1095
			'taxonomy'   => array( $taxonomy ),
1096
			'hide_empty' => false,
1097
			'name__like' => $keyword,
1098
		);
1099
1100
		$terms = get_terms( $args );
1101
		$array = array();
1102
1103
		if ( ! empty( $terms ) ) {
1104
			foreach ( $terms as $term ) {
1105
				$array[] = array(
1106
					'id'   => esc_attr( $term->term_id ),
1107
					'text' => esc_attr( $term->name ),
1108
				);
1109
			}
1110
		}
1111
1112
		wp_send_json_success( $array );
1113
	}
1114
1115
	/**
1116
	 * Get the post types in a name => Label array.
1117
	 */
1118
	public function get_post_types() {
1119
1120
		// Run a security check first.
1121
		check_ajax_referer( 'mi-admin-nonce', 'nonce' );
1122
1123
		$post_types_args = array(
1124
			'public' => true,
1125
		);
1126
		$post_types      = get_post_types( $post_types_args, 'objects' );
1127
1128
		$post_types_parsed = array();
1129
1130
		foreach ( $post_types as $post_type ) {
1131
			// Exclude post types that don't support the content editor.
1132
			// Exclude the WooCommerce product post type as that doesn't use the "the_content" filter and we can't auto-add popular posts to it.
1133
			if ( ! post_type_supports( $post_type->name, 'editor' ) || 'product' === $post_type->name ) {
1134
				continue;
1135
			}
1136
			$post_types_parsed[ $post_type->name ] = $post_type->labels->singular_name;
1137
		}
1138
1139
		$post_types_parsed = apply_filters( 'monsterinsights_vue_post_types_editor', $post_types_parsed );
1140
1141
		wp_send_json( $post_types_parsed );
1142
1143
	}
1144
1145
1146
	public function check_popular_posts_report() {
1147
1148
		check_ajax_referer( 'mi-admin-nonce', 'nonce' );
1149
1150
		if ( ! current_user_can( 'monsterinsights_view_dashboard' ) ) {
1151
			wp_send_json_error( array( 'message' => __( "You don't have permission to view MonsterInsights reports.", 'google-analytics-for-wordpress' ) ) );
1152
		}
1153
1154
		if ( ! empty( $_REQUEST['isnetwork'] ) && $_REQUEST['isnetwork'] ) {
1155
			define( 'WP_NETWORK_ADMIN', true );
1156
		}
1157
		$settings_page = admin_url( 'admin.php?page=monsterinsights_settings' );
1158
1159
		// Only for Pro users, require a license key to be entered first so we can link to things.
1160
		if ( monsterinsights_is_pro_version() ) {
1161
			if ( ! MonsterInsights()->license->is_site_licensed() && ! MonsterInsights()->license->is_network_licensed() ) {
1162
				wp_send_json_error( array(
1163
					'message' => __( "You can't view MonsterInsights reports because you are not licensed.", 'google-analytics-for-wordpress' ),
1164
					'footer'  => '<a href="' . $settings_page . '">' . __( 'Add your license', 'google-analytics-for-wordpress' ) . '</a>',
1165
				) );
1166
			} else if ( MonsterInsights()->license->is_site_licensed() && ! MonsterInsights()->license->site_license_has_error() ) {
1167
				// Good to go: site licensed.
1168
			} else if ( MonsterInsights()->license->is_network_licensed() && ! MonsterInsights()->license->network_license_has_error() ) {
1169
				// Good to go: network licensed.
1170
			} else {
1171
				wp_send_json_error( array( 'message' => __( 'You can\'t view MonsterInsights reports due to license key errors.', 'google-analytics-for-wordpress' ) ) );
1172
			}
1173
		}
1174
1175
		// We do not have a current auth.
1176
		$site_auth = MonsterInsights()->auth->get_viewname();
1177
		$ms_auth   = is_multisite() && MonsterInsights()->auth->get_network_viewname();
1178
		if ( ! $site_auth && ! $ms_auth ) {
1179
			wp_send_json_error( array( 'message' => __( 'You must authenticate with MonsterInsights before you can view reports.', 'google-analytics-for-wordpress' ) ) );
1180
		}
1181
1182
		$report_name = 'popularposts';
1183
1184
		if ( empty( $report_name ) ) {
1185
			wp_send_json_error( array( 'message' => __( 'Unknown report. Try refreshing and retrying. Contact support if this issue persists.', 'google-analytics-for-wordpress' ) ) );
1186
		}
1187
1188
		$report = MonsterInsights()->reporting->get_report( $report_name );
1189
1190
		$isnetwork = ! empty( $_REQUEST['isnetwork'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['isnetwork'] ) ) : '';
1191
		$start     = ! empty( $_POST['start'] ) ? sanitize_text_field( wp_unslash( $_POST['start'] ) ) : $report->default_start_date();
1192
		$end       = ! empty( $_POST['end'] ) ? sanitize_text_field( wp_unslash( $_POST['end'] ) ) : $report->default_end_date();
1193
1194
		$args = array(
1195
			'start' => $start,
1196
			'end'   => $end,
1197
		);
1198
1199
		if ( $isnetwork ) {
1200
			$args['network'] = true;
1201
		}
1202
1203
		if ( monsterinsights_is_pro_version() && ! MonsterInsights()->license->license_can( $report->level ) ) {
1204
			$data = array(
1205
				'success' => false,
1206
				'error'   => 'license_level',
1207
			);
1208
		} else {
1209
			$data = apply_filters( 'monsterinsights_vue_reports_data', $report->get_data( $args ), $report_name, $report );
1210
		}
1211
1212
		if ( ! empty( $data['success'] ) && ! empty( $data['data'] ) ) {
1213
			wp_send_json_success( $data['data'] );
1214
		} else if ( isset( $data['success'] ) && false === $data['success'] && ! empty( $data['error'] ) ) {
1215
			// Use a custom handler for invalid_grant errors.
1216
			if ( strpos( $data['error'], 'invalid_grant' ) > 0 ) {
1217
				wp_send_json_error(
1218
					array(
1219
						'message' => 'invalid_grant',
1220
						'footer'  => '',
1221
					)
1222
				);
1223
			}
1224
1225
			wp_send_json_error(
1226
				array(
1227
					'message' => $data['error'],
1228
					'footer'  => isset( $data['data']['footer'] ) ? $data['data']['footer'] : '',
1229
				)
1230
			);
1231
		}
1232
1233
		wp_send_json_error( array( 'message' => __( 'We encountered an error when fetching the report data.', 'google-analytics-for-wordpress' ) ) );
1234
1235
	}
1236
1237
	/**
1238
	 * Ajax handler for popular posts theme customization settings.
1239
	 * Specific theme styles are stored separately so we can handle 20+ themes with their specific settings.
1240
	 */
1241
	public function update_popular_posts_theme_setting() {
1242
1243
		check_ajax_referer( 'mi-admin-nonce', 'nonce' );
1244
1245
		if ( ! current_user_can( 'monsterinsights_save_settings' ) ) {
1246
			return;
1247
		}
1248
1249
		if ( ! empty( $_POST['type'] ) && ! empty( $_POST['theme'] ) && ! empty( $_POST['object'] ) && ! empty( $_POST['key'] ) && ! empty( $_POST['value'] ) ) {
1250
			$settings_key = 'monsterinsights_popular_posts_theme_settings';
1251
			$type         = sanitize_text_field( wp_unslash( $_POST['type'] ) ); // Type of Popular Posts instance: inline/widget/products.
1252
			$theme        = sanitize_text_field( wp_unslash( $_POST['theme'] ) );
1253
			$object       = sanitize_text_field( wp_unslash( $_POST['object'] ) ); // Style object like title, label, background, etc.
1254
			$key          = sanitize_text_field( wp_unslash( $_POST['key'] ) ); // Style key for the object like color, font size, etc.
1255
			$value        = sanitize_text_field( wp_unslash( $_POST['value'] ) ); // Value of custom style like 12px or #fff.
1256
			$settings     = get_option( $settings_key, array() );
1257
1258
			if ( ! isset( $settings[ $type ] ) ) {
1259
				$settings[ $type ] = array();
1260
			}
1261
			if ( ! isset( $settings[ $type ][ $theme ] ) ) {
1262
				$settings[ $type ][ $theme ] = array();
1263
			}
1264
1265
			if ( ! isset( $settings[ $type ][ $theme ][ $object ] ) ) {
1266
				$settings[ $type ][ $theme ][ $object ] = array();
1267
			}
1268
1269
			$settings[ $type ][ $theme ][ $object ][ $key ] = $value;
1270
1271
			update_option( $settings_key, $settings );
1272
1273
			wp_send_json_success();
1274
		}
1275
1276
		wp_send_json_error();
1277
1278
	}
1279
}
1280