Completed
Push — master ( 9a3ee6...bca146 )
by Justin
05:42
created

WPSC_Tracking   D

Complexity

Total Complexity 81

Size/Duplication

Total Lines 601
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
dl 0
loc 601
rs 4.8678
c 0
b 0
f 0
wmc 81
lcom 1
cbo 3

22 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
B capture_tracking_settings() 0 10 5
A tracking_allowed() 0 3 1
A get_last_send() 0 3 1
D send_data() 0 43 9
A check_for_optin() 0 11 1
A check_for_optout() 0 13 2
A check_for_settings_optin() 0 5 4
B admin_notice() 0 24 4
B setup_data() 0 43 1
A get_theme_info() 0 9 2
B get_wordpress_info() 0 18 5
D get_server_info() 0 30 9
C get_all_plugins() 0 46 8
A get_wpec_info() 0 12 1
A get_user_counts() 0 13 2
A get_product_counts() 0 8 1
B get_order_counts() 0 46 4
C get_active_payment_gateways() 0 28 7
B get_active_shipping_methods() 0 16 5
A get_all_template_overrides() 0 11 2
B wpsc_let_to_num() 0 17 6

How to fix   Complexity   

Complex Class

Complex classes like WPSC_Tracking often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use WPSC_Tracking, and based on these observations, apply Extract Interface, too.

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( 'admin_init'                     , array( $this, 'capture_tracking_settings' ) );
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 capture_tracking_settings() {
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
73
	/**
74
	 * Check if the user has opted into tracking
75
	 *
76
	 * @since 3.12.0
77
	 * @access private
78
	 * @return bool
79
	 */
80
	private function tracking_allowed() {
81
		return (bool) get_option( 'wpsc_usage_tracking', false );
82
	}
83
84
	/**
85
	 * Get the last time a checkin was sent
86
	 *
87
	 * @since 3.12.0
88
	 * @access private
89
	 * @return false|string
90
	 */
91
	private function get_last_send() {
92
		return get_option( 'wpsc_usage_tracking_last_send' );
93
	}
94
95
	/**
96
	 * Send the data to the WPEC server
97
	 *
98
	 * @since 3.12.0
99
	 * @access private
100
	 * @return void
101
	 */
102
	public function send_data( $override = false ) {
103
104
		if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
105
			return;
106
		}
107
108
		$home_url = trailingslashit( home_url() );
109
110
		// Allows us to stop our own site from checking in, and a filter for our additional sites
111
		if ( true === apply_filters( 'wpsc_disable_tracking_checkin', false ) ) {
112
			return false;
113
		}
114
115
		if ( ! $this->tracking_allowed() && ! $override ) {
116
			return false;
117
		}
118
119
		// Send a maximum of once per week
120
		$last_send = $this->get_last_send();
121
122
		if ( is_numeric( $last_send ) && $last_send > strtotime( '-1 week' ) ) {
123
			return false;
124
		}
125
126
		$this->setup_data();
127
128
		$request = wp_safe_remote_post( $this->api_url . '?wpsc_tracking_action=checkin', array(
129
			'timeout'     => 20,
130
			'redirection' => 5,
131
			'httpversion' => '1.1',
132
			'blocking'    => true,
133
			'body'        => $this->data,
134
			'user-agent'  => 'WPEC/' . WPSC_VERSION . '; ' . get_bloginfo( 'url' )
135
		) );
136
137
		if ( is_wp_error( $request ) ) {
138
			return $request;
139
		}
140
141
		update_option( 'wpsc_usage_tracking_last_send', time() );
142
143
		return true;
144
	}
145
146
	/**
147
	 * Check for a new opt-in via the admin notice
148
	 *
149
	 * @since 3.12.0
150
	 * @access public
151
	 * @return void
152
	 */
153
	public function check_for_optin() {
154
155
		update_option( 'wpsc_usage_tracking', '1' );
156
157
		$this->send_data( true );
158
159
		update_option( 'wpsc_usage_tracking_notice', '1' );
160
161
		wp_safe_redirect( esc_url_raw( remove_query_arg( 'wpsc_tracking_action' ) ) );
162
		exit;
163
	}
164
165
	/**
166
	 * Check for opt-out via the admin notice
167
	 *
168
	 * @since 3.12.0
169
	 * @access public
170
	 * @return void
171
	 */
172
	public function check_for_optout() {
173
174
		$allowed = get_option( 'wpsc_usage_tracking', false );
175
176
		if ( $allowed ) {
177
			delete_option( 'wpsc_usage_tracking' );
178
		}
179
180
		update_option( 'wpsc_usage_tracking_notice', '1' );
181
182
		wp_safe_redirect( esc_url_raw( remove_query_arg( 'wpsc_tracking_action' ) ) );
183
		exit;
184
	}
185
186
	/**
187
	 * Check for opt-in via the settings page
188
	 *
189
	 * @since 3.12.0
190
	 * @access public
191
	 * @return void
192
	 */
193
	public function check_for_settings_optin( $option, $value ) {
194
		if( isset( $option ) && $option == 'wpsc_usage_tracking' && $value == '1'  ) {
195
			$this->send_data( true );
196
		}
197
	}
198
199
	/**
200
	 * Display the admin notice to users that have not opted-in or out
201
	 *
202
	 * @since 3.12.0
203
	 * @access public
204
	 * @return void
205
	 */
206
	public function admin_notice() {
207
		$hide_notice = get_option( 'wpsc_usage_tracking_notice' );
208
209
		if ( $hide_notice ) {
210
			return;
211
		}
212
213
		if ( get_option( 'wpsc_usage_tracking', false ) ) {
214
			return;
215
		}
216
217
		if ( ! current_user_can( 'manage_options' ) ) {
218
			return;
219
		}
220
221
		$optin_url  = esc_url_raw( add_query_arg( 'wpsc_tracking_action', 'opt_into_tracking' ) );
222
		$optout_url = esc_url_raw( add_query_arg( 'wpsc_tracking_action', 'opt_out_of_tracking' ) );
223
		$extensions_url = $this->api_url . 'store/';
224
		echo '<div class="updated"><p>';
225
			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 );
226
			echo '&nbsp;<a href="' . esc_url( $optin_url ) . '" class="button-secondary">' . __( 'Allow', 'wp-e-commerce' ) . '</a>';
227
			echo '&nbsp;<a href="' . esc_url( $optout_url ) . '" class="button-secondary">' . __( 'Do not allow', 'wp-e-commerce' ) . '</a>';
228
		echo '</p></div>';
229
	}
230
231
	/**
232
	 * Setup the data that is going to be tracked
233
	 *
234
	 * @since 3.12.0
235
	 * @access private
236
	 * @return void
237
	 */
238
	private function setup_data() {
239
240
		$data = array();
241
242
		// General site info
243
		$data['url']                = home_url();
244
		$data['email']              = get_option( 'admin_email' );
245
		$data['first_name']         = wp_get_current_user()->first_name;
246
		$data['last_name']          = wp_get_current_user()->last_name;
247
248
		// Theme info
249
		$data['theme']              = self::get_theme_info();
250
251
		// WordPress Info
252
		$data['wp']                 = self::get_wordpress_info();
253
254
		// Server Info
255
		$data['server']             = self::get_server_info();
256
257
		// Plugin info
258
		$all_plugins                = self::get_all_plugins();
259
		$data['active_plugins']     = $all_plugins['active_plugins'];
260
		$data['inactive_plugins']   = $all_plugins['inactive_plugins'];
261
262
		// WPEC Related Section
263
		$data['wpec']               = self::get_wpec_info();
264
265
		// Store count info
266
		$data['users']              = self::get_user_counts();
267
		$data['products']           = self::get_product_counts();
268
		$data['orders']             = self::get_order_counts();
269
270
		// Payment gateway info
271
		$data['gateways']           = self::get_active_payment_gateways();
272
273
		// Shipping method info
274
		$data['shipping_methods']   = self::get_active_shipping_methods();
275
276
		// Template overrides
277
		$data['template_overrides'] = self::get_all_template_overrides();
278
279
		$this->data = $data;
280
	}
281
282
	/**
283
	 * Get the current theme info, theme name and version.
284
	 *
285
	 * @since 3.12.0
286
	 * @return array
287
	 */
288
	public static function get_theme_info() {
289
		$theme_data        = wp_get_theme();
290
291
		return array(
292
			'name'        => $theme_data->Name,
293
			'version'     => $theme_data->Version,
294
			'child_theme' => is_child_theme() ? 'Yes' : 'No'
295
		);
296
	}
297
298
	/**
299
	 * Get WordPress related data.
300
	 *
301
	 * @since 3.12.0
302
	 * @return array
303
	 */
304
	private static function get_wordpress_info() {
305
		$wp_data = array();
306
307
		$memory = self::wpsc_let_to_num( WP_MEMORY_LIMIT );
308
309
		if ( function_exists( 'memory_get_usage' ) ) {
310
			$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...
311
			$memory        = max( $memory, $system_memory );
312
		}
313
314
		$wp_data['memory_limit'] = size_format( $memory );
315
		$wp_data['debug_mode']   = ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ? 'Yes' : 'No';
316
		$wp_data['locale']       = get_locale();
317
		$wp_data['version']      = get_bloginfo( 'version' );
318
		$wp_data['multisite']    = is_multisite() ? 'Yes' : 'No';
319
320
		return $wp_data;
321
	}
322
323
	/**
324
	 * Get server related info.
325
	 *
326
	 * @since 3.12.0
327
	 * @return array
328
	 */
329
	private static function get_server_info() {
330
		$server_data = array();
331
332
		if ( isset( $_SERVER['SERVER_SOFTWARE'] ) && ! empty( $_SERVER['SERVER_SOFTWARE'] ) ) {
333
			$server_data['software'] = $_SERVER['SERVER_SOFTWARE'];
334
		}
335
336
		if ( function_exists( 'phpversion' ) ) {
337
			$server_data['php_version'] = phpversion();
338
		}
339
340
		if ( function_exists( 'ini_get' ) ) {
341
			$server_data['php_post_max_size'] = size_format( self::wpsc_let_to_num( ini_get( 'post_max_size' ) ) );
342
			$server_data['php_time_limt']      = ini_get( 'max_execution_time' );
343
			$server_data['php_max_input_vars'] = ini_get( 'max_input_vars' );
344
			$server_data['php_suhosin']        = extension_loaded( 'suhosin' ) ? 'Yes' : 'No';
345
		}
346
347
		global $wpdb;
348
349
		$server_data['mysql_version'] = $wpdb->db_version();
350
351
		$server_data['php_max_upload_size']  = size_format( wp_max_upload_size() );
352
		$server_data['php_default_timezone'] = date_default_timezone_get();
353
		$server_data['php_soap']             = class_exists( 'SoapClient' )   ? 'Yes' : 'No';
354
		$server_data['php_fsockopen']        = function_exists( 'fsockopen' ) ? 'Yes' : 'No';
355
		$server_data['php_curl']             = function_exists( 'curl_init' ) ? 'Yes' : 'No';
356
357
		return $server_data;
358
	}
359
360
	/**
361
	 * Get all plugins grouped into activated or not.
362
	 *
363
	 * @since 3.12.0
364
	 * @return array
365
	 */
366
	private static function get_all_plugins() {
367
368
		// Ensure get_plugins function is loaded
369
		if ( ! function_exists( 'get_plugins' ) ) {
370
			include ABSPATH . '/wp-admin/includes/plugin.php';
371
		}
372
373
		$plugins        	 = get_plugins();
374
		$active_plugins_keys = get_option( 'active_plugins', array() );
375
		$active_plugins 	 = array();
376
377
		foreach ( $plugins as $k => $v ) {
378
			// Take care of formatting the data how we want it.
379
			$formatted = array();
380
			$formatted['name'] = strip_tags( $v['Name'] );
381
382
			if ( isset( $v['Version'] ) ) {
383
				$formatted['version'] = strip_tags( $v['Version'] );
384
			}
385
386
			if ( isset( $v['Author'] ) ) {
387
				$formatted['author'] = strip_tags( $v['Author'] );
388
			}
389
390
			if ( isset( $v['Network'] ) ) {
391
				$formatted['network'] = strip_tags( $v['Network'] );
392
			}
393
394
			if ( isset( $v['PluginURI'] ) ) {
395
				$formatted['plugin_uri'] = strip_tags( $v['PluginURI'] );
396
			}
397
398
			if ( in_array( $k, $active_plugins_keys ) ) {
399
				// Remove active plugins from list so we can show active and inactive separately
400
				unset( $plugins[ $k ] );
401
				$active_plugins[ $k ] = $formatted;
402
			} else {
403
				$plugins[ $k ] = $formatted;
404
			}
405
		}
406
407
		return array(
408
			'active_plugins'   => $active_plugins,
409
			'inactive_plugins' => $plugins
410
		);
411
	}
412
413
	/**
414
	 * Get WP eCommerce related info.
415
	 *
416
	 * @since 3.12.0
417
	 * @return array
418
	 */
419
	private static function get_wpec_info() {
420
		$wpec_data = array();
421
422
		$base_country = new WPSC_Country( wpsc_get_base_country() );
423
424
		$wpec_data['version']      = WPSC_VERSION;
425
		$wpec_data['url']          = WPSC_URL;
426
		$wpec_data['base_country'] = $base_country->get_name();
427
		$wpec_data['debug']        = WPSC_DEBUG;
428
429
		return $wpec_data;
430
	}
431
432
	/**
433
	 * Get user totals based on user role.
434
	 *
435
	 * @since 3.12.0
436
	 * @return array
437
	 */
438
	private static function get_user_counts() {
439
		$user_count          = array();
440
441
		$user_count_data     = count_users();
442
		$user_count['total'] = $user_count_data['total_users'];
443
444
		// Get user count based on user role
445
		foreach ( $user_count_data['avail_roles'] as $role => $count ) {
446
			$user_count[ $role ] = $count;
447
		}
448
449
		return $user_count;
450
	}
451
452
	/**
453
	 * Get product totals based on product type.
454
	 *
455
	 * @since 3.12.0
456
	 * @return array
457
	 */
458
	private static function get_product_counts() {
459
		$product_count          = array();
460
461
		$product_count_data     = wp_count_posts( 'wpsc-product' );
462
		$product_count['total'] = $product_count_data->publish;
463
464
		return $product_count;
465
	}
466
467
	/**
468
	 * Get order counts based on order status.
469
	 *
470
	 * @since 3.12.0
471
	 * @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...
472
	 */
473
	private static function get_order_counts() {
474
		global $wpdb;
475
476
		$order_count = array();
477
		$curr_year   = date( 'Y' );
478
479
		$result = $wpdb->get_row(
480
			"SELECT FROM_UNIXTIME( DATE,  '%Y' ) AS year
481
			FROM `" . WPSC_TABLE_PURCHASE_LOGS . "`
482
			WHERE FROM_UNIXTIME( DATE,  '%Y' ) > 2000
483
			AND processed IN ( 3, 4, 5 )
484
			ORDER BY date ASC
485
			LIMIT 1 ", ARRAY_A
486
		);
487
488
		$start_year = $result['year'];
489
490
		if ( $start_year ) {
491
			while ( $start_year <= $curr_year ) {
492
				$sql = $wpdb->prepare(
493
					"SELECT SUM(`totalprice`) as total,
494
					COUNT(*) as cnt
495
					FROM `" . WPSC_TABLE_PURCHASE_LOGS . "`
496
					WHERE `processed` IN (3,4,5) AND `date` BETWEEN %s AND %s",
497
					mktime( 0, 0, 0, 1, 1, $start_year ),
498
					mktime( 23, 59, 59, 12, 31, $start_year )
499
				);
500
501
				$orders = $wpdb->get_row( $sql, ARRAY_A );
502
503
				if ( $orders ) {
504
					$order_count[ $start_year ] = array(
505
						'orders' => $orders['cnt'],
506
						'total'  => $orders['total']
507
					);
508
				}
509
510
				$start_year++;
511
			}
512
		}
513
514
		$currency_data           = WPSC_Countries::get_currency_data( get_option( 'currency_type' ), true );
515
		$order_count['currency'] = $currency_data['code'];
516
517
		return $order_count;
518
	}
519
520
	/**
521
	 * Get a list of all active payment gateways.
522
	 *
523
	 * @since 3.12.0
524
	 * @return array
525
	 */
526
	private static function get_active_payment_gateways() {
527
		$active_gateways = array();
528
529
		// First get merchant V2 gateways
530
		if ( _wpsc_is_merchant_v2_active() ) {
531
			$gateways = _wpsc_merchant_v2_get_active_gateways();
532
533
			if ( ! empty( $gateways ) ) {
534
				foreach ( $gateways as $id => $gateway ) {
535
					$active_gateways['mv2'][ $id ] = array( 'title' => $gateway['name'] );
536
				}
537
			}
538
		}
539
540
		// Merchant V3 gateways if any
541
		$gateways = WPSC_Payment_Gateways::get_active_gateways();
542
543
		if ( ! empty( $gateways ) ) {
544
			foreach ( $gateways as $id => $gateway ) {
545
				$meta = WPSC_Payment_Gateways::get_meta( $gateway );
546
				$name = isset( $meta['name'] ) ? $meta['name'] : $meta['class'];
547
548
				$active_gateways['mv3'][ $id ] = array( 'title' => $name );
549
			}
550
		}
551
552
		return $active_gateways;
553
	}
554
555
	/**
556
	 * Get a list of all active shipping methods.
557
	 *
558
	 * @since 3.12.0
559
	 * @return array
560
	 */
561
	private static function get_active_shipping_methods() {
562
		$active_methods   = array();
563
564
		if ( wpsc_is_shipping_enabled() ) {
565
			global $wpsc_shipping_modules;
566
567
			$custom_shipping = get_option( 'custom_shipping_options' );
568
569
			foreach ( (array) $custom_shipping as $id => $shipping ) {
570
				$module_title = isset( $wpsc_shipping_modules[ $shipping ] ) && is_callable( array( $wpsc_shipping_modules[ $shipping ], 'getName' ) ) ? $wpsc_shipping_modules[ $shipping ]->getName() : '';
571
				$active_methods[ $id ] = array( 'name' => $shipping, 'title' => $module_title );
572
			}
573
		}
574
575
		return $active_methods;
576
	}
577
578
	/**
579
	 * Look for any template override and return filenames.
580
	 *
581
	 * @todo Implement a method of checking template overrides for tev2.
582
	 * @since 3.12.0
583
	 * @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...
584
	 */
585
	private static function get_all_template_overrides() {
586
		$override_data  = array();
587
588
		$te = get_option( 'wpsc_get_active_theme_engine', '1.0' );
589
590
		if( '1.0' == $te ) {
591
			$override_data = wpsc_check_theme_location();
592
		}
593
594
		return $override_data;
595
	}
596
597
	/**
598
	 * let_to_num function.
599
	 *
600
	 * This function transforms the php.ini notation for numbers (like '2M') to an integer.
601
	 *
602
	 * @since 3.12.0
603
	 * @param $size
604
	 * @return int
605
	 */
606
	private static function wpsc_let_to_num( $size ) {
607
		$l   = substr( $size, -1 );
608
		$ret = substr( $size, 0, -1 );
609
		switch ( strtoupper( $l ) ) {
610
			case 'P':
611
				$ret *= 1024;
612
			case 'T':
613
				$ret *= 1024;
614
			case 'G':
615
				$ret *= 1024;
616
			case 'M':
617
				$ret *= 1024;
618
			case 'K':
619
				$ret *= 1024;
620
		}
621
		return $ret;
622
	}
623
}
624
625
$wpsc_tracking = new WPSC_Tracking;
626