Completed
Pull Request — master (#2229)
by
unknown
05:05
created

WPSC_Tracking::admin_notice()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 24
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 16
nc 4
nop 0
dl 0
loc 24
rs 8.6845
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style introduced by
End of line character is invalid; expected "\n" but found "\r\n"
Loading history...
2
3
/**
4
 * Tracking functions for reporting plugin usage to the WPEC site for users that have opted in
5
 *
6
 * @package     WPEC
7
 * @subpackage  Admin
8
 * @copyright   Copyright (c) 2017
9
 * @license     http://opensource.org/licenses/gpl-2.0.php GNU Public License
10
 * @since       3.12.0
11
*/
12
13
// Exit if accessed directly
14
if ( ! defined( 'ABSPATH' ) ) exit;
15
16
/**
17
 * Usage tracking
18
 *
19
 * @access public
20
 * @since  3.12.0
21
 * @return void
22
 */
23
class WPSC_Tracking {
24
25
	/**
26
	 * The data to send to the WPEC site
27
	 *
28
	 * @since 3.12.0
29
	 * @access private
30
	 */
31
	private $data;
32
33
	/**
34
	 * Where we are sending the data to
35
	 *
36
	 * @since 3.12.0
37
	 * @access private
38
	 */
39
	private $api_url = 'https://wpecommerce.org/';
40
41
	/**
42
	 * Get things going
43
	 *
44
	 * @since 3.12.0
45
	 * @access public
46
	 */
47
	public function __construct() {
48
		add_action( 'init'                           , array( $this, 'schedule_send' ) );
49
		add_action( 'wpsc_opt_into_tracking'         , array( $this, 'check_for_optin' ) );
50
		add_action( 'wpsc_opt_out_of_tracking'       , array( $this, 'check_for_optout' ) );
51
		add_action( 'wpsc_settings_page_save_options', array( $this, 'check_for_settings_optin' ), 10, 2 );
52
		add_action( 'admin_notices'                  , array( $this, 'admin_notice' ) );
53
	}
54
55
	/**
56
	 * Schedule a weekly checkin
57
	 *
58
	 * @since 3.12.0
59
	 * @access public
60
	 * @return void
61
	 */
62
	public function schedule_send() {
63
64
		if ( isset( $_REQUEST['wpsc_tracking_action'] ) && ( $_REQUEST['wpsc_tracking_action'] == 'opt_into_tracking' ) ) {
65
			do_action( 'wpsc_opt_into_tracking' );
66
		}
67
68
		if ( isset( $_REQUEST['wpsc_tracking_action'] ) && ( $_REQUEST['wpsc_tracking_action'] == 'opt_out_of_tracking' ) ) {
69
			do_action( 'wpsc_opt_out_of_tracking' );
70
		}
71
72
		// We send once a week (while tracking is allowed) to check in, which can be used to determine active sites
73
		add_action( 'wpsc_weekly_cron_task', array( $this, 'send_data' ) );
74
	}
75
76
	/**
77
	 * Check if the user has opted into tracking
78
	 *
79
	 * @since 3.12.0
80
	 * @access private
81
	 * @return bool
82
	 */
83
	private function tracking_allowed() {
84
		return (bool) get_option( 'wpsc_usage_tracking', false );
85
	}
86
87
	/**
88
	 * Get the last time a checkin was sent
89
	 *
90
	 * @since 3.12.0
91
	 * @access private
92
	 * @return false|string
93
	 */
94
	private function get_last_send() {
95
		return get_option( 'wpsc_usage_tracking_last_send' );
96
	}
97
98
	/**
99
	 * Send the data to the WPEC server
100
	 *
101
	 * @since 3.12.0
102
	 * @access private
103
	 * @return void
104
	 */
105
	public function send_data( $override = false ) {
106
107
		if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
108
			return;
109
		}
110
111
		$home_url = trailingslashit( home_url() );
112
113
		// Allows us to stop our own site from checking in, and a filter for our additional sites
114
		if ( true === apply_filters( 'wpsc_disable_tracking_checkin', false ) ) {
115
			return false;
116
		}
117
118
		if ( ! $this->tracking_allowed() && ! $override ) {
119
			return false;
120
		}
121
122
		// Send a maximum of once per week
123
		$last_send = $this->get_last_send();
124
125
		if ( is_numeric( $last_send ) && $last_send > strtotime( '-1 week' ) ) {
126
			return false;
127
		}
128
129
		$this->setup_data();
130
131
		$request = wp_safe_remote_post( $this->api_url . '?wpsc_tracking_action=checkin', array(
132
			'timeout'     => 20,
133
			'redirection' => 5,
134
			'httpversion' => '1.1',
135
			'blocking'    => true,
136
			'body'        => $this->data,
137
			'user-agent'  => 'WPEC/' . WPSC_VERSION . '; ' . get_bloginfo( 'url' )
138
		) );
139
140
		if ( is_wp_error( $request ) ) {
141
			return $request;
142
		}
143
144
		update_option( 'wpsc_usage_tracking_last_send', time() );
145
146
		return true;
147
	}
148
149
	/**
150
	 * Check for a new opt-in via the admin notice
151
	 *
152
	 * @since 3.12.0
153
	 * @access public
154
	 * @return void
155
	 */
156
	public function check_for_optin() {
157
158
		update_option( 'wpsc_usage_tracking', '1' );
159
160
		$this->send_data( true );
161
162
		update_option( 'wpsc_usage_tracking_notice', '1' );
163
164
		wp_safe_redirect( esc_url_raw( remove_query_arg( 'wpsc_tracking_action' ) ) );
165
		exit;
166
	}
167
168
	/**
169
	 * Check for opt-out via the admin notice
170
	 *
171
	 * @since 3.12.0
172
	 * @access public
173
	 * @return void
174
	 */
175
	public function check_for_optout() {
176
177
		$allowed = get_option( 'wpsc_usage_tracking', false );
178
179
		if ( $allowed ) {
180
			delete_option( 'wpsc_usage_tracking' );
181
		}
182
183
		update_option( 'wpsc_usage_tracking_notice', '1' );
184
185
		wp_safe_redirect( esc_url_raw( remove_query_arg( 'wpsc_tracking_action' ) ) );
186
		exit;
187
	}
188
189
	/**
190
	 * Check for opt-in via the settings page
191
	 *
192
	 * @since 3.12.0
193
	 * @access public
194
	 * @return void
195
	 */
196
	public function check_for_settings_optin( $option, $value ) {
197
		if( isset( $option ) && $option == 'wpsc_usage_tracking' && $value == '1'  ) {
198
			$this->send_data( true );
199
		}
200
	}
201
202
	/**
203
	 * Display the admin notice to users that have not opted-in or out
204
	 *
205
	 * @since 3.12.0
206
	 * @access public
207
	 * @return void
208
	 */
209
	public function admin_notice() {
210
		$hide_notice = get_option( 'wpsc_usage_tracking_notice' );
211
212
		if ( $hide_notice ) {
213
			return;
214
		}
215
216
		if ( get_option( 'wpsc_usage_tracking', false ) ) {
217
			return;
218
		}
219
220
		if ( ! current_user_can( 'manage_options' ) ) {
221
			return;
222
		}
223
224
		$optin_url  = esc_url_raw( add_query_arg( 'wpsc_tracking_action', 'opt_into_tracking' ) );
225
		$optout_url = esc_url_raw( add_query_arg( 'wpsc_tracking_action', 'opt_out_of_tracking' ) );
226
		$extensions_url = $this->api_url . 'store/';
227
		echo '<div class="updated"><p>';
228
			echo sprintf( __( 'Allow WP eCommerce to track plugin usage? Opt-in to tracking and our newsletter and immediately be emailed a 20%s discount to the WPEC shop, valid towards the <a href="%s" target="_blank">purchase of extensions</a>. No sensitive data is tracked.', 'wp-e-commerce' ), '%', $extensions_url );
229
			echo '&nbsp;<a href="' . esc_url( $optin_url ) . '" class="button-secondary">' . __( 'Allow', 'wp-e-commerce' ) . '</a>';
230
			echo '&nbsp;<a href="' . esc_url( $optout_url ) . '" class="button-secondary">' . __( 'Do not allow', 'wp-e-commerce' ) . '</a>';
231
		echo '</p></div>';
232
	}
233
234
	/**
235
	 * Setup the data that is going to be tracked
236
	 *
237
	 * @since 3.12.0
238
	 * @access private
239
	 * @return void
240
	 */
241
	private function setup_data() {
242
243
		$data = array();
244
245
		// General site info
246
		$data['url']                = home_url();
247
		$data['email']              = get_option( 'admin_email' );
248
249
		// Theme info
250
		$data['theme']              = self::get_theme_info();
251
252
		// WordPress Info
253
		$data['wp']                 = self::get_wordpress_info();
254
255
		// Server Info
256
		$data['server']             = self::get_server_info();
257
258
		// Plugin info
259
		$all_plugins                = self::get_all_plugins();
260
		$data['active_plugins']     = $all_plugins['active_plugins'];
261
		$data['inactive_plugins']   = $all_plugins['inactive_plugins'];
262
263
		// WPEC Related Section
264
		$data['wpec']               = self::get_wpec_info();
265
266
		// Store count info
267
		$data['users']              = self::get_user_counts();
268
		$data['products']           = self::get_product_counts();
269
		$data['orders']             = self::get_order_counts();
270
271
		// Payment gateway info
272
		$data['gateways']           = self::get_active_payment_gateways();
273
274
		// Shipping method info
275
		$data['shipping_methods']   = self::get_active_shipping_methods();
276
277
		// Template overrides
278
		$data['template_overrides'] = self::get_all_template_overrides();
279
280
		$this->data = $data;
281
	}
282
283
	/**
284
	 * Get the current theme info, theme name and version.
285
	 *
286
	 * @since 3.12.0
287
	 * @return array
288
	 */
289
	public static function get_theme_info() {
290
		$theme_data        = wp_get_theme();
291
292
		return array(
293
			'name'        => $theme_data->Name,
294
			'version'     => $theme_data->Version,
295
			'child_theme' => is_child_theme() ? 'Yes' : 'No'
296
		);
297
	}
298
299
	/**
300
	 * Get WordPress related data.
301
	 *
302
	 * @since 3.12.0
303
	 * @return array
304
	 */
305
	private static function get_wordpress_info() {
306
		$wp_data = array();
307
308
		$memory = self::wpsc_let_to_num( WP_MEMORY_LIMIT );
309
310
		if ( function_exists( 'memory_get_usage' ) ) {
311
			$system_memory = self::wpsc_let_to_num( @ini_get( 'memory_limit' ) );
0 ignored issues
show
Coding Style introduced by
Silencing errors is discouraged
Loading history...
312
			$memory        = max( $memory, $system_memory );
313
		}
314
315
		$wp_data['memory_limit'] = size_format( $memory );
316
		$wp_data['debug_mode']   = ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ? 'Yes' : 'No';
317
		$wp_data['locale']       = get_locale();
318
		$wp_data['version']      = get_bloginfo( 'version' );
319
		$wp_data['multisite']    = is_multisite() ? 'Yes' : 'No';
320
321
		return $wp_data;
322
	}
323
324
	/**
325
	 * Get server related info.
326
	 *
327
	 * @since 3.12.0
328
	 * @return array
329
	 */
330
	private static function get_server_info() {
331
		$server_data = array();
332
333
		if ( isset( $_SERVER['SERVER_SOFTWARE'] ) && ! empty( $_SERVER['SERVER_SOFTWARE'] ) ) {
334
			$server_data['software'] = $_SERVER['SERVER_SOFTWARE'];
335
		}
336
337
		if ( function_exists( 'phpversion' ) ) {
338
			$server_data['php_version'] = phpversion();
339
		}
340
341
		if ( function_exists( 'ini_get' ) ) {
342
			$server_data['php_post_max_size'] = size_format( self::wpsc_let_to_num( ini_get( 'post_max_size' ) ) );
343
			$server_data['php_time_limt']      = ini_get( 'max_execution_time' );
344
			$server_data['php_max_input_vars'] = ini_get( 'max_input_vars' );
345
			$server_data['php_suhosin']        = extension_loaded( 'suhosin' ) ? 'Yes' : 'No';
346
		}
347
348
		global $wpdb;
349
350
		$server_data['mysql_version'] = $wpdb->db_version();
351
352
		$server_data['php_max_upload_size']  = size_format( wp_max_upload_size() );
353
		$server_data['php_default_timezone'] = date_default_timezone_get();
354
		$server_data['php_soap']             = class_exists( 'SoapClient' )   ? 'Yes' : 'No';
355
		$server_data['php_fsockopen']        = function_exists( 'fsockopen' ) ? 'Yes' : 'No';
356
		$server_data['php_curl']             = function_exists( 'curl_init' ) ? 'Yes' : 'No';
357
358
		return $server_data;
359
	}
360
361
	/**
362
	 * Get all plugins grouped into activated or not.
363
	 *
364
	 * @since 3.12.0
365
	 * @return array
366
	 */
367
	private static function get_all_plugins() {
368
369
		// Ensure get_plugins function is loaded
370
		if ( ! function_exists( 'get_plugins' ) ) {
371
			include ABSPATH . '/wp-admin/includes/plugin.php';
372
		}
373
374
		$plugins        	 = get_plugins();
375
		$active_plugins_keys = get_option( 'active_plugins', array() );
376
		$active_plugins 	 = array();
377
378
		foreach ( $plugins as $k => $v ) {
379
			// Take care of formatting the data how we want it.
380
			$formatted = array();
381
			$formatted['name'] = strip_tags( $v['Name'] );
382
383
			if ( isset( $v['Version'] ) ) {
384
				$formatted['version'] = strip_tags( $v['Version'] );
385
			}
386
387
			if ( isset( $v['Author'] ) ) {
388
				$formatted['author'] = strip_tags( $v['Author'] );
389
			}
390
391
			if ( isset( $v['Network'] ) ) {
392
				$formatted['network'] = strip_tags( $v['Network'] );
393
			}
394
395
			if ( isset( $v['PluginURI'] ) ) {
396
				$formatted['plugin_uri'] = strip_tags( $v['PluginURI'] );
397
			}
398
399
			if ( in_array( $k, $active_plugins_keys ) ) {
400
				// Remove active plugins from list so we can show active and inactive separately
401
				unset( $plugins[ $k ] );
402
				$active_plugins[ $k ] = $formatted;
403
			} else {
404
				$plugins[ $k ] = $formatted;
405
			}
406
		}
407
408
		return array(
409
			'active_plugins'   => $active_plugins,
410
			'inactive_plugins' => $plugins
411
		);
412
	}
413
414
	/**
415
	 * Get WP eCommerce related info.
416
	 *
417
	 * @since 3.12.0
418
	 * @return array
419
	 */
420
	private static function get_wpec_info() {
421
		$wpec_data = array();
422
423
		$wpec_data['version'] = WPSC_VERSION;
424
		$wpec_data['url']     = WPSC_URL;
425
		$wpec_data['debug']   = WPSC_DEBUG;
426
427
		return $wpec_data;
428
	}
429
430
	/**
431
	 * Get user totals based on user role.
432
	 *
433
	 * @since 3.12.0
434
	 * @return array
435
	 */
436
	private static function get_user_counts() {
437
		$user_count          = array();
438
439
		$user_count_data     = count_users();
440
		$user_count['total'] = $user_count_data['total_users'];
441
442
		// Get user count based on user role
443
		foreach ( $user_count_data['avail_roles'] as $role => $count ) {
444
			$user_count[ $role ] = $count;
445
		}
446
447
		return $user_count;
448
	}
449
450
	/**
451
	 * Get product totals based on product type.
452
	 *
453
	 * @since 3.12.0
454
	 * @return array
455
	 */
456
	private static function get_product_counts() {
457
		$product_count          = array();
458
459
		$product_count_data     = wp_count_posts( 'wpsc-product' );
460
		$product_count['total'] = $product_count_data->publish;
461
462
		return $product_count;
463
	}
464
465
	/**
466
	 * Get order counts based on order status.
467
	 *
468
	 * @since 3.12.0
469
	 * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
470
	 */
471
	private static function get_order_counts() {
472
		global $wpdb;
473
474
		$order_count = array();
475
		$curr_year   = date( 'Y' );
476
477
		$result = $wpdb->get_row(
478
			"SELECT FROM_UNIXTIME( DATE,  '%Y' ) AS year
479
			FROM `" . WPSC_TABLE_PURCHASE_LOGS . "`
480
			WHERE FROM_UNIXTIME( DATE,  '%Y' ) > 2000
481
			AND processed IN ( 3, 4, 5 )
482
			ORDER BY date ASC
483
			LIMIT 1 ", ARRAY_A
484
		);
485
486
		$start_year = $result['year'];
487
488
		if ( $start_year ) {
489
			while ( $start_year <= $curr_year ) {
490
				$sql = $wpdb->prepare(
491
					"SELECT SUM(`totalprice`) as total,
492
					COUNT(*) as cnt
493
					FROM `" . WPSC_TABLE_PURCHASE_LOGS . "`
494
					WHERE `processed` IN (3,4,5) AND `date` BETWEEN %s AND %s",
495
					mktime( 0, 0, 0, 1, 1, $start_year ),
496
					mktime( 23, 59, 59, 12, 31, $start_year )
497
				);
498
499
				$orders = $wpdb->get_row( $sql, ARRAY_A );
500
501
				if ( $orders ) {
502
					$order_count[ $start_year ] = array(
503
						'orders' => $orders['cnt'],
504
						'total'  => $orders['total']
505
					);
506
				}
507
508
				$start_year++;
509
			}
510
		}
511
512
		$currency_data           = WPSC_Countries::get_currency_data( get_option( 'currency_type' ), true );
513
		$order_count['currency'] = $currency_data['code'];
514
515
		return $order_count;
516
	}
517
518
	/**
519
	 * Get a list of all active payment gateways.
520
	 *
521
	 * @since 3.12.0
522
	 * @return array
523
	 */
524
	private static function get_active_payment_gateways() {
525
		$active_gateways = array();
526
527
		// First get merchant V2 gateways
528
		if ( _wpsc_is_merchant_v2_active() ) {
529
			$gateways = _wpsc_merchant_v2_get_active_gateways();
530
531
			if ( ! empty( $gateways ) ) {
532
				foreach ( $gateways as $id => $gateway ) {
533
					$active_gateways['mv2'][ $id ] = array( 'title' => $gateway['name'] );
534
				}
535
			}
536
		}
537
538
		// Merchant V3 gateways if any
539
		$gateways = WPSC_Payment_Gateways::get_active_gateways();
540
541
		if ( ! empty( $gateways ) ) {
542
			foreach ( $gateways as $id => $gateway ) {
543
				$meta = WPSC_Payment_Gateways::get_meta( $gateway );
544
				$name = isset( $meta['name'] ) ? $meta['name'] : $meta['class'];
545
546
				$active_gateways['mv3'][ $id ] = array( 'title' => $name );
547
			}
548
		}
549
550
		return $active_gateways;
551
	}
552
553
	/**
554
	 * Get a list of all active shipping methods.
555
	 *
556
	 * @since 3.12.0
557
	 * @return array
558
	 */
559
	private static function get_active_shipping_methods() {
560
		$active_methods   = array();
561
562
		if ( wpsc_is_shipping_enabled() ) {
563
			global $wpsc_shipping_modules;
564
565
			$custom_shipping = get_option( 'custom_shipping_options' );
566
567
			foreach ( (array) $custom_shipping as $id => $shipping ) {
568
				$module_title = isset( $wpsc_shipping_modules[ $shipping ] ) && is_callable( array( $wpsc_shipping_modules[ $shipping ], 'getName' ) ) ? $wpsc_shipping_modules[ $shipping ]->getName() : '';
569
				$active_methods[ $id ] = array( 'name' => $shipping, 'title' => $module_title );
570
			}
571
		}
572
573
		return $active_methods;
574
	}
575
576
	/**
577
	 * Look for any template override and return filenames.
578
	 *
579
	 * @todo Implement a method of checking template overrides for tev2.
580
	 * @since 3.12.0
581
	 * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be array|false? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
582
	 */
583
	private static function get_all_template_overrides() {
584
		$override_data  = array();
585
586
		$te = get_option( 'wpsc_get_active_theme_engine', '1.0' );
587
588
		if( '1.0' == $te ) {
589
			$override_data = wpsc_check_theme_location();
590
		}
591
592
		return $override_data;
593
	}
594
595
	/**
596
	 * let_to_num function.
597
	 *
598
	 * This function transforms the php.ini notation for numbers (like '2M') to an integer.
599
	 *
600
	 * @since 3.12.0
601
	 * @param $size
602
	 * @return int
603
	 */
604
	private static function wpsc_let_to_num( $size ) {
605
		$l   = substr( $size, -1 );
606
		$ret = substr( $size, 0, -1 );
607
		switch ( strtoupper( $l ) ) {
608
			case 'P':
609
				$ret *= 1024;
610
			case 'T':
611
				$ret *= 1024;
612
			case 'G':
613
				$ret *= 1024;
614
			case 'M':
615
				$ret *= 1024;
616
			case 'K':
617
				$ret *= 1024;
618
		}
619
		return $ret;
620
	}
621
}
622
623
$wpsc_tracking = new WPSC_Tracking;
624