Completed
Pull Request — master (#11647)
by
unknown
08:14
created

WC_REST_System_Status_Controller   C

Complexity

Total Complexity 78

Size/Duplication

Total Lines 985
Duplicated Lines 4.87 %

Coupling/Cohesion

Components 3
Dependencies 4

Importance

Changes 5
Bugs 1 Features 2
Metric Value
c 5
b 1
f 2
dl 48
loc 985
rs 5
wmc 78
lcom 3
cbo 4

19 Methods

Rating   Name   Duplication   Size   Complexity  
B register_routes() 25 25 1
A get_items_permissions_check() 0 6 2
A get_modes_permissions_check() 0 6 2
A update_modes_permissions_check() 0 6 2
A get_items() 0 17 4
B _get_modes() 0 29 1
A get_modes() 0 8 2
B update_modes() 0 26 4
A prepare_mode_for_response() 0 7 2
B get_item_schema() 0 333 1
B get_mode_item_schema() 0 40 1
A get_item_mappings() 0 10 1
F get_environment_info() 6 71 17
B get_database_info() 0 36 3
C get_active_plugins() 17 67 10
C get_theme_info() 0 67 14
A get_settings() 0 22 2
C get_pages() 0 63 8
A get_collection_params() 0 5 1

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_REST_System_Status_Controller 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_REST_System_Status_Controller, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * REST API WC System Status controller
4
 *
5
 * Handles requests to the /system_status endpoint.
6
 *
7
 * @author   WooThemes
8
 * @category API
9
 * @package  WooCommerce/API
10
 * @since    2.7.0
11
 */
12
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit;
15
}
16
17
/**
18
 * @package WooCommerce/API
19
 * @extends WC_REST_Controller
20
 */
21
class WC_REST_System_Status_Controller extends WC_REST_Controller {
22
23
	/**
24
	 * Endpoint namespace.
25
	 *
26
	 * @var string
27
	 */
28
	protected $namespace = 'wc/v1';
29
30
	/**
31
	 * Route base.
32
	 *
33
	 * @var string
34
	 */
35
	protected $rest_base = 'system_status';
36
37
	/**
38
	 * Register the routes for /system_status and /system_status/modes
39
	 */
40 View Code Duplication
	public function register_routes() {
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...
41
        register_rest_route( $this->namespace, '/' . $this->rest_base, array(
42
			array(
43
				'methods'             => WP_REST_Server::READABLE,
44
				'callback'            => array( $this, 'get_items' ),
45
                'permission_callback' => array( $this, 'get_items_permissions_check' ),
46
				'args'                => $this->get_collection_params(),
47
			),
48
			'schema' => array( $this, 'get_public_item_schema' ),
49
		) );
50
		register_rest_route( $this->namespace, '/' . $this->rest_base . '/modes', array(
51
			array(
52
				'methods'             => WP_REST_Server::READABLE,
53
				'callback'            => array( $this, 'get_modes' ),
54
				'permission_callback' => array( $this, 'get_modes_permissions_check' ),
55
			),
56
			array(
57
				'methods'             => WP_REST_Server::EDITABLE,
58
				'callback'            => array( $this, 'update_modes' ),
59
				'permission_callback' => array( $this, 'update_modes_permissions_check' ),
60
				'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
61
			),
62
			'schema' => array( $this, 'get_mode_item_schema' ),
63
		) );
64
	}
65
66
    /**
67
	 * Check whether a given request has permission to view system status.
68
	 *
69
	 * @param  WP_REST_Request $request Full details about the request.
70
	 * @return WP_Error|boolean
71
	 */
72
	public function get_items_permissions_check( $request ) {
73
        if ( ! wc_rest_check_manager_permissions( 'system_status', 'read' ) ) {
74
        	return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
75
		}
76
		return true;
77
	}
78
79
	/**
80
	 * Check whether a given request has permission to view system status modes.
81
	 *
82
	 * @param  WP_REST_Request $request Full details about the request.
83
	 * @return WP_Error|boolean
84
	 */
85
	public function get_modes_permissions_check( $request ) {
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
86
		if ( ! wc_rest_check_manager_permissions( 'system_status', 'read' ) ) {
87
			return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list system modes.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
88
		}
89
		return true;
90
	}
91
92
	/**
93
	 * Check whether a given request has permission to toggle system status modes.
94
	 *
95
	 * @param  WP_REST_Request $request Full details about the request.
96
	 * @return WP_Error|boolean
97
	 */
98
	public function update_modes_permissions_check( $request ) {
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
99
		if ( ! wc_rest_check_manager_permissions( 'system_status', 'edit' ) ) {
100
			return new WP_Error( 'woocommerce_rest_cannot_update', __( 'Sorry, you cannot update system modes', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
101
		}
102
		return true;
103
	}
104
105
    /**
106
	 * Get a system status info, by section.
107
	 *
108
	 * @param WP_REST_Request $request Full details about the request.
109
	 * @return WP_Error|WP_REST_Response
110
	 */
111
	public function get_items( $request ) {
112
		$schema    = $this->get_item_schema();
113
		$mappings  = $this->get_item_mappings();
114
		$response  = array();
115
116
		foreach ( $mappings as $section => $values ) {
117
			settype( $values, $schema['properties'][ $section ]['type'] );
118
			foreach ( $values as $key => $value ) {
119
				if ( isset( $schema['properties'][ $section ]['properties'][ $key ]['type'] ) ) {
120
					settype( $values[ $key ], $schema['properties'][ $section ]['properties'][ $key ]['type'] );
121
				}
122
			}
123
			$response[ $section ] = $values;
124
		}
125
126
		return rest_ensure_response( $response );
127
	}
128
129
	/**
130
	 * A list of modes that can be toggled via WC's system status screens
131
	 *
132
	 * @return array
133
	 */
134
	public function _get_modes() {
135
		$options = wp_parse_args( get_option( 'woocommerce_status_options', array() ), array(
136
			'uninstall_data'      => 0,
137
			'template_debug_mode' => 0,
138
			'shipping_debug_mode' => 0,
139
		) );
140
		$modes = array(
141
			'shipping_debug' => array(
142
				'id'          => 'shipping_debug',
143
				'name'        => __( 'Shipping Debug Mode', 'woocommerce' ),
144
				'description' => __( 'Enable Shipping Debug Mode to show matching shipping zones and to bypass shipping rate cache.', 'woocommerce' ),
145
				'enabled'     => (bool) $options['shipping_debug_mode'],
146
			),
147
			'template_debug' => array(
148
				'id'          => 'template_debug',
149
				'name'        => __( 'Template Debug Mode', 'woocommerce' ),
150
				'description' => __( 'Enable Template Debug Mode to bypass all theme and plugin template overrides for logged-in administrators. Used for debugging purposes.', 'woocommerce' ),
151
				'enabled'     => (bool) $options['template_debug_mode'],
152
			),
153
			'uninstall_data' => array(
154
				'id'          => 'uninstall_data',
155
				'name'        => __( 'Remove All Data On Uninstall Mode', 'woocommerce' ),
156
				'description' => __( 'This mode will remove all WooCommerce, Product and Order data when using the "Delete" link on the plugins screen. It will also remove any setting/option prepended with "woocommerce_" so may also affect installed WooCommerce Extensions.', 'woocommerce' ),
157
				'enabled'     => (bool) $options['uninstall_data'],
158
			),
159
		);
160
161
		return $modes;
162
	}
163
164
	/**
165
	 * Get system status modes.
166
167
	 * @param  WP_REST_Request $request
168
	 * @return WP_Error|WP_REST_Response
169
	 */
170
	public function get_modes( $request ) {
171
		$modes_response = array();
172
		foreach ( $this->_get_modes() as $id => $mode ) {
173
			$modes_response[] = $this->prepare_response_for_collection( $this->prepare_mode_for_response ( $mode, $request ) );
174
		}
175
		$response = rest_ensure_response( $modes_response );
176
		return $response;
177
	}
178
179
	/**
180
	 * Update system status modes.
181
182
	 * @param  WP_REST_Request $request
183
	 * @return WP_Error|WP_REST_Response
184
	 */
185
	public function update_modes( $request ) {
186
		$items   = $request->get_params();
187
		$modes   = $this->_get_modes();
188
		$options = wp_parse_args( get_option( 'woocommerce_status_options', array() ), array(
189
			'uninstall_data'      => 0,
190
			'template_debug_mode' => 0,
191
			'shipping_debug_mode' => 0,
192
		) );
193
194
		foreach ( $items as $key => $value ) {
195
			if ( ! array_key_exists( $key, $modes ) ) {
196
				return new WP_Error( 'woocommerce_rest_system_status_mode_invalid', __( 'Invalid mode.', 'woocommerce' ), array( 'status' => 500 ) );
197
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
198
			}
199
200
			if ( 'uninstall_data' !== $key ) {
201
				$key = $key . '_mode'; // all other modes have a suffix
202
			}
203
204
			$options[ $key ] = (bool) $value;
205
		}
206
207
		update_option( 'woocommerce_status_options', $options );
208
209
		return $this->get_modes( $request );
210
	}
211
212
	 /**
213
	  * Prepare a mode for serialization.
214
	  *
215
	  * @param  array $item Object.
216
	  * @param  WP_REST_Request $request Request object.
217
	  * @return WP_REST_Response $response Response data.
218
	  */
219
	 public function prepare_mode_for_response( $item, $request ) {
220
		 $context  = empty( $request['context'] ) ? 'view' : $request['context'];
221
		 $data     = $this->add_additional_fields_to_object( $item, $request );
222
		 $data     = $this->filter_response_by_context( $data, $context );
223
		 $response = rest_ensure_response( $data );
224
		 return $response;
225
	 }
226
227
    /**
228
	 * Get the system status schema, conforming to JSON Schema.
229
	 *
230
	 * @return array
231
	 */
232
	public function get_item_schema() {
233
		$schema = array(
234
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
235
			'title'      => 'system_status',
236
			'type'       => 'object',
237
			'properties' => array(
238
				'environment' => array(
239
					'description' => __( 'Environment', 'woocommerce' ),
240
					'type'        => 'array',
241
					'context'     => array( 'view', 'edit' ),
242
					'properties'  => array(
243
						'home_url' => array(
244
							'description' => __( 'Home URL', 'woocommerce' ),
245
							'type'        => 'string',
246
		                    'format'      => 'uri',
247
							'context'     => array( 'view', 'edit' ),
248
						),
249
		                'site_url' => array(
250
		                    'description' => __( 'Site URL', 'woocommerce' ),
251
		                    'type'        => 'string',
252
		                    'format'      => 'uri',
253
		                    'context'     => array( 'view', 'edit' ),
254
		                ),
255
		                'wc_version' => array(
256
		                    'description' => __( 'WooCommerce Version', 'woocommerce' ),
257
		                    'type'        => 'string',
258
		                    'context'     => array( 'view', 'edit' ),
259
		                ),
260
		                'log_directory' => array(
261
		                    'description' => __( 'Log Directory', 'woocommerce' ),
262
		                    'type'        => 'string',
263
		                    'context'     => array( 'view', 'edit' ),
264
		                ),
265
		                'log_directory_writable' => array(
266
		                    'description' => __( 'Is Log Directory Writable?', 'woocommerce' ),
267
		                    'type'        => 'boolean',
268
		                    'context'     => array( 'view', 'edit' ),
269
		                ),
270
		                'wp_version' => array(
271
		                    'description' => __( 'WordPress Version', 'woocommerce' ),
272
		                    'type'        => 'string',
273
		                    'context'     => array( 'view', 'edit' ),
274
		                ),
275
		                'wp_multisite' => array(
276
		                    'description' => __( 'Is WordPress Multisite?', 'woocommerce' ),
277
		                    'type'        => 'boolean',
278
		                    'context'     => array( 'view', 'edit' ),
279
		                ),
280
		                'wp_memory_limit' => array(
281
		                    'description' => __( 'WordPress Memory Limit', 'woocommerce' ),
282
		                    'type'        => 'integer',
283
		                    'context'     => array( 'view', 'edit' ),
284
		                ),
285
		                'wp_debug_mode' => array(
286
		                    'description' => __( 'Is WordPress Debug Mode Active?', 'woocommerce' ),
287
		                    'type'        => 'boolean',
288
		                    'context'     => array( 'view', 'edit' ),
289
		                ),
290
		                'wp_cron' => array(
291
		                    'description' => __( 'Are WordPress Cron Jobs Enabled?', 'woocommerce' ),
292
		                    'type'        => 'boolean',
293
		                    'context'     => array( 'view', 'edit' ),
294
		                ),
295
		                'language' => array(
296
		                    'description' => __( 'WordPress Language', 'woocommerce' ),
297
		                    'type'        => 'string',
298
		                    'context'     => array( 'view', 'edit' ),
299
		                ),
300
		                'server_info' => array(
301
		                    'description' => __( 'Server Info', 'woocommerce' ),
302
		                    'type'        => 'string',
303
		                    'context'     => array( 'view', 'edit' ),
304
		                ),
305
		                'php_version' => array(
306
		                    'description' => __( 'PHP Version', 'woocommerce' ),
307
		                    'type'        => 'string',
308
		                    'context'     => array( 'view', 'edit' ),
309
		                ),
310
		                'php_post_max_size' => array(
311
		                    'description' => __( 'PHP Post Max Size', 'woocommerce' ),
312
		                    'type'        => 'integer',
313
		                    'context'     => array( 'view', 'edit' ),
314
		                ),
315
		                'php_max_execution_time' => array(
316
		                    'description' => __( 'PHP Max Execution Time', 'woocommerce' ),
317
		                    'type'        => 'integer',
318
		                    'context'     => array( 'view', 'edit' ),
319
		                ),
320
		                'php_max_input_vars' => array(
321
		                    'description' => __( 'PHP Max Input Vars', 'woocommerce' ),
322
		                    'type'        => 'integer',
323
		                    'context'     => array( 'view', 'edit' ),
324
		                ),
325
		                'curl_version' => array(
326
		                    'description' => __( 'cURL Version', 'woocommerce' ),
327
		                    'type'        => 'string',
328
		                    'context'     => array( 'view', 'edit' ),
329
		                ),
330
						'suhosin_installed' => array(
331
							'description' => __( 'Is SUHOSIN Installed?', 'woocommerce' ),
332
							'type'        => 'boolean',
333
							'context'     => array( 'view', 'edit' ),
334
						),
335
						'max_upload_size' => array(
336
							'description' => __( 'Max Upload Size', 'woocommerce' ),
337
							'type'        => 'integer',
338
							'context'     => array( 'view', 'edit' ),
339
						),
340
						'mysql_version' => array(
341
							'description' => __( 'MySQL Version', 'woocommerce' ),
342
							'type'        => 'string',
343
							'context'     => array( 'view', 'edit' ),
344
						),
345
						'default_timezone' => array(
346
							'description' => __( 'Default Timezone', 'woocommerce' ),
347
							'type'        => 'string',
348
							'context'     => array( 'view', 'edit' ),
349
						),
350
						'fsockopen_or_curl_enabled' => array(
351
							'description' => __( 'Is fsockopen/cURL Enabled?', 'woocommerce' ),
352
							'type'        => 'boolean',
353
							'context'     => array( 'view', 'edit' ),
354
						),
355
						'soapclient_enabled' => array(
356
							'description' => __( 'Is SoapClient Class Enabled?', 'woocommerce' ),
357
							'type'        => 'boolean',
358
							'context'     => array( 'view', 'edit' ),
359
						),
360
						'domdocument_enabled' => array(
361
							'description' => __( 'Is DomDocument Class Enabled?', 'woocommerce' ),
362
							'type'        => 'boolean',
363
							'context'     => array( 'view', 'edit' ),
364
						),
365
						'gzip_enabled' => array(
366
							'description' => __( 'Is GZip Enabled?', 'woocommerce' ),
367
							'type'        => 'boolean',
368
							'context'     => array( 'view', 'edit' ),
369
						),
370
						'mbstring_enabled' => array(
371
							'description' => __( 'Is mbstring Enabled?', 'woocommerce' ),
372
							'type'        => 'boolean',
373
							'context'     => array( 'view', 'edit' ),
374
						),
375
						'remote_post_successful' => array(
376
							'description' => __( 'Remote POST Successful?', 'woocommerce' ),
377
							'type'        => 'boolean',
378
							'context'     => array( 'view', 'edit' ),
379
						),
380
						'remote_post_response' => array(
381
							'description' => __( 'Remote POST Response', 'woocommerce' ),
382
							'type'        => 'string',
383
							'context'     => array( 'view', 'edit' ),
384
						),
385
						'remote_get_successful' => array(
386
							'description' => __( 'Remote GET Successful?', 'woocommerce' ),
387
							'type'        => 'boolean',
388
							'context'     => array( 'view', 'edit' ),
389
						),
390
						'remote_get_response' => array(
391
							'description' => __( 'Remote GET Response', 'woocommerce' ),
392
							'type'        => 'string',
393
							'context'     => array( 'view', 'edit' ),
394
						),
395
					),
396
				),
397
				'database' => array(
398
					'description' => __( 'Database', 'woocommerce' ),
399
					'type'        => 'array',
400
					'context'     => array( 'view', 'edit' ),
401
					'properties'  => array(
402
						'wc_database_version' => array(
403
							'description' => __( 'WC Database Version', 'woocommerce' ),
404
							'type'        => 'string',
405
							'context'     => array( 'view', 'edit' ),
406
						),
407
						'database_prefix' => array(
408
							'description' => __( 'Database Prefix', 'woocommerce' ),
409
							'type'        => 'string',
410
							'context'     => array( 'view', 'edit' ),
411
						),
412
						'maxmind_geoip_database' => array(
413
							'description' => __( 'MaxMind GeoIP Database', 'woocommerce' ),
414
							'type'        => 'string',
415
							'context'     => array( 'view', 'edit' ),
416
						),
417
						'database_tables' => array(
418
							'description' => __( 'Database Tables', 'woocommerce' ),
419
							'type'        => 'array',
420
							'context'     => array( 'view', 'edit' ),
421
						),
422
					)
423
				),
424
				'active_plugins' => array(
425
					'description' => __( 'Active Plugins', 'woocommerce' ),
426
					'type'        => 'array',
427
					'context'     => array( 'view', 'edit' ),
428
				),
429
				'theme' => array(
430
					'description' => __( 'Theme', 'woocommerce' ),
431
					'type'        => 'array',
432
					'context'     => array( 'view', 'edit' ),
433
					'properties'  => array(
434
						'name' => array(
435
							'description' => __( 'Theme Name', 'woocommerce' ),
436
							'type'        => 'string',
437
							'context'     => array( 'view', 'edit' ),
438
						),
439
						'version' => array(
440
							'description' => __( 'Theme Version', 'woocommerce' ),
441
							'type'        => 'string',
442
							'context'     => array( 'view', 'edit' ),
443
						),
444
						'version_latest' => array(
445
							'description' => __( 'Latest Version Of Theme', 'woocommerce' ),
446
							'type'        => 'string',
447
							'context'     => array( 'view', 'edit' ),
448
						),
449
						'author_url' => array(
450
							'description' => __( 'Theme Author URL', 'woocommerce' ),
451
							'type'        => 'string',
452
							'format'      => 'uri',
453
							'context'     => array( 'view', 'edit' ),
454
						),
455
						'is_child_theme' => array(
456
							'description' => __( 'Is this theme a child theme?', 'woocommerce' ),
457
							'type'        => 'boolean',
458
							'context'     => array( 'view', 'edit' ),
459
						),
460
						'has_woocommerce_support' => array(
461
							'description' => __( 'Does the theme declare WooCommerce support?', 'woocommerce' ),
462
							'type'        => 'boolean',
463
							'context'     => array( 'view', 'edit' ),
464
						),
465
						'has_woocommerce_file' => array(
466
							'description' => __( 'Does the theme have a woocommerce.php file?', 'woocommerce' ),
467
							'type'        => 'boolean',
468
							'context'     => array( 'view', 'edit' ),
469
						),
470
						'has_outdated_templates' => array(
471
							'description' => __( 'Does this theme have outdated templates?', 'woocommerce' ),
472
							'type'        => 'boolean',
473
							'context'     => array( 'view', 'edit' ),
474
						),
475
						'overrides' => array(
476
							'description' => __( 'Template Overrides', 'woocommerce' ),
477
							'type'        => 'array',
478
							'context'     => array( 'view', 'edit' ),
479
						),
480
						'parent_name' => array(
481
							'description' => __( 'Parent Theme Name', 'woocommerce' ),
482
							'type'        => 'string',
483
							'context'     => array( 'view', 'edit' ),
484
						),
485
						'parent_version' => array(
486
							'description' => __( 'Parent Theme Version', 'woocommerce' ),
487
							'type'        => 'string',
488
							'context'     => array( 'view', 'edit' ),
489
						),
490
						'parent_author_url' => array(
491
							'description' => __( 'Parent Theme Author URL', 'woocommerce' ),
492
							'type'        => 'string',
493
							'format'      => 'uri',
494
							'context'     => array( 'view', 'edit' ),
495
						),
496
					)
497
				),
498
				'settings' => array(
499
					'description' => __( 'Settings', 'woocommerce' ),
500
					'type'        => 'array',
501
					'context'     => array( 'view', 'edit' ),
502
					'properties'  => array(
503
						'api_enabled' => array(
504
							'description' => __( 'REST API Enabled?', 'woocommerce' ),
505
							'type'        => 'boolean',
506
							'context'     => array( 'view', 'edit' ),
507
						),
508
						'force_ssl' => array(
509
							'description' => __( 'SSL Forced?', 'woocommerce' ),
510
							'type'        => 'boolean',
511
							'context'     => array( 'view', 'edit' ),
512
						),
513
						'currency' => array(
514
							'description' => __( 'Currency', 'woocommerce' ),
515
							'type'        => 'string',
516
							'context'     => array( 'view', 'edit' ),
517
						),
518
						'currency_symbol' => array(
519
							'description' => __( 'Currency Symbol', 'woocommerce' ),
520
							'type'        => 'string',
521
							'context'     => array( 'view', 'edit' ),
522
						),
523
						'currency_position' => array(
524
							'description' => __( 'Currency Position', 'woocommerce' ),
525
							'type'        => 'string',
526
							'context'     => array( 'view', 'edit' ),
527
						),
528
						'thousand_separator' => array(
529
							'description' => __( 'Thousand Separator', 'woocommerce' ),
530
							'type'        => 'string',
531
							'context'     => array( 'view', 'edit' ),
532
						),
533
						'decimal_separator' => array(
534
							'description' => __( 'Decimal Separator', 'woocommerce' ),
535
							'type'        => 'string',
536
							'context'     => array( 'view', 'edit' ),
537
						),
538
						'number_of_decimals' => array(
539
							'description' => __( 'Number of Decimals', 'woocommerce' ),
540
							'type'        => 'integer',
541
							'context'     => array( 'view', 'edit' ),
542
						),
543
						'geolocation_enabled' => array(
544
							'description' => __( 'Geolocation Enabled?', 'woocommerce' ),
545
							'type'        => 'boolean',
546
							'context'     => array( 'view', 'edit' ),
547
						),
548
						'taxonomies' => array(
549
							'description' => __( 'Taxonomy Terms for Product/Order Statuses', 'woocommerce' ),
550
							'type'        => 'array',
551
							'context'     => array( 'view', 'edit' ),
552
						),
553
					)
554
				),
555
				'pages' => array(
556
					'description' => __( 'WooCommerce Pages', 'woocommerce' ),
557
					'type'        => 'array',
558
					'context'     => array( 'view', 'edit' ),
559
				),
560
			)
561
		);
562
563
		return $this->add_additional_fields_schema( $schema );
564
	}
565
566
	/**
567
	 * Get the system status modes schema, conforming to JSON Schema.
568
	 *
569
	 * @return array
570
	 */
571
	public function get_mode_item_schema() {
572
		$schema = array(
573
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
574
			'title'      => 'system_status_option',
575
			'type'       => 'object',
576
			'properties' => array(
577
				'id'               => array(
578
					'description'  => __( 'A unique identifier for the system status mode.', 'woocommerce' ),
579
					'type'         => 'string',
580
					'context'      => array( 'view', 'edit' ),
581
					'arg_options'  => array(
582
						'sanitize_callback' => 'sanitize_title',
583
					),
584
				),
585
				'name'      => array(
586
					'description'  => __( 'Mode name.', 'woocommerce' ),
587
					'type'         => 'string',
588
					'context'      => array( 'view', 'edit' ),
589
					'arg_options'  => array(
590
						'sanitize_callback' => 'sanitize_text_field',
591
					),
592
				),
593
				'description'      => array(
594
					'description'  => __( 'Mode description.', 'woocommerce' ),
595
					'type'         => 'string',
596
					'context'      => array( 'view', 'edit' ),
597
					'arg_options'  => array(
598
						'sanitize_callback' => 'sanitize_text_field',
599
					),
600
				),
601
				'enabled'            => array(
602
					'description'  => __( 'True if this mode is enabled.', 'woocommerce' ),
603
					'type'         => 'boolean',
604
					'context'      => array( 'view', 'edit' ),
605
				),
606
			),
607
		);
608
609
		return $this->add_additional_fields_schema( $schema );
610
	}
611
612
    /**
613
	 * Return an array of sections and the data associated with each.
614
	 *
615
	 * @return array
616
	 */
617
	public function get_item_mappings() {
618
		return array(
619
			'environment'    => $this->get_environment_info(),
620
			'database'       => $this->get_database_info(),
621
			'active_plugins' => $this->get_active_plugins(),
622
			'theme'          => $this->get_theme_info(),
623
			'settings'       => $this->get_settings(),
624
			'pages'          => $this->get_pages(),
625
		);
626
	}
627
628
	/**
629
	 * Get array of environment information. Includes thing like software
630
	 * versions, and various server settings.
631
	 *
632
	 * @return array
633
	 */
634
	public function get_environment_info() {
635
		global $wpdb;
636
637
		// Figure out cURL version, if installed.
638
		$curl_version = '';
639
		if ( function_exists( 'curl_version' ) ) {
640
            $curl_version = curl_version();
641
            $curl_version = $curl_version['version'] . ', ' . $curl_version['ssl_version'];
642
        }
643
644
		// WP memory limit
645
        $wp_memory_limit = wc_let_to_num( WP_MEMORY_LIMIT );
646
        if ( function_exists( 'memory_get_usage' ) ) {
647
            $wp_memory_limit = max( $wp_memory_limit, wc_let_to_num( @ini_get( 'memory_limit' ) ) );
648
        }
649
650
		// Test POST requests
651
		$post_response = wp_safe_remote_post( 'https://www.paypal.com/cgi-bin/webscr', array(
652
			'timeout'     => 60,
653
			'user-agent'  => 'WooCommerce/' . WC()->version,
654
			'httpversion' => '1.1',
655
			'body'        => array(
656
				'cmd'    => '_notify-validate'
657
			)
658
		) );
659
		$post_response_successful = false;
660 View Code Duplication
		if ( ! is_wp_error( $post_response ) && $post_response['response']['code'] >= 200 && $post_response['response']['code'] < 300 ) {
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...
661
			$post_response_successful = true;
662
		}
663
664
		// Test GET requests
665
		$get_response = wp_safe_remote_get( 'https://woocommerce.com/wc-api/product-key-api?request=ping&network=' . ( is_multisite() ? '1' : '0' ) );
666
		$get_response_successful = false;
667 View Code Duplication
		if ( ! is_wp_error( $post_response ) && $post_response['response']['code'] >= 200 && $post_response['response']['code'] < 300 ) {
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...
668
			$get_response_successful = true;
669
		}
670
671
		// Return all environment info. Described by JSON Schema.
672
		return array(
673
            'home_url'                  => get_option( 'home' ),
674
            'site_url'                  => get_option( 'siteurl' ),
675
            'version'                => WC()->version,
676
            'log_directory'             => WC_LOG_DIR,
677
            'log_directory_writable'    => ( @fopen( WC_LOG_DIR . 'test-log.log', 'a' ) ? true : false ),
678
            'wp_version'                => get_bloginfo('version'),
679
            'wp_multisite'              => is_multisite(),
680
            'wp_memory_limit'           => $wp_memory_limit,
681
            'wp_debug_mode'             => ( defined( 'WP_DEBUG' ) && WP_DEBUG ),
682
            'wp_cron'                   => ! ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ),
683
            'language'                  => get_locale(),
684
            'server_info'               => $_SERVER['SERVER_SOFTWARE'],
685
            'php_version'               => phpversion(),
686
            'php_post_max_size'         => wc_let_to_num( ini_get( 'post_max_size' ) ),
687
            'php_max_execution_time'    => ini_get( 'max_execution_time' ),
688
            'php_max_input_vars'        => ini_get( 'max_input_vars' ),
689
            'curl_version'              => $curl_version,
690
			'suhosin_installed'         => extension_loaded( 'suhosin' ),
691
			'max_upload_size'           => wp_max_upload_size(),
692
			'mysql_version'             => ( ! empty( $wpdb->is_mysql ) ? $wpdb->db_version() : '' ),
693
			'default_timezone'          => date_default_timezone_get(),
694
			'fsockopen_or_curl_enabled' => ( function_exists( 'fsockopen' ) || function_exists( 'curl_init' ) ),
695
			'soapclient_enabled'        => class_exists( 'SoapClient' ),
696
			'domdocument_enabled'       => class_exists( 'DOMDocument' ),
697
			'gzip_enabled'              => is_callable( 'gzopen' ),
698
			'mbstring_enabled'          => extension_loaded( 'mbstring' ),
699
			'remote_post_successful'    => $post_response_successful,
700
			'remote_post_response'      => ( is_wp_error( $post_response ) ? $post_response->get_error_message() : $post_response['response']['code'] ),
701
			'remote_get_successful'     => $get_response_successful,
702
			'remote_get_response'       => ( is_wp_error( $get_response ) ? $get_response->get_error_message() : $get_response['response']['code'] ),
703
        );
704
	}
705
706
	/**
707
	 * Get array of database information. Version, prefix, and table existence.
708
	 *
709
	 * @return array
710
	 */
711
	public function get_database_info() {
712
		global $wpdb;
713
714
		// WC Core tables to check existence of
715
		$tables = array(
716
			'woocommerce_sessions',
717
			'woocommerce_api_keys',
718
			'woocommerce_attribute_taxonomies',
719
			'woocommerce_downloadable_product_permissions',
720
			'woocommerce_order_items',
721
			'woocommerce_order_itemmeta',
722
			'woocommerce_tax_rates',
723
			'woocommerce_tax_rate_locations',
724
			'woocommerce_shipping_zones',
725
			'woocommerce_shipping_zone_locations',
726
			'woocommerce_shipping_zone_methods',
727
			'woocommerce_payment_tokens',
728
			'woocommerce_payment_tokenmeta',
729
		);
730
731
		if ( get_option( 'db_version' ) < 34370 ) {
732
			$tables[] = 'woocommerce_termmeta';
733
		}
734
		$table_exists = array();
735
		foreach ( $tables as $table ) {
736
			$table_exists[ $table ] = ( $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s;", $wpdb->prefix . $table ) ) === $wpdb->prefix . $table );
737
		}
738
739
		// Return all database info. Described by JSON Schema.
740
		return array(
741
			'wc_database_version'    => get_option( 'woocommerce_db_version' ),
742
			'database_prefix'        => $wpdb->prefix,
743
			'maxmind_geoip_database' => WC_Geolocation::get_local_database_path(),
744
			'database_tables'        => $table_exists,
745
		);
746
	}
747
748
	/**
749
	 * Get a list of plugins active on the site.
750
	 *
751
	 * @return array
752
	 */
753
	public function get_active_plugins() {
754
		require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
755
756
		// Get both site plugins and network plugins
757
		$active_plugins = (array) get_option( 'active_plugins', array() );
758
		if ( is_multisite() ) {
759
			$network_activated_plugins = array_keys( get_site_option( 'active_sitewide_plugins', array() ) );
760
			$active_plugins            = array_merge( $active_plugins, $network_activated_plugins );
761
		}
762
763
		$active_plugins_data = array();
764
		foreach ( $active_plugins as $plugin ) {
765
			$data                 = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
766
			$dirname              = dirname( $plugin );
767
			$theme_version_latest = '';
768
			if ( strstr( $data['PluginURI'], 'woothemes.com' ) ) {
769 View Code Duplication
				if ( false === ( $version_data = get_transient( md5( $plugin ) . '_version_data' ) ) ) {
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...
770
					$changelog = wp_safe_remote_get( 'http://dzv365zjfbd8v.cloudfront.net/changelogs/' . $dirname . '/changelog.txt' );
771
					$cl_lines  = explode( "\n", wp_remote_retrieve_body( $changelog ) );
772
					if ( ! empty( $cl_lines ) ) {
773
						foreach ( $cl_lines as $line_num => $cl_line ) {
774
							if ( preg_match( '/^[0-9]/', $cl_line ) ) {
775
								$date         = str_replace( '.' , '-' , trim( substr( $cl_line , 0 , strpos( $cl_line , '-' ) ) ) );
776
								$version      = preg_replace( '~[^0-9,.]~' , '' ,stristr( $cl_line , "version" ) );
777
								$update       = trim( str_replace( "*" , "" , $cl_lines[ $line_num + 1 ] ) );
778
								$version_data = array( 'date' => $date , 'version' => $version , 'update' => $update , 'changelog' => $changelog );
779
								set_transient( md5( $plugin ) . '_version_data', $version_data, DAY_IN_SECONDS );
780
								break;
781
							}
782
						}
783
					}
784
				}
785
				$theme_version_latest = $version_data['version'];
786
			} else {
787
				include_once( ABSPATH . 'wp-admin/includes/plugin-install.php' );
788
				$slug = explode( '/', $plugin );
789
				$slug = explode( '.', end( $slug ) );
790
				$slug = $slug[0];
791
792
				$api = plugins_api( 'plugin_information', array(
793
					'slug'     => $slug,
794
					'fields'   => array(
795
						'sections' => false,
796
						'tags'     => false,
797
					)
798
				) );
799
800
				if ( is_object( $api ) && ! is_wp_error( $api ) ) {
801
					$theme_version_latest = $api->version;
802
				}
803
			}
804
805
			// convert plugin data to json response format.
806
			$active_plugins_data[] = array(
807
				'plugin'            => $plugin,
808
				'name'              => $data['Name'],
809
				'version'           => $data['Version'],
810
				'version_latest'    => $theme_version_latest,
811
				'url'               => $data['PluginURI'],
812
				'author_name'       => $data['AuthorName'],
813
				'author_url'        => esc_url_raw( $data['AuthorURI'] ),
814
				'network_activated' => $data['Network'],
815
			);
816
		}
817
818
		return $active_plugins_data;
819
	}
820
821
	/**
822
	 * Get info on the current active theme, info on parent theme (if presnet)
823
	 * and a list of template overrides.
824
	 *
825
	 * @return array
826
	 */
827
	public function get_theme_info() {
828
		$active_theme = wp_get_theme();
829
830
		// Get parent theme info if this theme is a child theme, otherwise
831
		// pass empty info in the response.
832
		if ( is_child_theme() ) {
833
			$parent_theme      = wp_get_theme( $active_theme->Template );
834
			$parent_theme_info = array(
835
				'parent_name'           => $parent_theme->Name,
836
				'parent_version'        => $parent_theme->Version,
837
				'parent_version_latest' => WC_Admin_Status::get_latest_theme_version( $parent_theme ),
838
				'parent_author_url'     => $parent_theme->{'Author URI'},
839
			);
840
		} else {
841
			$parent_theme_info = array( 'parent_name' => '', 'parent_version' => '', 'parent_version_latest' => '', 'parent_author_url' => '' );
842
		}
843
844
		/**
845
		 * Scan the theme directory for all WC templates to see if our theme
846
		 * overrides any of them.
847
		 */
848
		$override_files     = array();
849
		$outdated_templates = false;
850
		$scan_files         = WC_Admin_Status::scan_template_files( WC()->plugin_path() . '/templates/' );
851
		foreach ( $scan_files as $file ) {
852
			if ( file_exists( get_stylesheet_directory() . '/' . $file ) ) {
853
				$theme_file = get_stylesheet_directory() . '/' . $file;
854
			} elseif ( file_exists( get_stylesheet_directory() . '/woocommerce/' . $file ) ) {
855
				$theme_file = get_stylesheet_directory() . '/woocommerce/' . $file;
856
			} elseif ( file_exists( get_template_directory() . '/' . $file ) ) {
857
				$theme_file = get_template_directory() . '/' . $file;
858
			} elseif ( file_exists( get_template_directory() . '/woocommerce/' . $file ) ) {
859
				$theme_file = get_template_directory() . '/woocommerce/' . $file;
860
			} else {
861
				$theme_file = false;
862
			}
863
864
			if ( ! empty( $theme_file ) ) {
865
				$core_version  = WC_Admin_Status::get_file_version( WC()->plugin_path() . '/templates/' . $file );
866
				$theme_version = WC_Admin_Status::get_file_version( $theme_file );
867
				if ( $core_version && ( empty( $theme_version ) || version_compare( $theme_version, $core_version, '<' ) ) ) {
868
					if ( ! $outdated_templates ) {
869
						$outdated_templates = true;
870
					}
871
				}
872
				$override_files[] =  array(
873
					'file'         => str_replace( WP_CONTENT_DIR . '/themes/', '', $theme_file ),
874
					'version'      => $theme_version,
875
					'core_version' => $core_version,
876
				);
877
			}
878
		}
879
880
		$active_theme_info = array(
881
			'name'                    => $active_theme->Name,
882
			'version'                 => $active_theme->Version,
883
			'version_latest'          => WC_Admin_Status::get_latest_theme_version( $active_theme ),
884
			'author_url'              => esc_url_raw( $active_theme->{'Author URI'} ),
885
			'is_child_theme'          => is_child_theme(),
886
			'has_woocommerce_support' => ( current_theme_supports( 'woocommerce' ) || in_array( $active_theme->template, wc_get_core_supported_themes() ) ),
887
			'has_woocommerce_file'    => ( file_exists( get_stylesheet_directory() . '/woocommerce.php' ) || file_exists( get_template_directory() . '/woocommerce.php' ) ),
888
			'has_outdated_templates'  => $outdated_templates,
889
			'overrides'               => $override_files,
890
		);
891
892
		return array_merge( $active_theme_info, $parent_theme_info );
893
	}
894
895
	/**
896
	 * Get some setting values for the site that are useful for debugging
897
	 * purposes. For full settings access, use the settings api.
898
	 *
899
	 * @return array
900
	 */
901
	public function get_settings() {
902
		// Get a list of terms used for product/order taxonomies
903
		$term_response = array();
904
		$terms         = get_terms( 'product_type', array( 'hide_empty' => 0 ) );
905
		foreach ( $terms as $term ) {
906
			$term_response[ $term->slug ] = strtolower( $term->name );
907
		}
908
909
		// Return array of useful settings for debugging.
910
		return array(
911
			'api_enabled'         => 'yes' === get_option( 'woocommerce_api_enabled' ),
912
			'force_ssl'           => 'yes' === get_option( 'woocommerce_force_ssl_checkout' ),
913
			'currency'            => get_woocommerce_currency(),
914
			'currency_symbol'     => get_woocommerce_currency_symbol(),
915
			'currency_position'   => get_option( 'woocommerce_currency_pos' ),
916
			'thousand_separator'  => wc_get_price_thousand_separator(),
917
			'decimal_separator'   => wc_get_price_decimal_separator(),
918
			'number_of_decimals'  => wc_get_price_decimals(),
919
			'geolocation_enabled' => in_array( get_option( 'woocommerce_default_customer_address' ), array( 'geolocation_ajax', 'geolocation' ) ),
920
			'taxonomies'          => $term_response,
921
		);
922
	}
923
924
	/**
925
	 * Returns a mini-report on WC pages and if they are configured correctly:
926
	 * Present, visible, and including the correct shortcode.
927
	 *
928
	 * @return array
929
	 */
930
	public function get_pages() {
931
		// WC pages to check against
932
		$check_pages = array(
933
			_x( 'Shop Base', 'Page setting', 'woocommerce' ) => array(
934
				'option'    => 'woocommerce_shop_page_id',
935
				'shortcode' => '',
936
			),
937
			_x( 'Cart', 'Page setting', 'woocommerce' ) => array(
938
				'option'    => 'woocommerce_cart_page_id',
939
				'shortcode' => '[' . apply_filters( 'woocommerce_cart_shortcode_tag', 'woocommerce_cart' ) . ']',
940
			),
941
			_x( 'Checkout', 'Page setting', 'woocommerce' ) => array(
942
				'option'    => 'woocommerce_checkout_page_id',
943
				'shortcode' => '[' . apply_filters( 'woocommerce_checkout_shortcode_tag', 'woocommerce_checkout' ) . ']',
944
			),
945
			_x( 'My Account', 'Page setting', 'woocommerce' ) => array(
946
				'option'    => 'woocommerce_myaccount_page_id',
947
				'shortcode' => '[' . apply_filters( 'woocommerce_my_account_shortcode_tag', 'woocommerce_my_account' ) . ']',
948
			),
949
		);
950
951
		$pages_output = array();
952
		foreach ( $check_pages as $page_name => $values ) {
953
			$errors   = array();
0 ignored issues
show
Unused Code introduced by
$errors is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
954
			$page_id  = get_option( $values['option'] );
955
			$page_set = $page_exists = $page_visible = false;
956
			$shortcode_present = $shortcode_required = false;
957
958
			// Page checks
959
			if ( $page_id ) {
960
				$page_set = true;
961
			}
962
			if ( get_post( $page_id ) ) {
963
				$page_exists = true;
964
			}
965
			if ( 'publish' === get_post_status( $page_id ) ) {
966
				$page_visible = true;
967
			}
968
969
			// Shortcode checks
970
			if ( $values['shortcode']  && get_post( $page_id ) ) {
971
				$shortcode_required = true;
972
				$page = get_post( $page_id );
973
				if ( strstr( $page->post_content, $values['shortcode'] ) ) {
974
					$shortcode_present = true;
975
				}
976
			}
977
978
			// Wrap up our findings into an output array
979
			$pages_output[] = array(
980
					'page_name'          => $page_name,
981
					'page_id'            => $page_id,
982
					'page_set'           => $page_set,
983
					'page_exists'        => $page_exists,
984
					'page_visible'       => $page_visible,
985
					'shortcode'          => $values['shortcode'],
986
					'shortcode_required' => $shortcode_required,
987
					'shortcode_present'  => $shortcode_present,
988
			);
989
		}
990
991
		return $pages_output;
992
	}
993
994
	/**
995
	 * Get any query params needed.
996
	 *
997
	 * @return array
998
	 */
999
	public function get_collection_params() {
1000
		return array(
1001
			'context' => $this->get_context_param( array( 'default' => 'view' ) ),
1002
		);
1003
	}
1004
1005
}
1006