/includes/api/class-wc-rest-system-status-controller.php

  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 3.0.0 
  11. */ 
  12.  
  13. if ( ! defined( 'ABSPATH' ) ) { 
  14. exit; 
  15.  
  16. /** 
  17. * @package WooCommerce/API 
  18. * @extends WC_REST_Controller 
  19. */ 
  20. class WC_REST_System_Status_Controller extends WC_REST_Controller { 
  21.  
  22. /** 
  23. * Endpoint namespace. 
  24. * 
  25. * @var string 
  26. */ 
  27. protected $namespace = 'wc/v2'; 
  28.  
  29. /** 
  30. * Route base. 
  31. * 
  32. * @var string 
  33. */ 
  34. protected $rest_base = 'system_status'; 
  35.  
  36. /** 
  37. * Register the route for /system_status 
  38. */ 
  39. public function register_routes() { 
  40. register_rest_route( $this->namespace, '/' . $this->rest_base, array( 
  41. array( 
  42. 'methods' => WP_REST_Server::READABLE,  
  43. 'callback' => array( $this, 'get_items' ),  
  44. 'permission_callback' => array( $this, 'get_items_permissions_check' ),  
  45. 'args' => $this->get_collection_params(),  
  46. ),  
  47. 'schema' => array( $this, 'get_public_item_schema' ),  
  48. ) ); 
  49.  
  50. /** 
  51. * Check whether a given request has permission to view system status. 
  52. * 
  53. * @param WP_REST_Request $request Full details about the request. 
  54. * @return WP_Error|boolean 
  55. */ 
  56. public function get_items_permissions_check( $request ) { 
  57. if ( ! wc_rest_check_manager_permissions( 'system_status', 'read' ) ) { 
  58. return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); 
  59. return true; 
  60.  
  61. /** 
  62. * Get a system status info, by section. 
  63. * 
  64. * @param WP_REST_Request $request Full details about the request. 
  65. * @return WP_Error|WP_REST_Response 
  66. */ 
  67. public function get_items( $request ) { 
  68. $schema = $this->get_item_schema(); 
  69. $mappings = $this->get_item_mappings(); 
  70. $response = array(); 
  71.  
  72. foreach ( $mappings as $section => $values ) { 
  73. foreach ( $values as $key => $value ) { 
  74. if ( isset( $schema['properties'][ $section ]['properties'][ $key ]['type'] ) ) { 
  75. settype( $values[ $key ], $schema['properties'][ $section ]['properties'][ $key ]['type'] ); 
  76. settype( $values, $schema['properties'][ $section ]['type'] ); 
  77. $response[ $section ] = $values; 
  78.  
  79. $response = $this->prepare_item_for_response( $response, $request ); 
  80.  
  81. return rest_ensure_response( $response ); 
  82.  
  83. /** 
  84. * Get the system status schema, conforming to JSON Schema. 
  85. * 
  86. * @return array 
  87. */ 
  88. public function get_item_schema() { 
  89. $schema = array( 
  90. '$schema' => 'http://json-schema.org/draft-04/schema#',  
  91. 'title' => 'system_status',  
  92. 'type' => 'object',  
  93. 'properties' => array( 
  94. 'environment' => array( 
  95. 'description' => __( 'Environment.', 'woocommerce' ),  
  96. 'type' => 'object',  
  97. 'context' => array( 'view' ),  
  98. 'readonly' => true,  
  99. 'properties' => array( 
  100. 'home_url' => array( 
  101. 'description' => __( 'Home URL.', 'woocommerce' ),  
  102. 'type' => 'string',  
  103. 'format' => 'uri',  
  104. 'context' => array( 'view' ),  
  105. 'readonly' => true,  
  106. ),  
  107. 'site_url' => array( 
  108. 'description' => __( 'Site URL.', 'woocommerce' ),  
  109. 'type' => 'string',  
  110. 'format' => 'uri',  
  111. 'context' => array( 'view' ),  
  112. 'readonly' => true,  
  113. ),  
  114. 'wc_version' => array( 
  115. 'description' => __( 'WooCommerce version.', 'woocommerce' ),  
  116. 'type' => 'string',  
  117. 'context' => array( 'view' ),  
  118. 'readonly' => true,  
  119. ),  
  120. 'log_directory' => array( 
  121. 'description' => __( 'Log directory.', 'woocommerce' ),  
  122. 'type' => 'string',  
  123. 'context' => array( 'view' ),  
  124. 'readonly' => true,  
  125. ),  
  126. 'log_directory_writable' => array( 
  127. 'description' => __( 'Is log directory writable?', 'woocommerce' ),  
  128. 'type' => 'boolean',  
  129. 'context' => array( 'view' ),  
  130. 'readonly' => true,  
  131. ),  
  132. 'wp_version' => array( 
  133. 'description' => __( 'WordPress version.', 'woocommerce' ),  
  134. 'type' => 'string',  
  135. 'context' => array( 'view' ),  
  136. 'readonly' => true,  
  137. ),  
  138. 'wp_multisite' => array( 
  139. 'description' => __( 'Is WordPress multisite?', 'woocommerce' ),  
  140. 'type' => 'boolean',  
  141. 'context' => array( 'view' ),  
  142. 'readonly' => true,  
  143. ),  
  144. 'wp_memory_limit' => array( 
  145. 'description' => __( 'WordPress memory limit.', 'woocommerce' ),  
  146. 'type' => 'integer',  
  147. 'context' => array( 'view' ),  
  148. 'readonly' => true,  
  149. ),  
  150. 'wp_debug_mode' => array( 
  151. 'description' => __( 'Is WordPress debug mode active?', 'woocommerce' ),  
  152. 'type' => 'boolean',  
  153. 'context' => array( 'view' ),  
  154. 'readonly' => true,  
  155. ),  
  156. 'wp_cron' => array( 
  157. 'description' => __( 'Are WordPress cron jobs enabled?', 'woocommerce' ),  
  158. 'type' => 'boolean',  
  159. 'context' => array( 'view' ),  
  160. 'readonly' => true,  
  161. ),  
  162. 'language' => array( 
  163. 'description' => __( 'WordPress language.', 'woocommerce' ),  
  164. 'type' => 'string',  
  165. 'context' => array( 'view' ),  
  166. 'readonly' => true,  
  167. ),  
  168. 'server_info' => array( 
  169. 'description' => __( 'Server info.', 'woocommerce' ),  
  170. 'type' => 'string',  
  171. 'context' => array( 'view' ),  
  172. 'readonly' => true,  
  173. ),  
  174. 'php_version' => array( 
  175. 'description' => __( 'PHP version.', 'woocommerce' ),  
  176. 'type' => 'string',  
  177. 'context' => array( 'view' ),  
  178. 'readonly' => true,  
  179. ),  
  180. 'php_post_max_size' => array( 
  181. 'description' => __( 'PHP post max size.', 'woocommerce' ),  
  182. 'type' => 'integer',  
  183. 'context' => array( 'view' ),  
  184. 'readonly' => true,  
  185. ),  
  186. 'php_max_execution_time' => array( 
  187. 'description' => __( 'PHP max execution time.', 'woocommerce' ),  
  188. 'type' => 'integer',  
  189. 'context' => array( 'view' ),  
  190. 'readonly' => true,  
  191. ),  
  192. 'php_max_input_vars' => array( 
  193. 'description' => __( 'PHP max input vars.', 'woocommerce' ),  
  194. 'type' => 'integer',  
  195. 'context' => array( 'view' ),  
  196. 'readonly' => true,  
  197. ),  
  198. 'curl_version' => array( 
  199. 'description' => __( 'cURL version.', 'woocommerce' ),  
  200. 'type' => 'string',  
  201. 'context' => array( 'view' ),  
  202. 'readonly' => true,  
  203. ),  
  204. 'suhosin_installed' => array( 
  205. 'description' => __( 'Is SUHOSIN installed?', 'woocommerce' ),  
  206. 'type' => 'boolean',  
  207. 'context' => array( 'view' ),  
  208. 'readonly' => true,  
  209. ),  
  210. 'max_upload_size' => array( 
  211. 'description' => __( 'Max upload size.', 'woocommerce' ),  
  212. 'type' => 'integer',  
  213. 'context' => array( 'view' ),  
  214. 'readonly' => true,  
  215. ),  
  216. 'mysql_version' => array( 
  217. 'description' => __( 'MySQL version.', 'woocommerce' ),  
  218. 'type' => 'string',  
  219. 'context' => array( 'view' ),  
  220. 'readonly' => true,  
  221. ),  
  222. 'default_timezone' => array( 
  223. 'description' => __( 'Default timezone.', 'woocommerce' ),  
  224. 'type' => 'string',  
  225. 'context' => array( 'view' ),  
  226. 'readonly' => true,  
  227. ),  
  228. 'fsockopen_or_curl_enabled' => array( 
  229. 'description' => __( 'Is fsockopen/cURL enabled?', 'woocommerce' ),  
  230. 'type' => 'boolean',  
  231. 'context' => array( 'view' ),  
  232. 'readonly' => true,  
  233. ),  
  234. 'soapclient_enabled' => array( 
  235. 'description' => __( 'Is SoapClient class enabled?', 'woocommerce' ),  
  236. 'type' => 'boolean',  
  237. 'context' => array( 'view' ),  
  238. 'readonly' => true,  
  239. ),  
  240. 'domdocument_enabled' => array( 
  241. 'description' => __( 'Is DomDocument class enabled?', 'woocommerce' ),  
  242. 'type' => 'boolean',  
  243. 'context' => array( 'view' ),  
  244. 'readonly' => true,  
  245. ),  
  246. 'gzip_enabled' => array( 
  247. 'description' => __( 'Is GZip enabled?', 'woocommerce' ),  
  248. 'type' => 'boolean',  
  249. 'context' => array( 'view' ),  
  250. 'readonly' => true,  
  251. ),  
  252. 'mbstring_enabled' => array( 
  253. 'description' => __( 'Is mbstring enabled?', 'woocommerce' ),  
  254. 'type' => 'boolean',  
  255. 'context' => array( 'view' ),  
  256. 'readonly' => true,  
  257. ),  
  258. 'remote_post_successful' => array( 
  259. 'description' => __( 'Remote POST successful?', 'woocommerce' ),  
  260. 'type' => 'boolean',  
  261. 'context' => array( 'view' ),  
  262. 'readonly' => true,  
  263. ),  
  264. 'remote_post_response' => array( 
  265. 'description' => __( 'Remote POST response.', 'woocommerce' ),  
  266. 'type' => 'string',  
  267. 'context' => array( 'view' ),  
  268. 'readonly' => true,  
  269. ),  
  270. 'remote_get_successful' => array( 
  271. 'description' => __( 'Remote GET successful?', 'woocommerce' ),  
  272. 'type' => 'boolean',  
  273. 'context' => array( 'view' ),  
  274. 'readonly' => true,  
  275. ),  
  276. 'remote_get_response' => array( 
  277. 'description' => __( 'Remote GET response.', 'woocommerce' ),  
  278. 'type' => 'string',  
  279. 'context' => array( 'view' ),  
  280. 'readonly' => true,  
  281. ),  
  282. ),  
  283. ),  
  284. 'database' => array( 
  285. 'description' => __( 'Database.', 'woocommerce' ),  
  286. 'type' => 'object',  
  287. 'context' => array( 'view' ),  
  288. 'readonly' => true,  
  289. 'properties' => array( 
  290. 'wc_database_version' => array( 
  291. 'description' => __( 'WC database version.', 'woocommerce' ),  
  292. 'type' => 'string',  
  293. 'context' => array( 'view' ),  
  294. 'readonly' => true,  
  295. ),  
  296. 'database_prefix' => array( 
  297. 'description' => __( 'Database prefix.', 'woocommerce' ),  
  298. 'type' => 'string',  
  299. 'context' => array( 'view' ),  
  300. 'readonly' => true,  
  301. ),  
  302. 'maxmind_geoip_database' => array( 
  303. 'description' => __( 'MaxMind GeoIP database.', 'woocommerce' ),  
  304. 'type' => 'string',  
  305. 'context' => array( 'view' ),  
  306. 'readonly' => true,  
  307. ),  
  308. 'database_tables' => array( 
  309. 'description' => __( 'Database tables.', 'woocommerce' ),  
  310. 'type' => 'array',  
  311. 'context' => array( 'view' ),  
  312. 'readonly' => true,  
  313. 'items' => array( 
  314. 'type' => 'string',  
  315. ),  
  316. ),  
  317. ),  
  318. ),  
  319. 'active_plugins' => array( 
  320. 'description' => __( 'Active plugins.', 'woocommerce' ),  
  321. 'type' => 'array',  
  322. 'context' => array( 'view' ),  
  323. 'readonly' => true,  
  324. 'items' => array( 
  325. 'type' => 'string',  
  326. ),  
  327. ),  
  328. 'theme' => array( 
  329. 'description' => __( 'Theme.', 'woocommerce' ),  
  330. 'type' => 'object',  
  331. 'context' => array( 'view' ),  
  332. 'readonly' => true,  
  333. 'properties' => array( 
  334. 'name' => array( 
  335. 'description' => __( 'Theme name.', 'woocommerce' ),  
  336. 'type' => 'string',  
  337. 'context' => array( 'view' ),  
  338. 'readonly' => true,  
  339. ),  
  340. 'version' => array( 
  341. 'description' => __( 'Theme version.', 'woocommerce' ),  
  342. 'type' => 'string',  
  343. 'context' => array( 'view' ),  
  344. 'readonly' => true,  
  345. ),  
  346. 'version_latest' => array( 
  347. 'description' => __( 'Latest version of theme.', 'woocommerce' ),  
  348. 'type' => 'string',  
  349. 'context' => array( 'view' ),  
  350. 'readonly' => true,  
  351. ),  
  352. 'author_url' => array( 
  353. 'description' => __( 'Theme author URL.', 'woocommerce' ),  
  354. 'type' => 'string',  
  355. 'format' => 'uri',  
  356. 'context' => array( 'view' ),  
  357. 'readonly' => true,  
  358. ),  
  359. 'is_child_theme' => array( 
  360. 'description' => __( 'Is this theme a child theme?', 'woocommerce' ),  
  361. 'type' => 'boolean',  
  362. 'context' => array( 'view' ),  
  363. 'readonly' => true,  
  364. ),  
  365. 'has_woocommerce_support' => array( 
  366. 'description' => __( 'Does the theme declare WooCommerce support?', 'woocommerce' ),  
  367. 'type' => 'boolean',  
  368. 'context' => array( 'view' ),  
  369. 'readonly' => true,  
  370. ),  
  371. 'has_woocommerce_file' => array( 
  372. 'description' => __( 'Does the theme have a woocommerce.php file?', 'woocommerce' ),  
  373. 'type' => 'boolean',  
  374. 'context' => array( 'view' ),  
  375. 'readonly' => true,  
  376. ),  
  377. 'has_outdated_templates' => array( 
  378. 'description' => __( 'Does this theme have outdated templates?', 'woocommerce' ),  
  379. 'type' => 'boolean',  
  380. 'context' => array( 'view' ),  
  381. 'readonly' => true,  
  382. ),  
  383. 'overrides' => array( 
  384. 'description' => __( 'Template overrides.', 'woocommerce' ),  
  385. 'type' => 'array',  
  386. 'context' => array( 'view' ),  
  387. 'readonly' => true,  
  388. 'items' => array( 
  389. 'type' => 'string',  
  390. ),  
  391. ),  
  392. 'parent_name' => array( 
  393. 'description' => __( 'Parent theme name.', 'woocommerce' ),  
  394. 'type' => 'string',  
  395. 'context' => array( 'view' ),  
  396. 'readonly' => true,  
  397. ),  
  398. 'parent_version' => array( 
  399. 'description' => __( 'Parent theme version.', 'woocommerce' ),  
  400. 'type' => 'string',  
  401. 'context' => array( 'view' ),  
  402. 'readonly' => true,  
  403. ),  
  404. 'parent_author_url' => array( 
  405. 'description' => __( 'Parent theme author URL.', 'woocommerce' ),  
  406. 'type' => 'string',  
  407. 'format' => 'uri',  
  408. 'context' => array( 'view' ),  
  409. 'readonly' => true,  
  410. ),  
  411. ),  
  412. ),  
  413. 'settings' => array( 
  414. 'description' => __( 'Settings.', 'woocommerce' ),  
  415. 'type' => 'object',  
  416. 'context' => array( 'view' ),  
  417. 'readonly' => true,  
  418. 'properties' => array( 
  419. 'api_enabled' => array( 
  420. 'description' => __( 'REST API enabled?', 'woocommerce' ),  
  421. 'type' => 'boolean',  
  422. 'context' => array( 'view' ),  
  423. 'readonly' => true,  
  424. ),  
  425. 'force_ssl' => array( 
  426. 'description' => __( 'SSL forced?', 'woocommerce' ),  
  427. 'type' => 'boolean',  
  428. 'context' => array( 'view' ),  
  429. 'readonly' => true,  
  430. ),  
  431. 'currency' => array( 
  432. 'description' => __( 'Currency.', 'woocommerce' ),  
  433. 'type' => 'string',  
  434. 'context' => array( 'view' ),  
  435. 'readonly' => true,  
  436. ),  
  437. 'currency_symbol' => array( 
  438. 'description' => __( 'Currency symbol.', 'woocommerce' ),  
  439. 'type' => 'string',  
  440. 'context' => array( 'view' ),  
  441. 'readonly' => true,  
  442. ),  
  443. 'currency_position' => array( 
  444. 'description' => __( 'Currency position.', 'woocommerce' ),  
  445. 'type' => 'string',  
  446. 'context' => array( 'view' ),  
  447. 'readonly' => true,  
  448. ),  
  449. 'thousand_separator' => array( 
  450. 'description' => __( 'Thousand separator.', 'woocommerce' ),  
  451. 'type' => 'string',  
  452. 'context' => array( 'view' ),  
  453. 'readonly' => true,  
  454. ),  
  455. 'decimal_separator' => array( 
  456. 'description' => __( 'Decimal separator.', 'woocommerce' ),  
  457. 'type' => 'string',  
  458. 'context' => array( 'view' ),  
  459. 'readonly' => true,  
  460. ),  
  461. 'number_of_decimals' => array( 
  462. 'description' => __( 'Number of decimals.', 'woocommerce' ),  
  463. 'type' => 'integer',  
  464. 'context' => array( 'view' ),  
  465. 'readonly' => true,  
  466. ),  
  467. 'geolocation_enabled' => array( 
  468. 'description' => __( 'Geolocation enabled?', 'woocommerce' ),  
  469. 'type' => 'boolean',  
  470. 'context' => array( 'view' ),  
  471. 'readonly' => true,  
  472. ),  
  473. 'taxonomies' => array( 
  474. 'description' => __( 'Taxonomy terms for product/order statuses.', 'woocommerce' ),  
  475. 'type' => 'array',  
  476. 'context' => array( 'view' ),  
  477. 'readonly' => true,  
  478. 'items' => array( 
  479. 'type' => 'string',  
  480. ),  
  481. ),  
  482. 'product_visibility_terms' => array( 
  483. 'description' => __( 'Terms in the product visibility taxonomy.', 'woocommerce' ),  
  484. 'type' => 'array',  
  485. 'context' => array( 'view' ),  
  486. 'readonly' => true,  
  487. 'items' => array( 
  488. 'type' => 'string',  
  489. ),  
  490. ),  
  491. ),  
  492. ),  
  493. 'security' => array( 
  494. 'description' => __( 'Security.', 'woocommerce' ),  
  495. 'type' => 'object',  
  496. 'context' => array( 'view' ),  
  497. 'readonly' => true,  
  498. 'properties' => array( 
  499. 'secure_connection' => array( 
  500. 'description' => __( 'Is the connection to your store secure?', 'woocommerce' ),  
  501. 'type' => 'boolean',  
  502. 'context' => array( 'view' ),  
  503. 'readonly' => true,  
  504. ),  
  505. 'hide_errors' => array( 
  506. 'description' => __( 'Hide errors from visitors?', 'woocommerce' ),  
  507. 'type' => 'boolean',  
  508. 'context' => array( 'view' ),  
  509. 'readonly' => true,  
  510. ),  
  511. ),  
  512. ),  
  513. 'pages' => array( 
  514. 'description' => __( 'WooCommerce pages.', 'woocommerce' ),  
  515. 'type' => 'array',  
  516. 'context' => array( 'view' ),  
  517. 'readonly' => true,  
  518. 'items' => array( 
  519. 'type' => 'string',  
  520. ),  
  521. ),  
  522. ),  
  523. ); 
  524.  
  525. return $this->add_additional_fields_schema( $schema ); 
  526.  
  527. /** 
  528. * Return an array of sections and the data associated with each. 
  529. * 
  530. * @return array 
  531. */ 
  532. public function get_item_mappings() { 
  533. return array( 
  534. 'environment' => $this->get_environment_info(),  
  535. 'database' => $this->get_database_info(),  
  536. 'active_plugins' => $this->get_active_plugins(),  
  537. 'theme' => $this->get_theme_info(),  
  538. 'settings' => $this->get_settings(),  
  539. 'security' => $this->get_security_info(),  
  540. 'pages' => $this->get_pages(),  
  541. ); 
  542.  
  543. /** 
  544. * Get array of environment information. Includes thing like software 
  545. * versions, and various server settings. 
  546. * 
  547. * @return array 
  548. */ 
  549. public function get_environment_info() { 
  550. global $wpdb; 
  551.  
  552. // Figure out cURL version, if installed. 
  553. $curl_version = ''; 
  554. if ( function_exists( 'curl_version' ) ) { 
  555. $curl_version = curl_version(); 
  556. $curl_version = $curl_version['version'] . ', ' . $curl_version['ssl_version']; 
  557.  
  558. // WP memory limit 
  559. $wp_memory_limit = wc_let_to_num( WP_MEMORY_LIMIT ); 
  560. if ( function_exists( 'memory_get_usage' ) ) { 
  561. $wp_memory_limit = max( $wp_memory_limit, wc_let_to_num( @ini_get( 'memory_limit' ) ) ); 
  562.  
  563. // Test POST requests 
  564. $post_response = wp_safe_remote_post( 'https://www.paypal.com/cgi-bin/webscr', array( 
  565. 'timeout' => 10,  
  566. 'user-agent' => 'WooCommerce/' . WC()->version,  
  567. 'httpversion' => '1.1',  
  568. 'body' => array( 
  569. 'cmd' => '_notify-validate',  
  570. ),  
  571. ) ); 
  572. $post_response_successful = false; 
  573. if ( ! is_wp_error( $post_response ) && $post_response['response']['code'] >= 200 && $post_response['response']['code'] < 300 ) { 
  574. $post_response_successful = true; 
  575.  
  576. // Test GET requests 
  577. $get_response = wp_safe_remote_get( 'https://woocommerce.com/wc-api/product-key-api?request=ping&network=' . ( is_multisite() ? '1' : '0' ) ); 
  578. $get_response_successful = false; 
  579. if ( ! is_wp_error( $post_response ) && $post_response['response']['code'] >= 200 && $post_response['response']['code'] < 300 ) { 
  580. $get_response_successful = true; 
  581.  
  582. // Return all environment info. Described by JSON Schema. 
  583. return array( 
  584. 'home_url' => get_option( 'home' ),  
  585. 'site_url' => get_option( 'siteurl' ),  
  586. 'version' => WC()->version,  
  587. 'log_directory' => WC_LOG_DIR,  
  588. 'log_directory_writable' => ( @fopen( WC_LOG_DIR . 'test-log.log', 'a' ) ? true : false ),  
  589. 'wp_version' => get_bloginfo( 'version' ),  
  590. 'wp_multisite' => is_multisite(),  
  591. 'wp_memory_limit' => $wp_memory_limit,  
  592. 'wp_debug_mode' => ( defined( 'WP_DEBUG' ) && WP_DEBUG ),  
  593. 'wp_cron' => ! ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ),  
  594. 'language' => get_locale(),  
  595. 'server_info' => $_SERVER['SERVER_SOFTWARE'],  
  596. 'php_version' => phpversion(),  
  597. 'php_post_max_size' => wc_let_to_num( ini_get( 'post_max_size' ) ),  
  598. 'php_max_execution_time' => ini_get( 'max_execution_time' ),  
  599. 'php_max_input_vars' => ini_get( 'max_input_vars' ),  
  600. 'curl_version' => $curl_version,  
  601. 'suhosin_installed' => extension_loaded( 'suhosin' ),  
  602. 'max_upload_size' => wp_max_upload_size(),  
  603. 'mysql_version' => ( ! empty( $wpdb->is_mysql ) ? $wpdb->db_version() : '' ),  
  604. 'default_timezone' => date_default_timezone_get(),  
  605. 'fsockopen_or_curl_enabled' => ( function_exists( 'fsockopen' ) || function_exists( 'curl_init' ) ),  
  606. 'soapclient_enabled' => class_exists( 'SoapClient' ),  
  607. 'domdocument_enabled' => class_exists( 'DOMDocument' ),  
  608. 'gzip_enabled' => is_callable( 'gzopen' ),  
  609. 'mbstring_enabled' => extension_loaded( 'mbstring' ),  
  610. 'remote_post_successful' => $post_response_successful,  
  611. 'remote_post_response' => ( is_wp_error( $post_response ) ? $post_response->get_error_message() : $post_response['response']['code'] ),  
  612. 'remote_get_successful' => $get_response_successful,  
  613. 'remote_get_response' => ( is_wp_error( $get_response ) ? $get_response->get_error_message() : $get_response['response']['code'] ),  
  614. ); 
  615.  
  616. /** 
  617. * Get array of database information. Version, prefix, and table existence. 
  618. * 
  619. * @return array 
  620. */ 
  621. public function get_database_info() { 
  622. global $wpdb; 
  623.  
  624. // WC Core tables to check existence of 
  625. $tables = apply_filters( 'woocommerce_database_tables', array( 
  626. 'woocommerce_sessions',  
  627. 'woocommerce_api_keys',  
  628. 'woocommerce_attribute_taxonomies',  
  629. 'woocommerce_downloadable_product_permissions',  
  630. 'woocommerce_order_items',  
  631. 'woocommerce_order_itemmeta',  
  632. 'woocommerce_tax_rates',  
  633. 'woocommerce_tax_rate_locations',  
  634. 'woocommerce_shipping_zones',  
  635. 'woocommerce_shipping_zone_locations',  
  636. 'woocommerce_shipping_zone_methods',  
  637. 'woocommerce_payment_tokens',  
  638. 'woocommerce_payment_tokenmeta',  
  639. ) ); 
  640.  
  641. if ( get_option( 'db_version' ) < 34370 ) { 
  642. $tables[] = 'woocommerce_termmeta'; 
  643. $table_exists = array(); 
  644. foreach ( $tables as $table ) { 
  645. $table_exists[ $table ] = ( $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s;", $wpdb->prefix . $table ) ) === $wpdb->prefix . $table ); 
  646.  
  647. // Return all database info. Described by JSON Schema. 
  648. return array( 
  649. 'wc_database_version' => get_option( 'woocommerce_db_version' ),  
  650. 'database_prefix' => $wpdb->prefix,  
  651. 'maxmind_geoip_database' => WC_Geolocation::get_local_database_path(),  
  652. 'database_tables' => $table_exists,  
  653. ); 
  654.  
  655. /** 
  656. * Get a list of plugins active on the site. 
  657. * 
  658. * @return array 
  659. */ 
  660. public function get_active_plugins() { 
  661. require_once( ABSPATH . 'wp-admin/includes/plugin.php' ); 
  662.  
  663. // Get both site plugins and network plugins 
  664. $active_plugins = (array) get_option( 'active_plugins', array() ); 
  665. if ( is_multisite() ) { 
  666. $network_activated_plugins = array_keys( get_site_option( 'active_sitewide_plugins', array() ) ); 
  667. $active_plugins = array_merge( $active_plugins, $network_activated_plugins ); 
  668.  
  669. $active_plugins_data = array(); 
  670. $available_updates = get_plugin_updates(); 
  671.  
  672. foreach ( $active_plugins as $plugin ) { 
  673. $data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin ); 
  674. $dirname = dirname( $plugin ); 
  675. $version_latest = ''; 
  676. $slug = explode( '/', $plugin ); 
  677. $slug = explode( '.', end( $slug ) ); 
  678. $slug = $slug[0]; 
  679.  
  680. if ( 'woocommerce' !== $slug && ( strstr( $data['PluginURI'], 'woothemes.com' ) || strstr( $data['PluginURI'], 'woocommerce.com' ) ) ) { 
  681. if ( false === ( $version_data = get_transient( md5( $plugin ) . '_version_data' ) ) ) { 
  682. $changelog = wp_safe_remote_get( 'http://dzv365zjfbd8v.cloudfront.net/changelogs/' . $dirname . '/changelog.txt' ); 
  683. $cl_lines = explode( "\n", wp_remote_retrieve_body( $changelog ) ); 
  684. if ( ! empty( $cl_lines ) ) { 
  685. foreach ( $cl_lines as $line_num => $cl_line ) { 
  686. if ( preg_match( '/^[0-9]/', $cl_line ) ) { 
  687. $date = str_replace( '.' , '-' , trim( substr( $cl_line , 0 , strpos( $cl_line , '-' ) ) ) ); 
  688. $version = preg_replace( '~[^0-9, .]~' , '' , stristr( $cl_line , "version" ) ); 
  689. $update = trim( str_replace( "*" , "" , $cl_lines[ $line_num + 1 ] ) ); 
  690. $version_data = array( 'date' => $date , 'version' => $version , 'update' => $update , 'changelog' => $changelog ); 
  691. set_transient( md5( $plugin ) . '_version_data', $version_data, DAY_IN_SECONDS ); 
  692. break; 
  693. $version_latest = $version_data['version']; 
  694. } elseif ( isset( $available_updates[ $plugin ]->update->new_version ) ) { 
  695. $version_latest = $available_updates[ $plugin ]->update->new_version; 
  696.  
  697. // convert plugin data to json response format. 
  698. $active_plugins_data[] = array( 
  699. 'plugin' => $plugin,  
  700. 'name' => $data['Name'],  
  701. 'version' => $data['Version'],  
  702. 'version_latest' => $version_latest,  
  703. 'url' => $data['PluginURI'],  
  704. 'author_name' => $data['AuthorName'],  
  705. 'author_url' => esc_url_raw( $data['AuthorURI'] ),  
  706. 'network_activated' => $data['Network'],  
  707. ); 
  708.  
  709. return $active_plugins_data; 
  710.  
  711. /** 
  712. * Get info on the current active theme, info on parent theme (if presnet) 
  713. * and a list of template overrides. 
  714. * 
  715. * @return array 
  716. */ 
  717. public function get_theme_info() { 
  718. $active_theme = wp_get_theme(); 
  719.  
  720. // Get parent theme info if this theme is a child theme, otherwise 
  721. // pass empty info in the response. 
  722. if ( is_child_theme() ) { 
  723. $parent_theme = wp_get_theme( $active_theme->Template ); 
  724. $parent_theme_info = array( 
  725. 'parent_name' => $parent_theme->Name,  
  726. 'parent_version' => $parent_theme->Version,  
  727. 'parent_version_latest' => WC_Admin_Status::get_latest_theme_version( $parent_theme ),  
  728. 'parent_author_url' => $parent_theme->{'Author URI'},  
  729. ); 
  730. } else { 
  731. $parent_theme_info = array( 'parent_name' => '', 'parent_version' => '', 'parent_version_latest' => '', 'parent_author_url' => '' ); 
  732.  
  733. /** 
  734. * Scan the theme directory for all WC templates to see if our theme 
  735. * overrides any of them. 
  736. */ 
  737. $override_files = array(); 
  738. $outdated_templates = false; 
  739. $scan_files = WC_Admin_Status::scan_template_files( WC()->plugin_path() . '/templates/' ); 
  740. foreach ( $scan_files as $file ) { 
  741. if ( file_exists( get_stylesheet_directory() . '/' . $file ) ) { 
  742. $theme_file = get_stylesheet_directory() . '/' . $file; 
  743. } elseif ( file_exists( get_stylesheet_directory() . '/' . WC()->template_path() . $file ) ) { 
  744. $theme_file = get_stylesheet_directory() . '/' . WC()->template_path() . $file; 
  745. } elseif ( file_exists( get_template_directory() . '/' . $file ) ) { 
  746. $theme_file = get_template_directory() . '/' . $file; 
  747. } elseif ( file_exists( get_template_directory() . '/' . WC()->template_path() . $file ) ) { 
  748. $theme_file = get_template_directory() . '/' . WC()->template_path() . $file; 
  749. } else { 
  750. $theme_file = false; 
  751.  
  752. if ( ! empty( $theme_file ) ) { 
  753. $core_version = WC_Admin_Status::get_file_version( WC()->plugin_path() . '/templates/' . $file ); 
  754. $theme_version = WC_Admin_Status::get_file_version( $theme_file ); 
  755. if ( $core_version && ( empty( $theme_version ) || version_compare( $theme_version, $core_version, '<' ) ) ) { 
  756. if ( ! $outdated_templates ) { 
  757. $outdated_templates = true; 
  758. $override_files[] = array( 
  759. 'file' => str_replace( WP_CONTENT_DIR . '/themes/', '', $theme_file ),  
  760. 'version' => $theme_version,  
  761. 'core_version' => $core_version,  
  762. ); 
  763.  
  764. $active_theme_info = array( 
  765. 'name' => $active_theme->Name,  
  766. 'version' => $active_theme->Version,  
  767. 'version_latest' => WC_Admin_Status::get_latest_theme_version( $active_theme ),  
  768. 'author_url' => esc_url_raw( $active_theme->{'Author URI'} ),  
  769. 'is_child_theme' => is_child_theme(),  
  770. 'has_woocommerce_support' => ( current_theme_supports( 'woocommerce' ) || in_array( $active_theme->template, wc_get_core_supported_themes() ) ),  
  771. 'has_woocommerce_file' => ( file_exists( get_stylesheet_directory() . '/woocommerce.php' ) || file_exists( get_template_directory() . '/woocommerce.php' ) ),  
  772. 'has_outdated_templates' => $outdated_templates,  
  773. 'overrides' => $override_files,  
  774. ); 
  775.  
  776. return array_merge( $active_theme_info, $parent_theme_info ); 
  777.  
  778. /** 
  779. * Get some setting values for the site that are useful for debugging 
  780. * purposes. For full settings access, use the settings api. 
  781. * 
  782. * @return array 
  783. */ 
  784. public function get_settings() { 
  785. // Get a list of terms used for product/order taxonomies 
  786. $term_response = array(); 
  787. $terms = get_terms( 'product_type', array( 'hide_empty' => 0 ) ); 
  788. foreach ( $terms as $term ) { 
  789. $term_response[ $term->slug ] = strtolower( $term->name ); 
  790.  
  791. // Get a list of terms used for product visibility. 
  792. $product_visibility_terms = array(); 
  793. $terms = get_terms( 'product_visibility', array( 'hide_empty' => 0 ) ); 
  794. foreach ( $terms as $term ) { 
  795. $product_visibility_terms[ $term->slug ] = strtolower( $term->name ); 
  796.  
  797. // Return array of useful settings for debugging. 
  798. return array( 
  799. 'api_enabled' => 'yes' === get_option( 'woocommerce_api_enabled' ),  
  800. 'force_ssl' => 'yes' === get_option( 'woocommerce_force_ssl_checkout' ),  
  801. 'currency' => get_woocommerce_currency(),  
  802. 'currency_symbol' => get_woocommerce_currency_symbol(),  
  803. 'currency_position' => get_option( 'woocommerce_currency_pos' ),  
  804. 'thousand_separator' => wc_get_price_thousand_separator(),  
  805. 'decimal_separator' => wc_get_price_decimal_separator(),  
  806. 'number_of_decimals' => wc_get_price_decimals(),  
  807. 'geolocation_enabled' => in_array( get_option( 'woocommerce_default_customer_address' ), array( 'geolocation_ajax', 'geolocation' ) ),  
  808. 'taxonomies' => $term_response,  
  809. 'product_visibility_terms' => $product_visibility_terms,  
  810. ); 
  811.  
  812. /** 
  813. * Returns security tips. 
  814. * 
  815. * @return array 
  816. */ 
  817. public function get_security_info() { 
  818. $check_page = 0 < wc_get_page_id( 'shop' ) ? get_permalink( wc_get_page_id( 'shop' ) ) : get_home_url(); 
  819. return array( 
  820. 'secure_connection' => 'https' === substr( $check_page, 0, 5 ),  
  821. 'hide_errors' => ! ( defined( 'WP_DEBUG' ) && defined( 'WP_DEBUG_DISPLAY' ) && WP_DEBUG && WP_DEBUG_DISPLAY ) || 0 === intval( ini_get( 'display_errors' ) ),  
  822. ); 
  823.  
  824. /** 
  825. * Returns a mini-report on WC pages and if they are configured correctly: 
  826. * Present, visible, and including the correct shortcode. 
  827. * 
  828. * @return array 
  829. */ 
  830. public function get_pages() { 
  831. // WC pages to check against 
  832. $check_pages = array( 
  833. _x( 'Shop base', 'Page setting', 'woocommerce' ) => array( 
  834. 'option' => 'woocommerce_shop_page_id',  
  835. 'shortcode' => '',  
  836. ),  
  837. _x( 'Cart', 'Page setting', 'woocommerce' ) => array( 
  838. 'option' => 'woocommerce_cart_page_id',  
  839. 'shortcode' => '[' . apply_filters( 'woocommerce_cart_shortcode_tag', 'woocommerce_cart' ) . ']',  
  840. ),  
  841. _x( 'Checkout', 'Page setting', 'woocommerce' ) => array( 
  842. 'option' => 'woocommerce_checkout_page_id',  
  843. 'shortcode' => '[' . apply_filters( 'woocommerce_checkout_shortcode_tag', 'woocommerce_checkout' ) . ']',  
  844. ),  
  845. _x( 'My account', 'Page setting', 'woocommerce' ) => array( 
  846. 'option' => 'woocommerce_myaccount_page_id',  
  847. 'shortcode' => '[' . apply_filters( 'woocommerce_my_account_shortcode_tag', 'woocommerce_my_account' ) . ']',  
  848. ),  
  849. ); 
  850.  
  851. $pages_output = array(); 
  852. foreach ( $check_pages as $page_name => $values ) { 
  853. $errors = array(); 
  854. $page_id = get_option( $values['option'] ); 
  855. $page_set = $page_exists = $page_visible = false; 
  856. $shortcode_present = $shortcode_required = false; 
  857.  
  858. // Page checks 
  859. if ( $page_id ) { 
  860. $page_set = true; 
  861. if ( get_post( $page_id ) ) { 
  862. $page_exists = true; 
  863. if ( 'publish' === get_post_status( $page_id ) ) { 
  864. $page_visible = true; 
  865.  
  866. // Shortcode checks 
  867. if ( $values['shortcode'] && get_post( $page_id ) ) { 
  868. $shortcode_required = true; 
  869. $page = get_post( $page_id ); 
  870. if ( strstr( $page->post_content, $values['shortcode'] ) ) { 
  871. $shortcode_present = true; 
  872.  
  873. // Wrap up our findings into an output array 
  874. $pages_output[] = array( 
  875. 'page_name' => $page_name,  
  876. 'page_id' => $page_id,  
  877. 'page_set' => $page_set,  
  878. 'page_exists' => $page_exists,  
  879. 'page_visible' => $page_visible,  
  880. 'shortcode' => $values['shortcode'],  
  881. 'shortcode_required' => $shortcode_required,  
  882. 'shortcode_present' => $shortcode_present,  
  883. ); 
  884.  
  885. return $pages_output; 
  886.  
  887. /** 
  888. * Get any query params needed. 
  889. * 
  890. * @return array 
  891. */ 
  892. public function get_collection_params() { 
  893. return array( 
  894. 'context' => $this->get_context_param( array( 'default' => 'view' ) ),  
  895. ); 
  896.  
  897. /** 
  898. * Prepare the system status response 
  899. * 
  900. * @param array $system_status 
  901. * @param WP_REST_Request $request Request object. 
  902. * @return WP_REST_Response $response Response data. 
  903. */ 
  904. public function prepare_item_for_response( $system_status, $request ) { 
  905. $data = $this->add_additional_fields_to_object( $system_status, $request ); 
  906. $data = $this->filter_response_by_context( $data, 'view' ); 
  907.  
  908. $response = rest_ensure_response( $data ); 
  909.  
  910. /** 
  911. * Filter the system status returned from the REST API. 
  912. * 
  913. * @param WP_REST_Response $response The response object. 
  914. * @param mixed $system_status System status 
  915. * @param WP_REST_Request $request Request object. 
  916. */ 
  917. return apply_filters( 'woocommerce_rest_prepare_system_status', $response, $system_status, $request ); 
.