Completed
Push — master ( 750fda...945ff7 )
by Mike
96:26 queued 86:58
created

v2/class-wc-rest-system-status-v2-controller.php (2 issues)

WordPress.VIP.DirectDatabaseQuery

Unknown

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * REST API WC System Status controller
4
 *
5
 * Handles requests to the /system_status endpoint.
6
 *
7
 * @package WooCommerce/API
8
 * @since   3.0.0
9
 */
10
11
defined( 'ABSPATH' ) || exit;
12
13
/**
14
 * System status controller class.
15
 *
16
 * @package WooCommerce/API
17
 * @extends WC_REST_Controller
18
 */
19
class WC_REST_System_Status_V2_Controller extends WC_REST_Controller {
20
21
	/**
22
	 * Endpoint namespace.
23
	 *
24
	 * @var string
25
	 */
26
	protected $namespace = 'wc/v2';
27
28
	/**
29
	 * Route base.
30
	 *
31
	 * @var string
32
	 */
33
	protected $rest_base = 'system_status';
34
35
	/**
36
	 * Register the route for /system_status
37
	 */
38 426 View Code Duplication
	public function register_routes() {
39 426
		register_rest_route(
40 426
			$this->namespace,
41 426
			'/' . $this->rest_base,
42
			array(
43
				array(
44 426
					'methods'             => WP_REST_Server::READABLE,
45 426
					'callback'            => array( $this, 'get_items' ),
46 426
					'permission_callback' => array( $this, 'get_items_permissions_check' ),
47 426
					'args'                => $this->get_collection_params(),
48
				),
49 426
				'schema' => array( $this, 'get_public_item_schema' ),
50
			)
51
		);
52
	}
53
54
	/**
55
	 * Check whether a given request has permission to view system status.
56
	 *
57
	 * @param  WP_REST_Request $request Full details about the request.
58
	 * @return WP_Error|boolean
59
	 */
60 20
	public function get_items_permissions_check( $request ) {
61 20
		if ( ! wc_rest_check_manager_permissions( 'system_status', 'read' ) ) {
62 4
			return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
63
		}
64 16
		return true;
65
	}
66
67
	/**
68
	 * Get a system status info, by section.
69
	 *
70
	 * @param WP_REST_Request $request Full details about the request.
71
	 * @return WP_Error|WP_REST_Response
72
	 */
73 16
	public function get_items( $request ) {
74 16
		$schema   = $this->get_item_schema();
75 16
		$mappings = $this->get_item_mappings();
76 16
		$response = array();
77
78 16
		foreach ( $mappings as $section => $values ) {
79 16
			foreach ( $values as $key => $value ) {
80 16
				if ( isset( $schema['properties'][ $section ]['properties'][ $key ]['type'] ) ) {
81 16
					settype( $values[ $key ], $schema['properties'][ $section ]['properties'][ $key ]['type'] );
82
				}
83
			}
84 16
			settype( $values, $schema['properties'][ $section ]['type'] );
85 16
			$response[ $section ] = $values;
86
		}
87
88 16
		$response = $this->prepare_item_for_response( $response, $request );
89
90 16
		return rest_ensure_response( $response );
91
	}
92
93
	/**
94
	 * Get the system status schema, conforming to JSON Schema.
95
	 *
96
	 * @return array
97
	 */
98 426
	public function get_item_schema() {
99
		$schema = array(
100 426
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
101 426
			'title'      => 'system_status',
102 426
			'type'       => 'object',
103
			'properties' => array(
104
				'environment'    => array(
105 426
					'description' => __( 'Environment.', 'woocommerce' ),
106 426
					'type'        => 'object',
107
					'context'     => array( 'view' ),
108
					'readonly'    => true,
109
					'properties'  => array(
110
						'home_url'                  => array(
111 426
							'description' => __( 'Home URL.', 'woocommerce' ),
112 426
							'type'        => 'string',
113 426
							'format'      => 'uri',
114
							'context'     => array( 'view' ),
115
							'readonly'    => true,
116
						),
117
						'site_url'                  => array(
118 426
							'description' => __( 'Site URL.', 'woocommerce' ),
119 426
							'type'        => 'string',
120 426
							'format'      => 'uri',
121
							'context'     => array( 'view' ),
122
							'readonly'    => true,
123
						),
124
						'wc_version'                => array(
125 426
							'description' => __( 'WooCommerce version.', 'woocommerce' ),
126 426
							'type'        => 'string',
127
							'context'     => array( 'view' ),
128
							'readonly'    => true,
129
						),
130
						'log_directory'             => array(
131 426
							'description' => __( 'Log directory.', 'woocommerce' ),
132 426
							'type'        => 'string',
133
							'context'     => array( 'view' ),
134
							'readonly'    => true,
135
						),
136
						'log_directory_writable'    => array(
137 426
							'description' => __( 'Is log directory writable?', 'woocommerce' ),
138 426
							'type'        => 'boolean',
139
							'context'     => array( 'view' ),
140
							'readonly'    => true,
141
						),
142
						'wp_version'                => array(
143 426
							'description' => __( 'WordPress version.', 'woocommerce' ),
144 426
							'type'        => 'string',
145
							'context'     => array( 'view' ),
146
							'readonly'    => true,
147
						),
148
						'wp_multisite'              => array(
149 426
							'description' => __( 'Is WordPress multisite?', 'woocommerce' ),
150 426
							'type'        => 'boolean',
151
							'context'     => array( 'view' ),
152
							'readonly'    => true,
153
						),
154
						'wp_memory_limit'           => array(
155 426
							'description' => __( 'WordPress memory limit.', 'woocommerce' ),
156 426
							'type'        => 'integer',
157
							'context'     => array( 'view' ),
158
							'readonly'    => true,
159
						),
160
						'wp_debug_mode'             => array(
161 426
							'description' => __( 'Is WordPress debug mode active?', 'woocommerce' ),
162 426
							'type'        => 'boolean',
163
							'context'     => array( 'view' ),
164
							'readonly'    => true,
165
						),
166
						'wp_cron'                   => array(
167 426
							'description' => __( 'Are WordPress cron jobs enabled?', 'woocommerce' ),
168 426
							'type'        => 'boolean',
169
							'context'     => array( 'view' ),
170
							'readonly'    => true,
171
						),
172
						'language'                  => array(
173 426
							'description' => __( 'WordPress language.', 'woocommerce' ),
174 426
							'type'        => 'string',
175
							'context'     => array( 'view' ),
176
							'readonly'    => true,
177
						),
178
						'server_info'               => array(
179 426
							'description' => __( 'Server info.', 'woocommerce' ),
180 426
							'type'        => 'string',
181
							'context'     => array( 'view' ),
182
							'readonly'    => true,
183
						),
184
						'php_version'               => array(
185 426
							'description' => __( 'PHP version.', 'woocommerce' ),
186 426
							'type'        => 'string',
187
							'context'     => array( 'view' ),
188
							'readonly'    => true,
189
						),
190
						'php_post_max_size'         => array(
191 426
							'description' => __( 'PHP post max size.', 'woocommerce' ),
192 426
							'type'        => 'integer',
193
							'context'     => array( 'view' ),
194
							'readonly'    => true,
195
						),
196
						'php_max_execution_time'    => array(
197 426
							'description' => __( 'PHP max execution time.', 'woocommerce' ),
198 426
							'type'        => 'integer',
199
							'context'     => array( 'view' ),
200
							'readonly'    => true,
201
						),
202
						'php_max_input_vars'        => array(
203 426
							'description' => __( 'PHP max input vars.', 'woocommerce' ),
204 426
							'type'        => 'integer',
205
							'context'     => array( 'view' ),
206
							'readonly'    => true,
207
						),
208
						'curl_version'              => array(
209 426
							'description' => __( 'cURL version.', 'woocommerce' ),
210 426
							'type'        => 'string',
211
							'context'     => array( 'view' ),
212
							'readonly'    => true,
213
						),
214
						'suhosin_installed'         => array(
215 426
							'description' => __( 'Is SUHOSIN installed?', 'woocommerce' ),
216 426
							'type'        => 'boolean',
217
							'context'     => array( 'view' ),
218
							'readonly'    => true,
219
						),
220
						'max_upload_size'           => array(
221 426
							'description' => __( 'Max upload size.', 'woocommerce' ),
222 426
							'type'        => 'integer',
223
							'context'     => array( 'view' ),
224
							'readonly'    => true,
225
						),
226
						'mysql_version'             => array(
227 426
							'description' => __( 'MySQL version.', 'woocommerce' ),
228 426
							'type'        => 'string',
229
							'context'     => array( 'view' ),
230
							'readonly'    => true,
231
						),
232
						'mysql_version_string'             => array(
233 426
							'description' => __( 'MySQL version string.', 'woocommerce' ),
234 426
							'type'        => 'string',
235
							'context'     => array( 'view' ),
236
							'readonly'    => true,
237
						),
238
						'default_timezone'          => array(
239 426
							'description' => __( 'Default timezone.', 'woocommerce' ),
240 426
							'type'        => 'string',
241
							'context'     => array( 'view' ),
242
							'readonly'    => true,
243
						),
244
						'fsockopen_or_curl_enabled' => array(
245 426
							'description' => __( 'Is fsockopen/cURL enabled?', 'woocommerce' ),
246 426
							'type'        => 'boolean',
247
							'context'     => array( 'view' ),
248
							'readonly'    => true,
249
						),
250
						'soapclient_enabled'        => array(
251 426
							'description' => __( 'Is SoapClient class enabled?', 'woocommerce' ),
252 426
							'type'        => 'boolean',
253
							'context'     => array( 'view' ),
254
							'readonly'    => true,
255
						),
256
						'domdocument_enabled'       => array(
257 426
							'description' => __( 'Is DomDocument class enabled?', 'woocommerce' ),
258 426
							'type'        => 'boolean',
259
							'context'     => array( 'view' ),
260
							'readonly'    => true,
261
						),
262
						'gzip_enabled'              => array(
263 426
							'description' => __( 'Is GZip enabled?', 'woocommerce' ),
264 426
							'type'        => 'boolean',
265
							'context'     => array( 'view' ),
266
							'readonly'    => true,
267
						),
268
						'mbstring_enabled'          => array(
269 426
							'description' => __( 'Is mbstring enabled?', 'woocommerce' ),
270 426
							'type'        => 'boolean',
271
							'context'     => array( 'view' ),
272
							'readonly'    => true,
273
						),
274
						'remote_post_successful'    => array(
275 426
							'description' => __( 'Remote POST successful?', 'woocommerce' ),
276 426
							'type'        => 'boolean',
277
							'context'     => array( 'view' ),
278
							'readonly'    => true,
279
						),
280
						'remote_post_response'      => array(
281 426
							'description' => __( 'Remote POST response.', 'woocommerce' ),
282 426
							'type'        => 'string',
283
							'context'     => array( 'view' ),
284
							'readonly'    => true,
285
						),
286
						'remote_get_successful'     => array(
287 426
							'description' => __( 'Remote GET successful?', 'woocommerce' ),
288 426
							'type'        => 'boolean',
289
							'context'     => array( 'view' ),
290
							'readonly'    => true,
291
						),
292
						'remote_get_response'       => array(
293 426
							'description' => __( 'Remote GET response.', 'woocommerce' ),
294 426
							'type'        => 'string',
295
							'context'     => array( 'view' ),
296
							'readonly'    => true,
297
						),
298
					),
299
				),
300
				'database'       => array(
301 426
					'description' => __( 'Database.', 'woocommerce' ),
302 426
					'type'        => 'object',
303
					'context'     => array( 'view' ),
304
					'readonly'    => true,
305
					'properties'  => array(
306
						'wc_database_version'    => array(
307 426
							'description' => __( 'WC database version.', 'woocommerce' ),
308 426
							'type'        => 'string',
309
							'context'     => array( 'view' ),
310
							'readonly'    => true,
311
						),
312
						'database_prefix'        => array(
313 426
							'description' => __( 'Database prefix.', 'woocommerce' ),
314 426
							'type'        => 'string',
315
							'context'     => array( 'view' ),
316
							'readonly'    => true,
317
						),
318
						'maxmind_geoip_database' => array(
319 426
							'description' => __( 'MaxMind GeoIP database.', 'woocommerce' ),
320 426
							'type'        => 'string',
321
							'context'     => array( 'view' ),
322
							'readonly'    => true,
323
						),
324
						'database_tables'        => array(
325 426
							'description' => __( 'Database tables.', 'woocommerce' ),
326 426
							'type'        => 'array',
327
							'context'     => array( 'view' ),
328
							'readonly'    => true,
329
							'items'       => array(
330
								'type' => 'string',
331
							),
332
						),
333
					),
334
				),
335
				'active_plugins' => array(
336 426
					'description' => __( 'Active plugins.', 'woocommerce' ),
337 426
					'type'        => 'array',
338
					'context'     => array( 'view' ),
339
					'readonly'    => true,
340
					'items'       => array(
341
						'type' => 'string',
342
					),
343
				),
344
				'inactive_plugins' => array(
345 426
					'description' => __( 'Inactive plugins.', 'woocommerce' ),
346 426
					'type'        => 'array',
347
					'context'     => array( 'view' ),
348
					'readonly'    => true,
349
					'items'       => array(
350
						'type' => 'string',
351
					),
352
				),
353
				'dropins_mu_plugins' => array(
354 426
					'description' => __( 'Dropins & MU plugins.', 'woocommerce' ),
355 426
					'type'        => 'array',
356
					'context'     => array( 'view' ),
357
					'readonly'    => true,
358
					'items'       => array(
359
						'type' => 'string',
360
					),
361
				),
362
				'theme'          => array(
363 426
					'description' => __( 'Theme.', 'woocommerce' ),
364 426
					'type'        => 'object',
365
					'context'     => array( 'view' ),
366
					'readonly'    => true,
367
					'properties'  => array(
368
						'name'                    => array(
369 426
							'description' => __( 'Theme name.', 'woocommerce' ),
370 426
							'type'        => 'string',
371
							'context'     => array( 'view' ),
372
							'readonly'    => true,
373
						),
374
						'version'                 => array(
375 426
							'description' => __( 'Theme version.', 'woocommerce' ),
376 426
							'type'        => 'string',
377
							'context'     => array( 'view' ),
378
							'readonly'    => true,
379
						),
380
						'version_latest'          => array(
381 426
							'description' => __( 'Latest version of theme.', 'woocommerce' ),
382 426
							'type'        => 'string',
383
							'context'     => array( 'view' ),
384
							'readonly'    => true,
385
						),
386
						'author_url'              => array(
387 426
							'description' => __( 'Theme author URL.', 'woocommerce' ),
388 426
							'type'        => 'string',
389 426
							'format'      => 'uri',
390
							'context'     => array( 'view' ),
391
							'readonly'    => true,
392
						),
393
						'is_child_theme'          => array(
394 426
							'description' => __( 'Is this theme a child theme?', 'woocommerce' ),
395 426
							'type'        => 'boolean',
396
							'context'     => array( 'view' ),
397
							'readonly'    => true,
398
						),
399
						'has_woocommerce_support' => array(
400 426
							'description' => __( 'Does the theme declare WooCommerce support?', 'woocommerce' ),
401 426
							'type'        => 'boolean',
402
							'context'     => array( 'view' ),
403
							'readonly'    => true,
404
						),
405
						'has_woocommerce_file'    => array(
406 426
							'description' => __( 'Does the theme have a woocommerce.php file?', 'woocommerce' ),
407 426
							'type'        => 'boolean',
408
							'context'     => array( 'view' ),
409
							'readonly'    => true,
410
						),
411
						'has_outdated_templates'  => array(
412 426
							'description' => __( 'Does this theme have outdated templates?', 'woocommerce' ),
413 426
							'type'        => 'boolean',
414
							'context'     => array( 'view' ),
415
							'readonly'    => true,
416
						),
417
						'overrides'               => array(
418 426
							'description' => __( 'Template overrides.', 'woocommerce' ),
419 426
							'type'        => 'array',
420
							'context'     => array( 'view' ),
421
							'readonly'    => true,
422
							'items'       => array(
423
								'type' => 'string',
424
							),
425
						),
426
						'parent_name'             => array(
427 426
							'description' => __( 'Parent theme name.', 'woocommerce' ),
428 426
							'type'        => 'string',
429
							'context'     => array( 'view' ),
430
							'readonly'    => true,
431
						),
432
						'parent_version'          => array(
433 426
							'description' => __( 'Parent theme version.', 'woocommerce' ),
434 426
							'type'        => 'string',
435
							'context'     => array( 'view' ),
436
							'readonly'    => true,
437
						),
438
						'parent_author_url'       => array(
439 426
							'description' => __( 'Parent theme author URL.', 'woocommerce' ),
440 426
							'type'        => 'string',
441 426
							'format'      => 'uri',
442
							'context'     => array( 'view' ),
443
							'readonly'    => true,
444
						),
445
					),
446
				),
447
				'settings'       => array(
448 426
					'description' => __( 'Settings.', 'woocommerce' ),
449 426
					'type'        => 'object',
450
					'context'     => array( 'view' ),
451
					'readonly'    => true,
452
					'properties'  => array(
453
						'api_enabled'              => array(
454 426
							'description' => __( 'REST API enabled?', 'woocommerce' ),
455 426
							'type'        => 'boolean',
456
							'context'     => array( 'view' ),
457
							'readonly'    => true,
458
						),
459
						'force_ssl'                => array(
460 426
							'description' => __( 'SSL forced?', 'woocommerce' ),
461 426
							'type'        => 'boolean',
462
							'context'     => array( 'view' ),
463
							'readonly'    => true,
464
						),
465
						'currency'                 => array(
466 426
							'description' => __( 'Currency.', 'woocommerce' ),
467 426
							'type'        => 'string',
468
							'context'     => array( 'view' ),
469
							'readonly'    => true,
470
						),
471
						'currency_symbol'          => array(
472 426
							'description' => __( 'Currency symbol.', 'woocommerce' ),
473 426
							'type'        => 'string',
474
							'context'     => array( 'view' ),
475
							'readonly'    => true,
476
						),
477
						'currency_position'        => array(
478 426
							'description' => __( 'Currency position.', 'woocommerce' ),
479 426
							'type'        => 'string',
480
							'context'     => array( 'view' ),
481
							'readonly'    => true,
482
						),
483
						'thousand_separator'       => array(
484 426
							'description' => __( 'Thousand separator.', 'woocommerce' ),
485 426
							'type'        => 'string',
486
							'context'     => array( 'view' ),
487
							'readonly'    => true,
488
						),
489
						'decimal_separator'        => array(
490 426
							'description' => __( 'Decimal separator.', 'woocommerce' ),
491 426
							'type'        => 'string',
492
							'context'     => array( 'view' ),
493
							'readonly'    => true,
494
						),
495
						'number_of_decimals'       => array(
496 426
							'description' => __( 'Number of decimals.', 'woocommerce' ),
497 426
							'type'        => 'integer',
498
							'context'     => array( 'view' ),
499
							'readonly'    => true,
500
						),
501
						'geolocation_enabled'      => array(
502 426
							'description' => __( 'Geolocation enabled?', 'woocommerce' ),
503 426
							'type'        => 'boolean',
504
							'context'     => array( 'view' ),
505
							'readonly'    => true,
506
						),
507
						'taxonomies'               => array(
508 426
							'description' => __( 'Taxonomy terms for product/order statuses.', 'woocommerce' ),
509 426
							'type'        => 'array',
510
							'context'     => array( 'view' ),
511
							'readonly'    => true,
512
							'items'       => array(
513
								'type' => 'string',
514
							),
515
						),
516
						'product_visibility_terms' => array(
517 426
							'description' => __( 'Terms in the product visibility taxonomy.', 'woocommerce' ),
518 426
							'type'        => 'array',
519
							'context'     => array( 'view' ),
520
							'readonly'    => true,
521
							'items'       => array(
522
								'type' => 'string',
523
							),
524
						),
525
					),
526
				),
527
				'security'       => array(
528 426
					'description' => __( 'Security.', 'woocommerce' ),
529 426
					'type'        => 'object',
530
					'context'     => array( 'view' ),
531
					'readonly'    => true,
532
					'properties'  => array(
533
						'secure_connection' => array(
534 426
							'description' => __( 'Is the connection to your store secure?', 'woocommerce' ),
535 426
							'type'        => 'boolean',
536
							'context'     => array( 'view' ),
537
							'readonly'    => true,
538
						),
539
						'hide_errors'       => array(
540 426
							'description' => __( 'Hide errors from visitors?', 'woocommerce' ),
541 426
							'type'        => 'boolean',
542
							'context'     => array( 'view' ),
543
							'readonly'    => true,
544
						),
545
					),
546
				),
547
				'pages'          => array(
548 426
					'description' => __( 'WooCommerce pages.', 'woocommerce' ),
549 426
					'type'        => 'array',
550
					'context'     => array( 'view' ),
551
					'readonly'    => true,
552
					'items'       => array(
553
						'type' => 'string',
554
					),
555
				),
556
			),
557
		);
558
559 426
		return $this->add_additional_fields_schema( $schema );
560
	}
561
562
	/**
563
	 * Return an array of sections and the data associated with each.
564
	 *
565
	 * @return array
566
	 */
567 16
	public function get_item_mappings() {
568
		return array(
569 16
			'environment'        => $this->get_environment_info(),
570 16
			'database'           => $this->get_database_info(),
571 16
			'active_plugins'     => $this->get_active_plugins(),
572 16
			'inactive_plugins'   => $this->get_inactive_plugins(),
573 16
			'dropins_mu_plugins' => $this->get_dropins_mu_plugins(),
574 16
			'theme'              => $this->get_theme_info(),
575 16
			'settings'           => $this->get_settings(),
576 16
			'security'           => $this->get_security_info(),
577 16
			'pages'              => $this->get_pages(),
578
		);
579
	}
580
581
	/**
582
	 * Get array of environment information. Includes thing like software
583
	 * versions, and various server settings.
584
	 *
585
	 * @return array
586
	 */
587 16
	public function get_environment_info() {
588
		global $wpdb;
589
590
		// Figure out cURL version, if installed.
591 16
		$curl_version = '';
592 16
		if ( function_exists( 'curl_version' ) ) {
593 16
			$curl_version = curl_version();
594 16
			$curl_version = $curl_version['version'] . ', ' . $curl_version['ssl_version'];
595
		} elseif ( extension_loaded( 'curl' ) ) {
596
			$curl_version = __( 'cURL installed but unable to retrieve version.', 'woocommerce' );
597
		}
598
599
		// WP memory limit.
600 16
		$wp_memory_limit = wc_let_to_num( WP_MEMORY_LIMIT );
601 16
		if ( function_exists( 'memory_get_usage' ) ) {
602 16
			$wp_memory_limit = max( $wp_memory_limit, wc_let_to_num( @ini_get( 'memory_limit' ) ) );
603
		}
604
605
		// Test POST requests.
606 16
		$post_response_code = get_transient( 'woocommerce_test_remote_post' );
607
608 16
		if ( false === $post_response_code || is_wp_error( $post_response_code ) ) {
609 16
			$response = wp_safe_remote_post(
610 16
				'https://www.paypal.com/cgi-bin/webscr',
611
				array(
612 16
					'timeout'     => 10,
613 16
					'user-agent'  => 'WooCommerce/' . WC()->version,
614 16
					'httpversion' => '1.1',
615
					'body'        => array(
616
						'cmd' => '_notify-validate',
617
					),
618
				)
619
			);
620 16
			if ( ! is_wp_error( $response ) ) {
621 16
				$post_response_code = $response['response']['code'];
622
			}
623 16
			set_transient( 'woocommerce_test_remote_post', $post_response_code, HOUR_IN_SECONDS );
624
		}
625
626 16
		$post_response_successful = ! is_wp_error( $post_response_code ) && $post_response_code >= 200 && $post_response_code < 300;
627
628
		// Test GET requests.
629 16
		$get_response_code = get_transient( 'woocommerce_test_remote_get' );
630
631 16
		if ( false === $get_response_code || is_wp_error( $get_response_code ) ) {
632 16
			$response = wp_safe_remote_get( 'https://woocommerce.com/wc-api/product-key-api?request=ping&network=' . ( is_multisite() ? '1' : '0' ) );
633 16
			if ( ! is_wp_error( $response ) ) {
634 16
				$get_response_code = $response['response']['code'];
635
			}
636 16
			set_transient( 'woocommerce_test_remote_get', $get_response_code, HOUR_IN_SECONDS );
637
		}
638
639 16
		$get_response_successful = ! is_wp_error( $get_response_code ) && $get_response_code >= 200 && $get_response_code < 300;
640
641 16
		$database_version = wc_get_server_database_version();
642
643
		// Return all environment info. Described by JSON Schema.
644
		return array(
645 16
			'home_url'                  => get_option( 'home' ),
646 16
			'site_url'                  => get_option( 'siteurl' ),
647 16
			'version'                   => WC()->version,
648
			'log_directory'             => WC_LOG_DIR,
649 16
			'log_directory_writable'    => (bool) @fopen( WC_LOG_DIR . 'test-log.log', 'a' ),
650 16
			'wp_version'                => get_bloginfo( 'version' ),
651 16
			'wp_multisite'              => is_multisite(),
652 16
			'wp_memory_limit'           => $wp_memory_limit,
653
			'wp_debug_mode'             => ( defined( 'WP_DEBUG' ) && WP_DEBUG ),
654
			'wp_cron'                   => ! ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ),
655 16
			'language'                  => get_locale(),
656 16
			'external_object_cache'     => wp_using_ext_object_cache(),
657 16
			'server_info'               => isset( $_SERVER['SERVER_SOFTWARE'] ) ? wc_clean( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) ) : '',
658 16
			'php_version'               => phpversion(),
659 16
			'php_post_max_size'         => wc_let_to_num( ini_get( 'post_max_size' ) ),
660 16
			'php_max_execution_time'    => ini_get( 'max_execution_time' ),
661 16
			'php_max_input_vars'        => ini_get( 'max_input_vars' ),
662 16
			'curl_version'              => $curl_version,
663 16
			'suhosin_installed'         => extension_loaded( 'suhosin' ),
664 16
			'max_upload_size'           => wp_max_upload_size(),
665 16
			'mysql_version'             => $database_version['number'],
666 16
			'mysql_version_string'      => $database_version['string'],
667 16
			'default_timezone'          => date_default_timezone_get(),
668 16
			'fsockopen_or_curl_enabled' => ( function_exists( 'fsockopen' ) || function_exists( 'curl_init' ) ),
669 16
			'soapclient_enabled'        => class_exists( 'SoapClient' ),
670 16
			'domdocument_enabled'       => class_exists( 'DOMDocument' ),
671 16
			'gzip_enabled'              => is_callable( 'gzopen' ),
672 16
			'mbstring_enabled'          => extension_loaded( 'mbstring' ),
673 16
			'remote_post_successful'    => $post_response_successful,
674 16
			'remote_post_response'      => is_wp_error( $post_response_code ) ? $post_response_code->get_error_message() : $post_response_code,
675 16
			'remote_get_successful'     => $get_response_successful,
676 16
			'remote_get_response'       => is_wp_error( $get_response_code ) ? $get_response_code->get_error_message() : $get_response_code,
677
		);
678
	}
679
680
	/**
681
	 * Add prefix to table.
682
	 *
683
	 * @param string $table Table name.
684
	 * @return stromg
685
	 */
686 16
	protected function add_db_table_prefix( $table ) {
687
		global $wpdb;
688 16
		return $wpdb->prefix . $table;
689
	}
690
691
	/**
692
	 * Get array of database information. Version, prefix, and table existence.
693
	 *
694
	 * @return array
695
	 */
696 16
	public function get_database_info() {
697
		global $wpdb;
698
699 16
		$database_table_information = $wpdb->get_results(
0 ignored issues
show
Usage of a direct database call is discouraged.
Loading history...
Usage of a direct database call without caching is prohibited. Use wp_cache_get / wp_cache_set.
Loading history...
700 16
			$wpdb->prepare(
701 16
				"SELECT
702
				    table_name AS 'name',
703
					engine,
704
				    round( ( data_length / 1024 / 1024 ), 2 ) 'data',
705
				    round( ( index_length / 1024 / 1024 ), 2 ) 'index'
706
				FROM information_schema.TABLES
707
				WHERE table_schema = %s
708
				ORDER BY name ASC;",
709 16
				DB_NAME
710
			)
711
		);
712
713
		// WC Core tables to check existence of.
714 16
		$core_tables = apply_filters(
715 16
			'woocommerce_database_tables',
716
			array(
717 16
				'woocommerce_sessions',
718
				'woocommerce_api_keys',
719
				'woocommerce_attribute_taxonomies',
720
				'woocommerce_downloadable_product_permissions',
721
				'woocommerce_order_items',
722
				'woocommerce_order_itemmeta',
723
				'woocommerce_tax_rates',
724
				'woocommerce_tax_rate_locations',
725
				'woocommerce_shipping_zones',
726
				'woocommerce_shipping_zone_locations',
727
				'woocommerce_shipping_zone_methods',
728
				'woocommerce_payment_tokens',
729
				'woocommerce_payment_tokenmeta',
730
				'woocommerce_log',
731
			)
732
		);
733
734
		/**
735
		 * Adding the prefix to the tables array, for backwards compatibility.
736
		 *
737
		 * If we changed the tables above to include the prefix, then any filters against that table could break.
738
		 */
739 16
		$core_tables = array_map( array( $this, 'add_db_table_prefix' ), $core_tables );
740
741
		/**
742
		 * Organize WooCommerce and non-WooCommerce tables separately for display purposes later.
743
		 *
744
		 * To ensure we include all WC tables, even if they do not exist, pre-populate the WC array with all the tables.
745
		 */
746
		$tables = array(
747 16
			'woocommerce' => array_fill_keys( $core_tables, false ),
748
			'other'       => array(),
749
		);
750
751
		$database_size = array(
752 16
			'data'  => 0,
753
			'index' => 0,
754
		);
755
756 16
		$site_tables_prefix = $wpdb->get_blog_prefix( get_current_blog_id() );
757 16
		$global_tables = $wpdb->tables( 'global', true );
758 16
		foreach ( $database_table_information as $table ) {
759
			// Only include tables matching the prefix of the current site, this is to prevent displaying all tables on a MS install not relating to the current.
760 16
			if ( is_multisite() && 0 !== strpos( $table->name, $site_tables_prefix ) && ! in_array( $table->name, $global_tables, true ) ) {
761
				continue;
762
			}
763 16
			$table_type = in_array( $table->name, $core_tables ) ? 'woocommerce' : 'other';
764
765 16
			$tables[ $table_type ][ $table->name ] = array(
766 16
				'data'   => $table->data,
767 16
				'index'  => $table->index,
768 16
				'engine' => $table->engine,
769
			);
770
771 16
			$database_size['data']  += $table->data;
772 16
			$database_size['index'] += $table->index;
773
		}
774
775
		// Return all database info. Described by JSON Schema.
776
		return array(
777 16
			'wc_database_version'    => get_option( 'woocommerce_db_version' ),
778 16
			'database_prefix'        => $wpdb->prefix,
779 16
			'maxmind_geoip_database' => WC_Geolocation::get_local_database_path(),
780 16
			'database_tables'        => $tables,
781 16
			'database_size'          => $database_size,
782
		);
783
	}
784
785
	/**
786
	 * Get array of counts of objects. Orders, products, etc.
787
	 *
788
	 * @return array
789
	 */
790
	public function get_post_type_counts() {
791
		global $wpdb;
792
793
		$post_type_counts = $wpdb->get_results( "SELECT post_type AS 'type', count(1) AS 'count' FROM {$wpdb->posts} GROUP BY post_type;" );
794
795
		return is_array( $post_type_counts ) ? $post_type_counts : array();
796
	}
797
798
	/**
799
	 * Get a list of plugins active on the site.
800
	 *
801
	 * @return array
802
	 */
803 16
	public function get_active_plugins() {
804 16
		$active_plugins = (array) get_option( 'active_plugins', array() );
805 16 View Code Duplication
		if ( is_multisite() ) {
806
			$network_activated_plugins = array_keys( get_site_option( 'active_sitewide_plugins', array() ) );
807
			$active_plugins            = array_merge( $active_plugins, $network_activated_plugins );
808
		}
809
810 16
		$active_plugins_data = array();
811
812 16
		foreach ( $active_plugins as $plugin ) {
813 2
			$data                  = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
814 2
			$active_plugins_data[] = $this->format_plugin_data( $plugin, $data );
815
		}
816
817 16
		return $active_plugins_data;
818
	}
819
820
	/**
821
	 * Get a list of inplugins active on the site.
822
	 *
823
	 * @return array
824
	 */
825 16
	public function get_inactive_plugins() {
826 16
		require_once ABSPATH . 'wp-admin/includes/plugin.php';
827
828 16
		if ( ! function_exists( 'get_plugins' ) ) {
829
			return array();
830
		}
831
832 16
		$plugins        = get_plugins();
833 16
		$active_plugins = (array) get_option( 'active_plugins', array() );
834
835 16 View Code Duplication
		if ( is_multisite() ) {
836
			$network_activated_plugins = array_keys( get_site_option( 'active_sitewide_plugins', array() ) );
837
			$active_plugins            = array_merge( $active_plugins, $network_activated_plugins );
838
		}
839
840 16
		$plugins_data = array();
841
842 16
		foreach ( $plugins as $plugin => $data ) {
843 16
			if ( in_array( $plugin, $active_plugins, true ) ) {
844 2
				continue;
845
			}
846 16
			$plugins_data[] = $this->format_plugin_data( $plugin, $data );
847
		}
848
849 16
		return $plugins_data;
850
	}
851
852
	/**
853
	 * Format plugin data, including data on updates, into a standard format.
854
	 *
855
	 * @since 3.6.0
856
	 * @param string $plugin Plugin directory/file.
857
	 * @param array  $data Plugin data from WP.
858
	 * @return array Formatted data.
859
	 */
860 16
	protected function format_plugin_data( $plugin, $data ) {
861 16
		require_once ABSPATH . 'wp-admin/includes/update.php';
862
863 16
		if ( ! function_exists( 'get_plugin_updates' ) ) {
864
			return array();
865
		}
866
867
		// Use WP API to lookup latest updates for plugins. WC_Helper injects updates for premium plugins.
868 16
		if ( empty( $this->available_updates ) ) {
869 16
			$this->available_updates = get_plugin_updates();
870
		}
871
872 16
		$version_latest = $data['Version'];
873
874
		// Find latest version.
875 16
		if ( isset( $available_updates[ $plugin ]->update->new_version ) ) {
876
			$version_latest = $available_updates[ $plugin ]->update->new_version;
877
		}
878
879
		return array(
880 16
			'plugin'            => $plugin,
881 16
			'name'              => $data['Name'],
882 16
			'version'           => $data['Version'],
883 16
			'version_latest'    => $version_latest,
884 16
			'url'               => $data['PluginURI'],
885 16
			'author_name'       => $data['AuthorName'],
886 16
			'author_url'        => esc_url_raw( $data['AuthorURI'] ),
887 16
			'network_activated' => $data['Network'],
888
		);
889
	}
890
891
	/**
892
	 * Get a list of Dropins and MU plugins.
893
	 *
894
	 * @since 3.6.0
895
	 * @return array
896
	 */
897 16
	public function get_dropins_mu_plugins() {
898 16
		$dropins = get_dropins();
899
		$plugins = array(
900 16
			'dropins'    => array(),
901
			'mu_plugins' => array(),
902
		);
903 16
		foreach ( $dropins as $key => $dropin ) {
904 16
			$plugins['dropins'][] = array(
905 16
				'plugin' => $key,
906 16
				'name'   => $dropin['Name'],
907
			);
908
		}
909
910 16
		$mu_plugins = get_mu_plugins();
911 16
		foreach ( $mu_plugins as $plugin => $mu_plugin ) {
912
			$plugins['mu_plugins'][] = array(
913
				'plugin'      => $plugin,
914
				'name'        => $mu_plugin['Name'],
915
				'version'     => $mu_plugin['Version'],
916
				'url'         => $mu_plugin['PluginURI'],
917
				'author_name' => $mu_plugin['AuthorName'],
918
				'author_url'  => esc_url_raw( $mu_plugin['AuthorURI'] ),
919
			);
920
		}
921 16
		return $plugins;
922
	}
923
924
	/**
925
	 * Get info on the current active theme, info on parent theme (if presnet)
926
	 * and a list of template overrides.
927
	 *
928
	 * @return array
929
	 */
930 16
	public function get_theme_info() {
931 16
		$active_theme = wp_get_theme();
932
933
		// Get parent theme info if this theme is a child theme, otherwise
934
		// pass empty info in the response.
935 16
		if ( is_child_theme() ) {
936
			$parent_theme      = wp_get_theme( $active_theme->template );
937
			$parent_theme_info = array(
938
				'parent_name'           => $parent_theme->name,
939
				'parent_version'        => $parent_theme->version,
940
				'parent_version_latest' => WC_Admin_Status::get_latest_theme_version( $parent_theme ),
941
				'parent_author_url'     => $parent_theme->{'Author URI'},
942
			);
943
		} else {
944
			$parent_theme_info = array(
945 16
				'parent_name'           => '',
946
				'parent_version'        => '',
947
				'parent_version_latest' => '',
948
				'parent_author_url'     => '',
949
			);
950
		}
951
952
		/**
953
		 * Scan the theme directory for all WC templates to see if our theme
954
		 * overrides any of them.
955
		 */
956 16
		$override_files     = array();
957 16
		$outdated_templates = false;
958 16
		$scan_files         = WC_Admin_Status::scan_template_files( WC()->plugin_path() . '/templates/' );
959 16
		foreach ( $scan_files as $file ) {
960 16
			$located = apply_filters( 'wc_get_template', $file, $file, array(), WC()->template_path(), WC()->plugin_path() . '/templates/' );
961
962 16
			if ( file_exists( $located ) ) {
963
				$theme_file = $located;
964 16
			} elseif ( file_exists( get_stylesheet_directory() . '/' . $file ) ) {
965
				$theme_file = get_stylesheet_directory() . '/' . $file;
966 16
			} elseif ( file_exists( get_stylesheet_directory() . '/' . WC()->template_path() . $file ) ) {
967
				$theme_file = get_stylesheet_directory() . '/' . WC()->template_path() . $file;
968 16
			} elseif ( file_exists( get_template_directory() . '/' . $file ) ) {
969
				$theme_file = get_template_directory() . '/' . $file;
970 16
			} elseif ( file_exists( get_template_directory() . '/' . WC()->template_path() . $file ) ) {
971
				$theme_file = get_template_directory() . '/' . WC()->template_path() . $file;
972
			} else {
973 16
				$theme_file = false;
974
			}
975
976 16
			if ( ! empty( $theme_file ) ) {
977
				$core_version  = WC_Admin_Status::get_file_version( WC()->plugin_path() . '/templates/' . $file );
978
				$theme_version = WC_Admin_Status::get_file_version( $theme_file );
979
				if ( $core_version && ( empty( $theme_version ) || version_compare( $theme_version, $core_version, '<' ) ) ) {
980
					if ( ! $outdated_templates ) {
981
						$outdated_templates = true;
982
					}
983
				}
984
				$override_files[] = array(
985
					'file'         => str_replace( WP_CONTENT_DIR . '/themes/', '', $theme_file ),
986
					'version'      => $theme_version,
987
					'core_version' => $core_version,
988
				);
989
			}
990
		}
991
992
		$active_theme_info = array(
993 16
			'name'                    => $active_theme->name,
994 16
			'version'                 => $active_theme->version,
995 16
			'version_latest'          => WC_Admin_Status::get_latest_theme_version( $active_theme ),
996 16
			'author_url'              => esc_url_raw( $active_theme->{'Author URI'} ),
997 16
			'is_child_theme'          => is_child_theme(),
998 16
			'has_woocommerce_support' => current_theme_supports( 'woocommerce' ),
999 16
			'has_woocommerce_file'    => ( file_exists( get_stylesheet_directory() . '/woocommerce.php' ) || file_exists( get_template_directory() . '/woocommerce.php' ) ),
1000 16
			'has_outdated_templates'  => $outdated_templates,
1001 16
			'overrides'               => $override_files,
1002
		);
1003
1004 16
		return array_merge( $active_theme_info, $parent_theme_info );
1005
	}
1006
1007
	/**
1008
	 * Get some setting values for the site that are useful for debugging
1009
	 * purposes. For full settings access, use the settings api.
1010
	 *
1011
	 * @return array
1012
	 */
1013 16
	public function get_settings() {
1014
		// Get a list of terms used for product/order taxonomies.
1015 16
		$term_response = array();
1016 16
		$terms         = get_terms( 'product_type', array( 'hide_empty' => 0 ) );
1017 16
		foreach ( $terms as $term ) {
1018 16
			$term_response[ $term->slug ] = strtolower( $term->name );
1019
		}
1020
1021
		// Get a list of terms used for product visibility.
1022 16
		$product_visibility_terms = array();
1023 16
		$terms                    = get_terms( 'product_visibility', array( 'hide_empty' => 0 ) );
1024 16
		foreach ( $terms as $term ) {
1025 16
			$product_visibility_terms[ $term->slug ] = strtolower( $term->name );
1026
		}
1027
1028
		// Check if WooCommerce.com account is connected.
1029 16
		$woo_com_connected = 'no';
1030 16
		$helper_options    = get_option( 'woocommerce_helper_data', array() );
1031 16
		if ( array_key_exists( 'auth', $helper_options ) && ! empty( $helper_options['auth'] ) ) {
1032
			$woo_com_connected = 'yes';
1033
		}
1034
1035
		// Return array of useful settings for debugging.
1036
		return array(
1037 16
			'api_enabled'               => 'yes' === get_option( 'woocommerce_api_enabled' ),
1038 16
			'force_ssl'                 => 'yes' === get_option( 'woocommerce_force_ssl_checkout' ),
1039 16
			'currency'                  => get_woocommerce_currency(),
1040 16
			'currency_symbol'           => get_woocommerce_currency_symbol(),
1041 16
			'currency_position'         => get_option( 'woocommerce_currency_pos' ),
1042 16
			'thousand_separator'        => wc_get_price_thousand_separator(),
1043 16
			'decimal_separator'         => wc_get_price_decimal_separator(),
1044 16
			'number_of_decimals'        => wc_get_price_decimals(),
1045 16
			'geolocation_enabled'       => in_array( get_option( 'woocommerce_default_customer_address' ), array( 'geolocation_ajax', 'geolocation' ) ),
1046 16
			'taxonomies'                => $term_response,
1047 16
			'product_visibility_terms'  => $product_visibility_terms,
1048 16
			'woocommerce_com_connected' => $woo_com_connected,
1049
		);
1050
	}
1051
1052
	/**
1053
	 * Returns security tips.
1054
	 *
1055
	 * @return array
1056
	 */
1057 16
	public function get_security_info() {
1058 16
		$check_page = wc_get_page_permalink( 'shop' );
1059
		return array(
1060 16
			'secure_connection' => 'https' === substr( $check_page, 0, 5 ),
1061 16
			'hide_errors'       => ! ( defined( 'WP_DEBUG' ) && defined( 'WP_DEBUG_DISPLAY' ) && WP_DEBUG && WP_DEBUG_DISPLAY ) || 0 === intval( ini_get( 'display_errors' ) ),
1062
		);
1063
	}
1064
1065
	/**
1066
	 * Returns a mini-report on WC pages and if they are configured correctly:
1067
	 * Present, visible, and including the correct shortcode.
1068
	 *
1069
	 * @return array
1070
	 */
1071 16
	public function get_pages() {
1072
		// WC pages to check against.
1073
		$check_pages = array(
1074 16
			_x( 'Shop base', 'Page setting', 'woocommerce' ) => array(
1075 16
				'option'    => 'woocommerce_shop_page_id',
1076
				'shortcode' => '',
1077
			),
1078 16
			_x( 'Cart', 'Page setting', 'woocommerce' ) => array(
1079 16
				'option'    => 'woocommerce_cart_page_id',
1080 16
				'shortcode' => '[' . apply_filters( 'woocommerce_cart_shortcode_tag', 'woocommerce_cart' ) . ']',
1081
			),
1082 16
			_x( 'Checkout', 'Page setting', 'woocommerce' ) => array(
1083 16
				'option'    => 'woocommerce_checkout_page_id',
1084 16
				'shortcode' => '[' . apply_filters( 'woocommerce_checkout_shortcode_tag', 'woocommerce_checkout' ) . ']',
1085
			),
1086 16
			_x( 'My account', 'Page setting', 'woocommerce' ) => array(
1087 16
				'option'    => 'woocommerce_myaccount_page_id',
1088 16
				'shortcode' => '[' . apply_filters( 'woocommerce_my_account_shortcode_tag', 'woocommerce_my_account' ) . ']',
1089
			),
1090 16
			_x( 'Terms and conditions', 'Page setting', 'woocommerce' ) => array(
1091
				'option'    => 'woocommerce_terms_page_id',
1092
				'shortcode' => '',
1093
			),
1094
		);
1095
1096 16
		$pages_output = array();
1097 16
		foreach ( $check_pages as $page_name => $values ) {
1098 16
			$page_id            = get_option( $values['option'] );
1099 16
			$page_set           = false;
1100 16
			$page_exists        = false;
1101 16
			$page_visible       = false;
1102 16
			$shortcode_present  = false;
1103 16
			$shortcode_required = false;
1104
1105
			// Page checks.
1106 16
			if ( $page_id ) {
1107
				$page_set = true;
1108
			}
1109 16
			if ( get_post( $page_id ) ) {
1110
				$page_exists = true;
1111
			}
1112 16
			if ( 'publish' === get_post_status( $page_id ) ) {
1113
				$page_visible = true;
1114
			}
1115
1116
			// Shortcode checks.
1117 16
			if ( $values['shortcode'] && get_post( $page_id ) ) {
1118
				$shortcode_required = true;
1119
				$page               = get_post( $page_id );
1120
				if ( strstr( $page->post_content, $values['shortcode'] ) ) {
1121
					$shortcode_present = true;
1122
				}
1123
			}
1124
1125
			// Wrap up our findings into an output array.
1126 16
			$pages_output[] = array(
1127 16
				'page_name'          => $page_name,
1128 16
				'page_id'            => $page_id,
1129 16
				'page_set'           => $page_set,
1130 16
				'page_exists'        => $page_exists,
1131 16
				'page_visible'       => $page_visible,
1132 16
				'shortcode'          => $values['shortcode'],
1133 16
				'shortcode_required' => $shortcode_required,
1134 16
				'shortcode_present'  => $shortcode_present,
1135
			);
1136
		}
1137
1138 16
		return $pages_output;
1139
	}
1140
1141
	/**
1142
	 * Get any query params needed.
1143
	 *
1144
	 * @return array
1145
	 */
1146 426
	public function get_collection_params() {
1147
		return array(
1148 426
			'context' => $this->get_context_param( array( 'default' => 'view' ) ),
1149
		);
1150
	}
1151
1152
	/**
1153
	 * Prepare the system status response
1154
	 *
1155
	 * @param  array           $system_status System status data.
1156
	 * @param  WP_REST_Request $request       Request object.
1157
	 * @return WP_REST_Response
1158
	 */
1159 16 View Code Duplication
	public function prepare_item_for_response( $system_status, $request ) {
1160 16
		$data = $this->add_additional_fields_to_object( $system_status, $request );
1161 16
		$data = $this->filter_response_by_context( $data, 'view' );
1162
1163 16
		$response = rest_ensure_response( $data );
1164
1165
		/**
1166
		 * Filter the system status returned from the REST API.
1167
		 *
1168
		 * @param WP_REST_Response   $response The response object.
1169
		 * @param mixed              $system_status System status
1170
		 * @param WP_REST_Request    $request  Request object.
1171
		 */
1172 16
		return apply_filters( 'woocommerce_rest_prepare_system_status', $response, $system_status, $request );
1173
	}
1174
}
1175