WC_Tracker   C
last analyzed

Complexity

Total Complexity 72

Size/Duplication

Total Lines 380
Duplicated Lines 9.74 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
dl 37
loc 380
rs 5.5667
c 0
b 0
f 0
wmc 72
lcom 1
cbo 3

15 Methods

Rating   Name   Duplication   Size   Complexity  
A init() 0 3 1
C send_tracking_data() 0 36 8
A get_last_send_time() 0 3 1
B get_theme_info() 0 17 5
B get_wordpress_info() 4 18 5
D get_server_info() 0 29 9
C get_all_plugins() 0 37 8
A get_user_counts() 0 12 2
A get_product_counts() 0 12 2
A get_order_counts() 0 10 2
A get_active_payment_gateways() 11 11 4
A get_active_shipping_methods() 11 11 4
A get_all_woocommerce_options_values() 0 21 1
D get_all_template_overrides() 11 32 9
F get_tracking_data() 0 45 11

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like WC_Tracker 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 WC_Tracker, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * WooCommerce Tracker
4
 *
5
 * The WooCommerce tracker class adds functionality to track WooCommerce usage based on if the customer opted in.
6
 * No personal infomation is tracked, only general WooCommerce settings, general product, order and user counts and admin email for discount code.
7
 *
8
 * @class 		WC_Tracker
9
 * @version		2.3.0
10
 * @package		WooCommerce/Classes
11
 * @category	Class
12
 * @author 		WooThemes
13
 */
14
15
if ( ! defined( 'ABSPATH' ) ) {
16
	exit;
17
}
18
19
class WC_Tracker {
20
21
	/**
22
	 * URL to the WooThemes Tracker API endpoint.
23
	 * @var string
24
	 */
25
	private static $api_url = 'https://tracking.woocommerce.com/v1/';
26
27
	/**
28
	 * Hook into cron event.
29
	 */
30
	public static function init() {
31
		add_action( 'woocommerce_tracker_send_event', array( __CLASS__, 'send_tracking_data' ) );
32
	}
33
34
	/**
35
	 * Decide whether to send tracking data or not.
36
	 *
37
	 * @param boolean $override
38
	 */
39
	public static function send_tracking_data( $override = false ) {
40
		// Dont trigger this on AJAX Requests
41
		if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
42
			return;
43
		}
44
45
		if ( ! apply_filters( 'woocommerce_tracker_send_override', $override ) ) {
46
			// Send a maximum of once per week by default.
47
			$last_send = self::get_last_send_time();
48
			if ( $last_send && $last_send > apply_filters( 'woocommerce_tracker_last_send_interval', strtotime( '-1 week' ) ) ) {
49
				return;
50
			}
51
		} else {
52
			// Make sure there is at least a 1 hour delay between override sends, we dont want duplicate calls due to double clicking links.
53
			$last_send = self::get_last_send_time();
54
			if ( $last_send && $last_send > strtotime( '-1 hours' ) ) {
55
				return;
56
			}
57
		}
58
59
		// Update time first before sending to ensure it is set
60
		update_option( 'woocommerce_tracker_last_send', time() );
61
62
		$params   = self::get_tracking_data();
63
		wp_safe_remote_post( self::$api_url, array(
64
				'method'      => 'POST',
65
				'timeout'     => 45,
66
				'redirection' => 5,
67
				'httpversion' => '1.0',
68
				'blocking'    => false,
69
				'headers'     => array( 'user-agent' => 'WooCommerceTracker/' . md5( esc_url( home_url( '/' ) ) ) . ';' ),
70
				'body'        => json_encode( $params ),
71
				'cookies'     => array()
72
			)
73
		);
74
	}
75
76
	/**
77
	 * Get the last time tracking data was sent.
78
	 * @return int|bool
79
	 */
80
	private static function get_last_send_time() {
81
		return apply_filters( 'woocommerce_tracker_last_send_time', get_option( 'woocommerce_tracker_last_send', false ) );
82
	}
83
84
	/**
85
	 * Get all the tracking data.
86
	 * @return array
87
	 */
88
	private static function get_tracking_data() {
89
		$data                       = array();
90
91
		// General site info
92
		$data['url']                = home_url();
93
		$data['email']              = apply_filters( 'woocommerce_tracker_admin_email', get_option( 'admin_email' ) );
94
		$data['theme']              = self::get_theme_info();
95
96
		// WordPress Info
97
		$data['wp']                 = self::get_wordpress_info();
98
99
		// Server Info
100
		$data['server']             = self::get_server_info();
101
102
		// Plugin info
103
		$all_plugins                = self::get_all_plugins();
104
		$data['active_plugins']     = $all_plugins['active_plugins'];
105
		$data['inactive_plugins']   = $all_plugins['inactive_plugins'];
106
107
		// Jetpack & WooCommerce Connect
108
		$data['jetpack_version']    = defined( 'JETPACK__VERSION' ) ? JETPACK__VERSION : 'none';
109
		$data['jetpack_connected']  = ( class_exists( 'Jetpack' ) && is_callable( 'Jetpack::is_active' ) && Jetpack::is_active() ) ? 'yes' : 'no';
110
		$data['jetpack_is_staging'] = ( class_exists( 'Jetpack' ) && is_callable( 'Jetpack::is_staging_site' ) && Jetpack::is_staging_site() ) ? 'yes' : 'no';
111
		$data['connect_installed']  = class_exists( 'WC_Connect_Loader' ) ? 'yes' : 'no';
112
		$data['connect_active']     = ( class_exists( 'WC_Connect_Loader' ) && wp_next_scheduled( 'wc_connect_fetch_service_schemas' ) ) ? 'yes' : 'no';
113
114
		// Store count info
115
		$data['users']              = self::get_user_counts();
116
		$data['products']           = self::get_product_counts();
117
		$data['orders']             = self::get_order_counts();
118
119
		// Payment gateway info
120
		$data['gateways']           = self::get_active_payment_gateways();
121
122
		// Shipping method info
123
		$data['shipping_methods']   = self::get_active_shipping_methods();
124
125
		// Get all WooCommerce options info
126
		$data['settings']           = self::get_all_woocommerce_options_values();
127
128
		// Template overrides
129
		$data['template_overrides'] = self::get_all_template_overrides();
130
131
		return apply_filters( 'woocommerce_tracker_data', $data );
132
	}
133
134
	/**
135
	 * Get the current theme info, theme name and version.
136
	 * @return array
137
	 */
138
	public static function get_theme_info() {
139
		$wp_version = get_bloginfo( 'version' );
140
141
		if ( version_compare( $wp_version, '3.4', '<' ) ) {
142
			$theme_data = get_theme_data( get_stylesheet_directory() . '/style.css' );
143
			$theme_name = $theme_data['Name'];
144
			$theme_version = $theme_data['Version'];
145
		} else {
146
			$theme_data = wp_get_theme();
147
			$theme_name = $theme_data->Name;
148
			$theme_version = $theme_data->Version;
149
		}
150
		$theme_child_theme = is_child_theme() ? 'Yes' : 'No';
151
		$theme_wc_support = ( ! current_theme_supports( 'woocommerce' ) && ! in_array( $theme_data->template, wc_get_core_supported_themes() ) ) ? 'No' : 'Yes';
152
153
		return array( 'name' => $theme_name, 'version' => $theme_version, 'child_theme' => $theme_child_theme, 'wc_support' => $theme_wc_support );
154
	}
155
156
	/**
157
	 * Get WordPress related data.
158
	 * @return array
159
	 */
160
	private static function get_wordpress_info() {
161
		$wp_data = array();
162
163
		$memory = wc_let_to_num( WP_MEMORY_LIMIT );
164
165 View Code Duplication
		if ( function_exists( 'memory_get_usage' ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
166
			$system_memory = wc_let_to_num( @ini_get( 'memory_limit' ) );
167
			$memory        = max( $memory, $system_memory );
168
		}
169
170
		$wp_data['memory_limit'] = size_format( $memory );
171
		$wp_data['debug_mode']   = ( defined('WP_DEBUG') && WP_DEBUG ) ? 'Yes' : 'No';
172
		$wp_data['locale']       = get_locale();
173
		$wp_data['version']      = get_bloginfo( 'version' );
174
		$wp_data['multisite']    = is_multisite() ? 'Yes' : 'No';
175
176
		return $wp_data;
177
	}
178
179
	/**
180
	 * Get server related info.
181
	 * @return array
182
	 */
183
	private static function get_server_info() {
184
		$server_data = array();
185
186
		if ( isset( $_SERVER['SERVER_SOFTWARE'] ) && ! empty( $_SERVER['SERVER_SOFTWARE'] ) ) {
187
			$server_data['software'] = $_SERVER['SERVER_SOFTWARE'];
188
		}
189
190
		if ( function_exists( 'phpversion' ) ) {
191
			$server_data['php_version'] = phpversion();
192
		}
193
194
		if ( function_exists( 'ini_get' ) ) {
195
			$server_data['php_post_max_size'] = size_format( wc_let_to_num( ini_get( 'post_max_size' ) ) );
196
			$server_data['php_time_limt'] = ini_get( 'max_execution_time' );
197
			$server_data['php_max_input_vars'] = ini_get( 'max_input_vars' );
198
			$server_data['php_suhosin'] = extension_loaded( 'suhosin' ) ? 'Yes' : 'No';
199
		}
200
201
		global $wpdb;
202
		$server_data['mysql_version'] = $wpdb->db_version();
203
204
		$server_data['php_max_upload_size'] = size_format( wp_max_upload_size() );
205
		$server_data['php_default_timezone'] = date_default_timezone_get();
206
		$server_data['php_soap'] = class_exists( 'SoapClient' ) ? 'Yes' : 'No';
207
		$server_data['php_fsockopen'] = function_exists( 'fsockopen' ) ? 'Yes' : 'No';
208
		$server_data['php_curl'] = function_exists( 'curl_init' ) ? 'Yes' : 'No';
209
210
		return $server_data;
211
	}
212
213
	/**
214
	 * Get all plugins grouped into activated or not.
215
	 * @return array
216
	 */
217
	private static function get_all_plugins() {
218
		// Ensure get_plugins function is loaded
219
		if( ! function_exists( 'get_plugins' ) ) {
220
			include ABSPATH . '/wp-admin/includes/plugin.php';
221
		}
222
223
		$plugins        	 = get_plugins();
224
		$active_plugins_keys = get_option( 'active_plugins', array() );
225
		$active_plugins 	 = array();
226
227
		foreach ( $plugins as $k => $v ) {
228
			// Take care of formatting the data how we want it.
229
			$formatted = array();
230
			$formatted['name'] = strip_tags( $v['Name'] );
231
			if ( isset( $v['Version'] ) ) {
232
				$formatted['version'] = strip_tags( $v['Version'] );
233
			}
234
			if ( isset( $v['Author'] ) ) {
235
				$formatted['author'] = strip_tags( $v['Author'] );
236
			}
237
			if ( isset( $v['Network'] ) ) {
238
				$formatted['network'] = strip_tags( $v['Network'] );
239
			}
240
			if ( isset( $v['PluginURI'] ) ) {
241
				$formatted['plugin_uri'] = strip_tags( $v['PluginURI'] );
242
			}
243
			if ( in_array( $k, $active_plugins_keys ) ) {
244
				// Remove active plugins from list so we can show active and inactive separately
245
				unset( $plugins[$k] );
246
				$active_plugins[$k] = $formatted;
247
			} else {
248
				$plugins[$k] = $formatted;
249
			}
250
		}
251
252
		return array( 'active_plugins' => $active_plugins, 'inactive_plugins' => $plugins );
253
	}
254
255
	/**
256
	 * Get user totals based on user role.
257
	 * @return array
258
	 */
259
	private static function get_user_counts() {
260
		$user_count          = array();
261
		$user_count_data     = count_users();
262
		$user_count['total'] = $user_count_data['total_users'];
263
264
		// Get user count based on user role
265
		foreach ( $user_count_data['avail_roles'] as $role => $count ) {
266
			$user_count[ $role ] = $count;
267
		}
268
269
		return $user_count;
270
	}
271
272
	/**
273
	 * Get product totals based on product type.
274
	 * @return array
275
	 */
276
	private static function get_product_counts() {
277
		$product_count          = array();
278
		$product_count_data     = wp_count_posts( 'product' );
279
		$product_count['total'] = $product_count_data->publish;
280
281
		$product_statuses = get_terms( 'product_type', array( 'hide_empty' => 0 ) );
282
		foreach ( $product_statuses as $product_status ) {
283
			$product_count[ $product_status->name ] = $product_status->count;
284
		}
285
286
		return $product_count;
287
	}
288
289
	/**
290
	 * Get order counts based on order status.
291
	 * @return array
292
	 */
293
	private static function get_order_counts() {
294
		$order_count      = array();
295
		$order_count_data = wp_count_posts( 'shop_order' );
296
297
		foreach ( wc_get_order_statuses() as $status_slug => $status_name ) {
298
			$order_count[ $status_slug ] = $order_count_data->{ $status_slug };
299
		}
300
301
		return $order_count;
302
	}
303
304
	/**
305
	 * Get a list of all active payment gateways.
306
	 * @return array
307
	 */
308 View Code Duplication
	private static function get_active_payment_gateways() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
309
		$active_gateways = array();
310
		$gateways        = WC()->payment_gateways->payment_gateways();
311
		foreach ( $gateways as $id => $gateway ) {
312
			if ( isset( $gateway->enabled ) && $gateway->enabled == 'yes' ) {
313
				$active_gateways[ $id ] = array( 'title' => $gateway->title, 'supports' => $gateway->supports );
314
			}
315
		}
316
317
		return $active_gateways;
318
	}
319
320
	/**
321
	 * Get a list of all active shipping methods.
322
	 * @return array
323
	 */
324 View Code Duplication
	private static function get_active_shipping_methods() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
325
		$active_methods   = array();
326
		$shipping_methods = WC()->shipping->get_shipping_methods();
327
		foreach ( $shipping_methods as $id => $shipping_method ) {
328
			if ( isset( $shipping_method->enabled ) && $shipping_method->enabled == 'yes' ) {
329
				$active_methods[ $id ] = array( 'title' => $shipping_method->title, 'tax_status' => $shipping_method->tax_status );
330
			}
331
		}
332
333
		return $active_methods;
334
	}
335
336
	/**
337
	 * Get all options starting with woocommerce_ prefix.
338
	 * @return array
339
	 */
340
	private static function get_all_woocommerce_options_values() {
341
		return array(
342
			'version'                               => WC()->version,
343
			'currency'                              => get_woocommerce_currency(),
344
			'base_location'                         => WC()->countries->get_base_country(),
345
			'selling_locations'                     => WC()->countries->get_allowed_countries(),
346
			'api_enabled'                           => get_option( 'woocommerce_api_enabled' ),
347
			'weight_unit'                           => get_option( 'woocommerce_weight_unit' ),
348
			'dimension_unit'                        => get_option( 'woocommerce_dimension_unit' ),
349
			'download_method'                       => get_option( 'woocommerce_file_download_method' ),
350
			'download_require_login'                => get_option( 'woocommerce_downloads_require_login' ),
351
			'calc_taxes'                            => get_option( 'woocommerce_calc_taxes' ),
352
			'coupons_enabled'                       => get_option( 'woocommerce_enable_coupons' ),
353
			'guest_checkout'                        => get_option( 'woocommerce_enable_guest_checkout'),
354
			'secure_checkout'                       => get_option( 'woocommerce_force_ssl_checkout' ),
355
			'enable_signup_and_login_from_checkout' => get_option( 'woocommerce_enable_signup_and_login_from_checkout' ),
356
			'enable_myaccount_registration'         => get_option( 'woocommerce_enable_myaccount_registration' ),
357
			'registration_generate_username'        => get_option( 'woocommerce_registration_generate_username' ),
358
			'registration_generate_password'        => get_option( 'woocommerce_registration_generate_password' ),
359
		);
360
	}
361
362
	/**
363
	 * Look for any template override and return filenames.
364
	 * @return array
365
	 */
366
	private static function get_all_template_overrides() {
367
		$override_data  = array();
368
		$template_paths = apply_filters( 'woocommerce_template_overrides_scan_paths', array( 'WooCommerce' => WC()->plugin_path() . '/templates/' ) );
369
		$scanned_files  = array();
370
371
		require_once( WC()->plugin_path() . '/includes/admin/class-wc-admin-status.php' );
372
373
		foreach ( $template_paths as $plugin_name => $template_path ) {
374
			$scanned_files[ $plugin_name ] = WC_Admin_Status::scan_template_files( $template_path );
375
		}
376
377
		foreach ( $scanned_files as $plugin_name => $files ) {
378
			foreach ( $files as $file ) {
379 View Code Duplication
				if ( file_exists( get_stylesheet_directory() . '/' . $file ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
380
					$theme_file = get_stylesheet_directory() . '/' . $file;
381
				} elseif ( file_exists( get_stylesheet_directory() . '/woocommerce/' . $file ) ) {
382
					$theme_file = get_stylesheet_directory() . '/woocommerce/' . $file;
383
				} elseif ( file_exists( get_template_directory() . '/' . $file ) ) {
384
					$theme_file = get_template_directory() . '/' . $file;
385
				} elseif( file_exists( get_template_directory() . '/woocommerce/' . $file ) ) {
386
					$theme_file = get_template_directory() . '/woocommerce/' . $file;
387
				} else {
388
					$theme_file = false;
389
				}
390
391
				if ( $theme_file !== false ) {
392
					$override_data[] = basename( $theme_file );
393
				}
394
			}
395
		}
396
		return $override_data;
397
	}
398
}
399
400
WC_Tracker::init();
401