WC_REST_System_Status_Tools_Controller

The WooCommerce WC REST System Status Tools Controller class.

Defined (1)

The class is defined in the following location(s).

/includes/api/class-wc-rest-system-status-tools-controller.php  
  1. class WC_REST_System_Status_Tools_Controller extends WC_REST_Controller { 
  2.  
  3. /** 
  4. * Endpoint namespace. 
  5. * @var string 
  6. */ 
  7. protected $namespace = 'wc/v2'; 
  8.  
  9. /** 
  10. * Route base. 
  11. * @var string 
  12. */ 
  13. protected $rest_base = 'system_status/tools'; 
  14.  
  15. /** 
  16. * Register the routes for /system_status/tools/**. 
  17. */ 
  18. public function register_routes() { 
  19. register_rest_route( $this->namespace, '/' . $this->rest_base, array( 
  20. array( 
  21. 'methods' => WP_REST_Server::READABLE,  
  22. 'callback' => array( $this, 'get_items' ),  
  23. 'permission_callback' => array( $this, 'get_items_permissions_check' ),  
  24. 'args' => $this->get_collection_params(),  
  25. ),  
  26. 'schema' => array( $this, 'get_public_item_schema' ),  
  27. ) ); 
  28.  
  29. register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\w-]+)', array( 
  30. 'args' => array( 
  31. 'id' => array( 
  32. 'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),  
  33. 'type' => 'string',  
  34. ),  
  35. ),  
  36. array( 
  37. 'methods' => WP_REST_Server::READABLE,  
  38. 'callback' => array( $this, 'get_item' ),  
  39. 'permission_callback' => array( $this, 'get_item_permissions_check' ),  
  40. ),  
  41. array( 
  42. 'methods' => WP_REST_Server::EDITABLE,  
  43. 'callback' => array( $this, 'update_item' ),  
  44. 'permission_callback' => array( $this, 'update_item_permissions_check' ),  
  45. 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),  
  46. ),  
  47. 'schema' => array( $this, 'get_public_item_schema' ),  
  48. ) ); 
  49.  
  50. /** 
  51. * Check whether a given request has permission to view system status tools. 
  52. * @param WP_REST_Request $request Full details about the request. 
  53. * @return WP_Error|boolean 
  54. */ 
  55. public function get_items_permissions_check( $request ) { 
  56. if ( ! wc_rest_check_manager_permissions( 'system_status', 'read' ) ) { 
  57. return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); 
  58. return true; 
  59.  
  60. /** 
  61. * Check whether a given request has permission to view a specific system status tool. 
  62. * @param WP_REST_Request $request Full details about the request. 
  63. * @return WP_Error|boolean 
  64. */ 
  65. public function get_item_permissions_check( $request ) { 
  66. if ( ! wc_rest_check_manager_permissions( 'system_status', 'read' ) ) { 
  67. return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); 
  68. return true; 
  69.  
  70. /** 
  71. * Check whether a given request has permission to execute a specific system status tool. 
  72. * @param WP_REST_Request $request Full details about the request. 
  73. * @return WP_Error|boolean 
  74. */ 
  75. public function update_item_permissions_check( $request ) { 
  76. if ( ! wc_rest_check_manager_permissions( 'system_status', 'edit' ) ) { 
  77. return new WP_Error( 'woocommerce_rest_cannot_update', __( 'Sorry, you cannot update resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); 
  78. return true; 
  79.  
  80. /** 
  81. * A list of avaiable tools for use in the system status section. 
  82. * 'button' becomes 'action' in the API. 
  83. * @return array 
  84. */ 
  85. public function get_tools() { 
  86. $tools = array( 
  87. 'clear_transients' => array( 
  88. 'name' => __( 'WC transients', 'woocommerce' ),  
  89. 'button' => __( 'Clear transients', 'woocommerce' ),  
  90. 'desc' => __( 'This tool will clear the product/shop transients cache.', 'woocommerce' ),  
  91. ),  
  92. 'clear_expired_transients' => array( 
  93. 'name' => __( 'Expired transients', 'woocommerce' ),  
  94. 'button' => __( 'Clear expired transients', 'woocommerce' ),  
  95. 'desc' => __( 'This tool will clear ALL expired transients from WordPress.', 'woocommerce' ),  
  96. ),  
  97. 'delete_orphaned_variations' => array( 
  98. 'name' => __( 'Orphaned variations', 'woocommerce' ),  
  99. 'button' => __( 'Delete orphaned variations', 'woocommerce' ),  
  100. 'desc' => __( 'This tool will delete all variations which have no parent.', 'woocommerce' ),  
  101. ),  
  102. 'recount_terms' => array( 
  103. 'name' => __( 'Term counts', 'woocommerce' ),  
  104. 'button' => __( 'Recount terms', 'woocommerce' ),  
  105. 'desc' => __( 'This tool will recount product terms - useful when changing your settings in a way which hides products from the catalog.', 'woocommerce' ),  
  106. ),  
  107. 'reset_roles' => array( 
  108. 'name' => __( 'Capabilities', 'woocommerce' ),  
  109. 'button' => __( 'Reset capabilities', 'woocommerce' ),  
  110. 'desc' => __( 'This tool will reset the admin, customer and shop_manager roles to default. Use this if your users cannot access all of the WooCommerce admin pages.', 'woocommerce' ),  
  111. ),  
  112. 'clear_sessions' => array( 
  113. 'name' => __( 'Customer sessions', 'woocommerce' ),  
  114. 'button' => __( 'Clear all sessions', 'woocommerce' ),  
  115. 'desc' => sprintf( 
  116. '<strong class="red">%1$s</strong> %2$s',  
  117. __( 'Note:', 'woocommerce' ),  
  118. __( 'This tool will delete all customer session data from the database, including any current live carts.', 'woocommerce' ) 
  119. ),  
  120. ),  
  121. 'install_pages' => array( 
  122. 'name' => __( 'Install WooCommerce pages', 'woocommerce' ),  
  123. 'button' => __( 'Install pages', 'woocommerce' ),  
  124. 'desc' => sprintf( 
  125. '<strong class="red">%1$s</strong> %2$s',  
  126. __( 'Note:', 'woocommerce' ),  
  127. __( 'This tool will install all the missing WooCommerce pages. Pages already defined and set up will not be replaced.', 'woocommerce' ) 
  128. ),  
  129. ),  
  130. 'delete_taxes' => array( 
  131. 'name' => __( 'Delete all WooCommerce tax rates', 'woocommerce' ),  
  132. 'button' => __( 'Delete ALL tax rates', 'woocommerce' ),  
  133. 'desc' => sprintf( 
  134. '<strong class="red">%1$s</strong> %2$s',  
  135. __( 'Note:', 'woocommerce' ),  
  136. __( 'This option will delete ALL of your tax rates, use with caution.', 'woocommerce' ) 
  137. ),  
  138. ),  
  139. 'reset_tracking' => array( 
  140. 'name' => __( 'Reset usage tracking settings', 'woocommerce' ),  
  141. 'button' => __( 'Reset usage tracking settings', 'woocommerce' ),  
  142. 'desc' => __( 'This will reset your usage tracking settings, causing it to show the opt-in banner again and not sending any data.', 'woocommerce' ),  
  143. ),  
  144. ); 
  145.  
  146. return apply_filters( 'woocommerce_debug_tools', $tools ); 
  147.  
  148. /** 
  149. * Get a list of system status tools. 
  150. * @param WP_REST_Request $request Full details about the request. 
  151. * @return WP_Error|WP_REST_Response 
  152. */ 
  153. public function get_items( $request ) { 
  154. $tools = array(); 
  155. foreach ( $this->get_tools() as $id => $tool ) { 
  156. $tools[] = $this->prepare_response_for_collection( $this->prepare_item_for_response( array( 
  157. 'id' => $id,  
  158. 'name' => $tool['name'],  
  159. 'action' => $tool['button'],  
  160. 'description' => $tool['desc'],  
  161. ), $request ) ); 
  162.  
  163. $response = rest_ensure_response( $tools ); 
  164. return $response; 
  165.  
  166. /** 
  167. * Return a single tool. 
  168. * @param WP_REST_Request $request 
  169. * @return WP_Error|WP_REST_Response 
  170. */ 
  171. public function get_item( $request ) { 
  172. $tools = $this->get_tools(); 
  173. if ( empty( $tools[ $request['id'] ] ) ) { 
  174. return new WP_Error( 'woocommerce_rest_system_status_tool_invalid_id', __( 'Invalid tool ID.', 'woocommerce' ), array( 'status' => 404 ) ); 
  175. $tool = $tools[ $request['id'] ]; 
  176. return rest_ensure_response( $this->prepare_item_for_response( array( 
  177. 'id' => $request['id'],  
  178. 'name' => $tool['name'],  
  179. 'action' => $tool['button'],  
  180. 'description' => $tool['desc'],  
  181. ), $request ) ); 
  182.  
  183. /** 
  184. * Update (execute) a tool. 
  185. * @param WP_REST_Request $request 
  186. * @return WP_Error|WP_REST_Response 
  187. */ 
  188. public function update_item( $request ) { 
  189. $tools = $this->get_tools(); 
  190. if ( empty( $tools[ $request['id'] ] ) ) { 
  191. return new WP_Error( 'woocommerce_rest_system_status_tool_invalid_id', __( 'Invalid tool ID.', 'woocommerce' ), array( 'status' => 404 ) ); 
  192.  
  193. $tool = $tools[ $request['id'] ]; 
  194. $tool = array( 
  195. 'id' => $request['id'],  
  196. 'name' => $tool['name'],  
  197. 'action' => $tool['button'],  
  198. 'description' => $tool['desc'],  
  199. ); 
  200.  
  201. $execute_return = $this->execute_tool( $request['id'] ); 
  202. $tool = array_merge( $tool, $execute_return ); 
  203.  
  204. $request->set_param( 'context', 'edit' ); 
  205. $response = $this->prepare_item_for_response( $tool, $request ); 
  206. return rest_ensure_response( $response ); 
  207.  
  208. /** 
  209. * Prepare a tool item for serialization. 
  210. * @param array $item Object. 
  211. * @param WP_REST_Request $request Request object. 
  212. * @return WP_REST_Response $response Response data. 
  213. */ 
  214. public function prepare_item_for_response( $item, $request ) { 
  215. $context = empty( $request['context'] ) ? 'view' : $request['context']; 
  216. $data = $this->add_additional_fields_to_object( $item, $request ); 
  217. $data = $this->filter_response_by_context( $data, $context ); 
  218.  
  219. $response = rest_ensure_response( $data ); 
  220.  
  221. $response->add_links( $this->prepare_links( $item['id'] ) ); 
  222.  
  223. return $response; 
  224.  
  225. /** 
  226. * Get the system status tools schema, conforming to JSON Schema. 
  227. * @return array 
  228. */ 
  229. public function get_item_schema() { 
  230. $schema = array( 
  231. '$schema' => 'http://json-schema.org/draft-04/schema#',  
  232. 'title' => 'system_status_tool',  
  233. 'type' => 'object',  
  234. 'properties' => array( 
  235. 'id' => array( 
  236. 'description' => __( 'A unique identifier for the tool.', 'woocommerce' ),  
  237. 'type' => 'string',  
  238. 'context' => array( 'view', 'edit' ),  
  239. 'arg_options' => array( 
  240. 'sanitize_callback' => 'sanitize_title',  
  241. ),  
  242. ),  
  243. 'name' => array( 
  244. 'description' => __( 'Tool name.', 'woocommerce' ),  
  245. 'type' => 'string',  
  246. 'context' => array( 'view', 'edit' ),  
  247. 'arg_options' => array( 
  248. 'sanitize_callback' => 'sanitize_text_field',  
  249. ),  
  250. ),  
  251. 'action' => array( 
  252. 'description' => __( 'What running the tool will do.', 'woocommerce' ),  
  253. 'type' => 'string',  
  254. 'context' => array( 'view', 'edit' ),  
  255. 'arg_options' => array( 
  256. 'sanitize_callback' => 'sanitize_text_field',  
  257. ),  
  258. ),  
  259. 'description' => array( 
  260. 'description' => __( 'Tool description.', 'woocommerce' ),  
  261. 'type' => 'string',  
  262. 'context' => array( 'view', 'edit' ),  
  263. 'arg_options' => array( 
  264. 'sanitize_callback' => 'sanitize_text_field',  
  265. ),  
  266. ),  
  267. 'success' => array( 
  268. 'description' => __( 'Did the tool run successfully?', 'woocommerce' ),  
  269. 'type' => 'boolean',  
  270. 'context' => array( 'edit' ),  
  271. ),  
  272. 'message' => array( 
  273. 'description' => __( 'Tool return message.', 'woocommerce' ),  
  274. 'type' => 'string',  
  275. 'context' => array( 'edit' ),  
  276. 'arg_options' => array( 
  277. 'sanitize_callback' => 'sanitize_text_field',  
  278. ),  
  279. ),  
  280. ),  
  281. ); 
  282.  
  283. return $this->add_additional_fields_schema( $schema ); 
  284.  
  285. /** 
  286. * Prepare links for the request. 
  287. * @param string $id 
  288. * @return array 
  289. */ 
  290. protected function prepare_links( $id ) { 
  291. $base = '/' . $this->namespace . '/' . $this->rest_base; 
  292. $links = array( 
  293. 'item' => array( 
  294. 'href' => rest_url( trailingslashit( $base ) . $id ),  
  295. 'embeddable' => true,  
  296. ),  
  297. ); 
  298.  
  299. return $links; 
  300.  
  301. /** 
  302. * Get any query params needed. 
  303. * @return array 
  304. */ 
  305. public function get_collection_params() { 
  306. return array( 
  307. 'context' => $this->get_context_param( array( 'default' => 'view' ) ),  
  308. ); 
  309.  
  310. /** 
  311. * Actually executes a a tool. 
  312. * @param string $tool 
  313. * @return array 
  314. */ 
  315. public function execute_tool( $tool ) { 
  316. global $wpdb; 
  317. $ran = true; 
  318. switch ( $tool ) { 
  319. case 'clear_transients' : 
  320. wc_delete_product_transients(); 
  321. wc_delete_shop_order_transients(); 
  322. WC_Cache_Helper::get_transient_version( 'shipping', true ); 
  323. $message = __( 'Product transients cleared', 'woocommerce' ); 
  324. break; 
  325. case 'clear_expired_transients' : 
  326. /** 
  327. * Deletes all expired transients. The multi-table delete syntax is used. 
  328. * to delete the transient record from table a, and the corresponding. 
  329. * transient_timeout record from table b. 
  330. * Based on code inside core's upgrade_network() function. 
  331. */ 
  332. $sql = "DELETE a, b FROM $wpdb->options a, $wpdb->options b 
  333. WHERE a.option_name LIKE %s 
  334. AND a.option_name NOT LIKE %s 
  335. AND b.option_name = CONCAT( '_transient_timeout_', SUBSTRING( a.option_name, 12 ) ) 
  336. AND b.option_value < %d"; 
  337. $rows = $wpdb->query( $wpdb->prepare( $sql, $wpdb->esc_like( '_transient_' ) . '%', $wpdb->esc_like( '_transient_timeout_' ) . '%', time() ) ); 
  338.  
  339. $sql = "DELETE a, b FROM $wpdb->options a, $wpdb->options b 
  340. WHERE a.option_name LIKE %s 
  341. AND a.option_name NOT LIKE %s 
  342. AND b.option_name = CONCAT( '_site_transient_timeout_', SUBSTRING( a.option_name, 17 ) ) 
  343. AND b.option_value < %d"; 
  344. $rows2 = $wpdb->query( $wpdb->prepare( $sql, $wpdb->esc_like( '_site_transient_' ) . '%', $wpdb->esc_like( '_site_transient_timeout_' ) . '%', time() ) ); 
  345.  
  346. $message = sprintf( __( '%d transients rows cleared', 'woocommerce' ), $rows + $rows2 ); 
  347. break; 
  348. case 'delete_orphaned_variations' : 
  349. /** 
  350. * Delete orphans 
  351. */ 
  352. $result = absint( $wpdb->query( "DELETE products 
  353. FROM {$wpdb->posts} products 
  354. LEFT JOIN {$wpdb->posts} wp ON wp.ID = products.post_parent 
  355. WHERE wp.ID IS NULL AND products.post_type = 'product_variation';" ) ); 
  356. $message = sprintf( __( '%d orphaned variations deleted', 'woocommerce' ), $result ); 
  357. break; 
  358. case 'reset_roles' : 
  359. // Remove then re-add caps and roles 
  360. WC_Install::remove_roles(); 
  361. WC_Install::create_roles(); 
  362. $message = __( 'Roles successfully reset', 'woocommerce' ); 
  363. break; 
  364. case 'recount_terms' : 
  365. $product_cats = get_terms( 'product_cat', array( 'hide_empty' => false, 'fields' => 'id=>parent' ) ); 
  366. _wc_term_recount( $product_cats, get_taxonomy( 'product_cat' ), true, false ); 
  367. $product_tags = get_terms( 'product_tag', array( 'hide_empty' => false, 'fields' => 'id=>parent' ) ); 
  368. _wc_term_recount( $product_tags, get_taxonomy( 'product_tag' ), true, false ); 
  369. $message = __( 'Terms successfully recounted', 'woocommerce' ); 
  370. break; 
  371. case 'clear_sessions' : 
  372. $wpdb->query( "TRUNCATE {$wpdb->prefix}woocommerce_sessions" ); 
  373. wp_cache_flush(); 
  374. $message = __( 'Sessions successfully cleared', 'woocommerce' ); 
  375. break; 
  376. case 'install_pages' : 
  377. WC_Install::create_pages(); 
  378. $message = __( 'All missing WooCommerce pages successfully installed', 'woocommerce' ); 
  379. break; 
  380. case 'delete_taxes' : 
  381.  
  382. $wpdb->query( "TRUNCATE TABLE {$wpdb->prefix}woocommerce_tax_rates;" ); 
  383. $wpdb->query( "TRUNCATE TABLE {$wpdb->prefix}woocommerce_tax_rate_locations;" ); 
  384. WC_Cache_Helper::incr_cache_prefix( 'taxes' ); 
  385. $message = __( 'Tax rates successfully deleted', 'woocommerce' ); 
  386. break; 
  387. case 'reset_tracking' : 
  388. delete_option( 'woocommerce_allow_tracking' ); 
  389. WC_Admin_Notices::add_notice( 'tracking' ); 
  390. $message = __( 'Usage tracking settings successfully reset.', 'woocommerce' ); 
  391. break; 
  392. default : 
  393. $tools = $this->get_tools(); 
  394. if ( isset( $tools[ $tool ]['callback'] ) ) { 
  395. $callback = $tools[ $tool ]['callback']; 
  396. $return = call_user_func( $callback ); 
  397. if ( false === $return ) { 
  398. $callback_string = is_array( $callback ) ? get_class( $callback[0] ) . '::' . $callback[1] : $callback; 
  399. $ran = false; 
  400. $message = sprintf( __( 'There was an error calling %s', 'woocommerce' ), $callback_string ); 
  401. } else { 
  402. $message = __( 'Tool ran.', 'woocommerce' ); 
  403. } else { 
  404. $ran = false; 
  405. $message = __( 'There was an error calling this tool. There is no callback present.', 'woocommerce' ); 
  406. break; 
  407.  
  408. return array( 'success' => $ran, 'message' => $message );