diff --git a/includes/api/class-wc-rest-system-status-tools-controller.php b/includes/api/class-wc-rest-system-status-tools-controller.php index abc2ad943ec..b0c8561ecef 100644 --- a/includes/api/class-wc-rest-system-status-tools-controller.php +++ b/includes/api/class-wc-rest-system-status-tools-controller.php @@ -49,7 +49,7 @@ class WC_REST_System_Status_Tools_Controller extends WC_REST_Controller { ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\w-]+)', array( - 'args' => array( + 'args' => array( 'id' => array( 'description' => __( 'Unique identifier for the resource.', 'woocommerce' ), 'type' => 'string', @@ -117,67 +117,67 @@ class WC_REST_System_Status_Tools_Controller extends WC_REST_Controller { */ public function get_tools() { $tools = array( - 'clear_transients' => array( - 'name' => __( 'WooCommerce transients', 'woocommerce' ), - 'button' => __( 'Clear transients', 'woocommerce' ), - 'desc' => __( 'This tool will clear the product/shop transients cache.', 'woocommerce' ), + 'clear_transients' => array( + 'name' => __( 'WooCommerce transients', 'woocommerce' ), + 'button' => __( 'Clear transients', 'woocommerce' ), + 'desc' => __( 'This tool will clear the product/shop transients cache.', 'woocommerce' ), ), - 'clear_expired_transients' => array( - 'name' => __( 'Expired transients', 'woocommerce' ), - 'button' => __( 'Clear transients', 'woocommerce' ), - 'desc' => __( 'This tool will clear ALL expired transients from WordPress.', 'woocommerce' ), + 'clear_expired_transients' => array( + 'name' => __( 'Expired transients', 'woocommerce' ), + 'button' => __( 'Clear transients', 'woocommerce' ), + 'desc' => __( 'This tool will clear ALL expired transients from WordPress.', 'woocommerce' ), ), 'delete_orphaned_variations' => array( - 'name' => __( 'Orphaned variations', 'woocommerce' ), - 'button' => __( 'Delete orphaned variations', 'woocommerce' ), - 'desc' => __( 'This tool will delete all variations which have no parent.', 'woocommerce' ), + 'name' => __( 'Orphaned variations', 'woocommerce' ), + 'button' => __( 'Delete orphaned variations', 'woocommerce' ), + 'desc' => __( 'This tool will delete all variations which have no parent.', 'woocommerce' ), ), - 'add_order_indexes' => array( - 'name' => __( 'Order address indexes', 'woocommerce' ), - 'button' => __( 'Index orders', 'woocommerce' ), - 'desc' => __( 'This tool will add address indexes to orders that do not have them yet. This improves order search results.', 'woocommerce' ), + 'add_order_indexes' => array( + 'name' => __( 'Order address indexes', 'woocommerce' ), + 'button' => __( 'Index orders', 'woocommerce' ), + 'desc' => __( 'This tool will add address indexes to orders that do not have them yet. This improves order search results.', 'woocommerce' ), ), - 'recount_terms' => array( - 'name' => __( 'Term counts', 'woocommerce' ), - 'button' => __( 'Recount terms', 'woocommerce' ), - 'desc' => __( 'This tool will recount product terms - useful when changing your settings in a way which hides products from the catalog.', 'woocommerce' ), + 'recount_terms' => array( + 'name' => __( 'Term counts', 'woocommerce' ), + 'button' => __( 'Recount terms', 'woocommerce' ), + 'desc' => __( 'This tool will recount product terms - useful when changing your settings in a way which hides products from the catalog.', 'woocommerce' ), ), - 'reset_roles' => array( - 'name' => __( 'Capabilities', 'woocommerce' ), - 'button' => __( 'Reset capabilities', 'woocommerce' ), - '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' ), + 'reset_roles' => array( + 'name' => __( 'Capabilities', 'woocommerce' ), + 'button' => __( 'Reset capabilities', 'woocommerce' ), + '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' ), ), - 'clear_sessions' => array( - 'name' => __( 'Clear customer sessions', 'woocommerce' ), - 'button' => __( 'Clear', 'woocommerce' ), - 'desc' => sprintf( + 'clear_sessions' => array( + 'name' => __( 'Clear customer sessions', 'woocommerce' ), + 'button' => __( 'Clear', 'woocommerce' ), + 'desc' => sprintf( '%1$s %2$s', __( 'Note:', 'woocommerce' ), __( 'This tool will delete all customer session data from the database, including current carts and saved carts in the database.', 'woocommerce' ) ), ), - 'install_pages' => array( - 'name' => __( 'Create default WooCommerce pages', 'woocommerce' ), - 'button' => __( 'Create pages', 'woocommerce' ), - 'desc' => sprintf( + 'install_pages' => array( + 'name' => __( 'Create default WooCommerce pages', 'woocommerce' ), + 'button' => __( 'Create pages', 'woocommerce' ), + 'desc' => sprintf( '%1$s %2$s', __( 'Note:', 'woocommerce' ), __( 'This tool will install all the missing WooCommerce pages. Pages already defined and set up will not be replaced.', 'woocommerce' ) ), ), - 'delete_taxes' => array( - 'name' => __( 'Delete WooCommerce tax rates', 'woocommerce' ), - 'button' => __( 'Delete tax rates', 'woocommerce' ), - 'desc' => sprintf( + 'delete_taxes' => array( + 'name' => __( 'Delete WooCommerce tax rates', 'woocommerce' ), + 'button' => __( 'Delete tax rates', 'woocommerce' ), + 'desc' => sprintf( '%1$s %2$s', __( 'Note:', 'woocommerce' ), __( 'This option will delete ALL of your tax rates, use with caution. This action cannot be reversed.', 'woocommerce' ) ), ), - 'reset_tracking' => array( - 'name' => __( 'Reset usage tracking', 'woocommerce' ), - 'button' => __( 'Reset', 'woocommerce' ), - 'desc' => __( 'This will reset your usage tracking settings, causing it to show the opt-in banner again and not sending any data.', 'woocommerce' ), + 'reset_tracking' => array( + 'name' => __( 'Reset usage tracking', 'woocommerce' ), + 'button' => __( 'Reset', 'woocommerce' ), + 'desc' => __( 'This will reset your usage tracking settings, causing it to show the opt-in banner again and not sending any data.', 'woocommerce' ), ), ); @@ -227,6 +227,7 @@ class WC_REST_System_Status_Tools_Controller extends WC_REST_Controller { /** * Update (execute) a tool. + * * @param WP_REST_Request $request * @return WP_Error|WP_REST_Response */ @@ -238,14 +239,22 @@ class WC_REST_System_Status_Tools_Controller extends WC_REST_Controller { $tool = $tools[ $request['id'] ]; $tool = array( - 'id' => $request['id'], - 'name' => $tool['name'], - 'action' => $tool['button'], - 'description' => $tool['desc'], + 'id' => $request['id'], + 'name' => $tool['name'], + 'action' => $tool['button'], + 'description' => $tool['desc'], ); $execute_return = $this->execute_tool( $request['id'] ); - $tool = array_merge( $tool, $execute_return ); + $tool = array_merge( $tool, $execute_return ); + + /** + * Fires after a WooCommerce REST system status tool has been executed. + * + * @param array $tool Details about the tool that has been executed. + * @param WP_REST_Request $request The current WP_REST_Request object. + */ + do_action( 'woocommerce_rest_insert_system_status_tool', $tool, $request ); $request->set_param( 'context', 'edit' ); $response = $this->prepare_item_for_response( $tool, $request ); @@ -255,8 +264,8 @@ class WC_REST_System_Status_Tools_Controller extends WC_REST_Controller { /** * Prepare a tool item for serialization. * - * @param array $item Object. - * @param WP_REST_Request $request Request object. + * @param array $item Object. + * @param WP_REST_Request $request Request object. * @return WP_REST_Response $response Response data. */ public function prepare_item_for_response( $item, $request ) { @@ -282,48 +291,48 @@ class WC_REST_System_Status_Tools_Controller extends WC_REST_Controller { 'title' => 'system_status_tool', 'type' => 'object', 'properties' => array( - 'id' => array( - 'description' => __( 'A unique identifier for the tool.', 'woocommerce' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( + 'id' => array( + 'description' => __( 'A unique identifier for the tool.', 'woocommerce' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'arg_options' => array( 'sanitize_callback' => 'sanitize_title', ), ), - 'name' => array( - 'description' => __( 'Tool name.', 'woocommerce' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( + 'name' => array( + 'description' => __( 'Tool name.', 'woocommerce' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), - 'action' => array( - 'description' => __( 'What running the tool will do.', 'woocommerce' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( + 'action' => array( + 'description' => __( 'What running the tool will do.', 'woocommerce' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), - 'description' => array( - 'description' => __( 'Tool description.', 'woocommerce' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( + 'description' => array( + 'description' => __( 'Tool description.', 'woocommerce' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), - 'success' => array( - 'description' => __( 'Did the tool run successfully?', 'woocommerce' ), - 'type' => 'boolean', - 'context' => array( 'edit' ), + 'success' => array( + 'description' => __( 'Did the tool run successfully?', 'woocommerce' ), + 'type' => 'boolean', + 'context' => array( 'edit' ), ), - 'message' => array( - 'description' => __( 'Tool return message.', 'woocommerce' ), - 'type' => 'string', - 'context' => array( 'edit' ), - 'arg_options' => array( + 'message' => array( + 'description' => __( 'Tool return message.', 'woocommerce' ), + 'type' => 'string', + 'context' => array( 'edit' ), + 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), @@ -372,31 +381,34 @@ class WC_REST_System_Status_Tools_Controller extends WC_REST_Controller { global $wpdb; $ran = true; switch ( $tool ) { - case 'clear_transients' : + case 'clear_transients': wc_delete_product_transients(); wc_delete_shop_order_transients(); WC_Cache_Helper::get_transient_version( 'shipping', true ); $message = __( 'Product transients cleared', 'woocommerce' ); - break; - case 'clear_expired_transients' : + break; + + case 'clear_expired_transients': $message = sprintf( __( '%d transients rows cleared', 'woocommerce' ), wc_delete_expired_transients() ); - break; - case 'delete_orphaned_variations' : + break; + + case 'delete_orphaned_variations': /** * Delete orphans */ - $result = absint( $wpdb->query( "DELETE products + $result = absint( $wpdb->query( "DELETE products FROM {$wpdb->posts} products LEFT JOIN {$wpdb->posts} wp ON wp.ID = products.post_parent WHERE wp.ID IS NULL AND products.post_type = 'product_variation';" ) ); $message = sprintf( __( '%d orphaned variations deleted', 'woocommerce' ), $result ); - break; - case 'add_order_indexes' : + break; + + case 'add_order_indexes': /** * Add billing and shipping address indexes containing the customer name for orders * that don't have address indexes yet. */ - $sql = "INSERT INTO {$wpdb->postmeta}( post_id, meta_key, meta_value ) + $sql = "INSERT INTO {$wpdb->postmeta}( post_id, meta_key, meta_value ) SELECT post_id, '%s', GROUP_CONCAT( meta_value SEPARATOR ' ' ) FROM {$wpdb->postmeta} WHERE meta_key IN ( '%s', '%s' ) @@ -404,57 +416,69 @@ class WC_REST_System_Status_Tools_Controller extends WC_REST_Controller { WHERE post_id NOT IN ( SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key='%s' ) AND post_id IN ( SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key='%s' ) ) GROUP BY post_id"; - $rows = $wpdb->query( $wpdb->prepare( $sql, '_billing_address_index', '_billing_first_name', '_billing_last_name', '_billing_address_index', '_billing_last_name' ) ); - $rows += $wpdb->query( $wpdb->prepare( $sql, '_shipping_address_index', '_shipping_first_name', '_shipping_last_name', '_shipping_address_index', '_shipping_last_name') ); + $rows = $wpdb->query( $wpdb->prepare( $sql, '_billing_address_index', '_billing_first_name', '_billing_last_name', '_billing_address_index', '_billing_last_name' ) ); + $rows += $wpdb->query( $wpdb->prepare( $sql, '_shipping_address_index', '_shipping_first_name', '_shipping_last_name', '_shipping_address_index', '_shipping_last_name' ) ); $message = sprintf( __( '%d indexes added', 'woocommerce' ), $rows ); - break; - case 'reset_roles' : + break; + + case 'reset_roles': // Remove then re-add caps and roles WC_Install::remove_roles(); WC_Install::create_roles(); $message = __( 'Roles successfully reset', 'woocommerce' ); - break; - case 'recount_terms' : - $product_cats = get_terms( 'product_cat', array( 'hide_empty' => false, 'fields' => 'id=>parent' ) ); + break; + + case 'recount_terms': + $product_cats = get_terms( 'product_cat', array( + 'hide_empty' => false, + 'fields' => 'id=>parent', + ) ); _wc_term_recount( $product_cats, get_taxonomy( 'product_cat' ), true, false ); - $product_tags = get_terms( 'product_tag', array( 'hide_empty' => false, 'fields' => 'id=>parent' ) ); + $product_tags = get_terms( 'product_tag', array( + 'hide_empty' => false, + 'fields' => 'id=>parent', + ) ); _wc_term_recount( $product_tags, get_taxonomy( 'product_tag' ), true, false ); $message = __( 'Terms successfully recounted', 'woocommerce' ); - break; - case 'clear_sessions' : + break; + + case 'clear_sessions': $wpdb->query( "TRUNCATE {$wpdb->prefix}woocommerce_sessions" ); $result = absint( $wpdb->query( "DELETE FROM {$wpdb->usermeta} WHERE meta_key='_woocommerce_persistent_cart_" . get_current_blog_id() . "';" ) ); wp_cache_flush(); $message = sprintf( __( 'Deleted all active sessions, and %d saved carts.', 'woocommerce' ), absint( $result ) ); - break; - case 'install_pages' : + break; + + case 'install_pages': WC_Install::create_pages(); $message = __( 'All missing WooCommerce pages successfully installed', 'woocommerce' ); - break; - case 'delete_taxes' : + break; + case 'delete_taxes': $wpdb->query( "TRUNCATE TABLE {$wpdb->prefix}woocommerce_tax_rates;" ); $wpdb->query( "TRUNCATE TABLE {$wpdb->prefix}woocommerce_tax_rate_locations;" ); WC_Cache_Helper::incr_cache_prefix( 'taxes' ); $message = __( 'Tax rates successfully deleted', 'woocommerce' ); - break; - case 'reset_tracking' : + break; + + case 'reset_tracking': delete_option( 'woocommerce_allow_tracking' ); WC_Admin_Notices::add_notice( 'tracking' ); $message = __( 'Usage tracking settings successfully reset.', 'woocommerce' ); - break; - default : + break; + + default: $tools = $this->get_tools(); if ( isset( $tools[ $tool ]['callback'] ) ) { $callback = $tools[ $tool ]['callback']; - $return = call_user_func( $callback ); + $return = call_user_func( $callback ); if ( is_string( $return ) ) { $message = $return; } elseif ( false === $return ) { $callback_string = is_array( $callback ) ? get_class( $callback[0] ) . '::' . $callback[1] : $callback; - $ran = false; - $message = sprintf( __( 'There was an error calling %s', 'woocommerce' ), $callback_string ); + $ran = false; + $message = sprintf( __( 'There was an error calling %s', 'woocommerce' ), $callback_string ); } else { $message = __( 'Tool ran.', 'woocommerce' ); } @@ -462,9 +486,12 @@ class WC_REST_System_Status_Tools_Controller extends WC_REST_Controller { $ran = false; $message = __( 'There was an error calling this tool. There is no callback present.', 'woocommerce' ); } - break; + break; } - return array( 'success' => $ran, 'message' => $message ); + return array( + 'success' => $ran, + 'message' => $message, + ); } } diff --git a/phpcs.xml b/phpcs.xml index 814bc6294d5..137f56c613e 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -52,7 +52,10 @@ includes/**/abstract-*.php - tests/ + tests/* + + + tests/* tests/ diff --git a/tests/unit-tests/api/system-status.php b/tests/unit-tests/api/system-status.php index 4d9762a87d0..173a9aef410 100644 --- a/tests/unit-tests/api/system-status.php +++ b/tests/unit-tests/api/system-status.php @@ -1,6 +1,13 @@ endpoint = new WC_REST_System_Status_Controller(); - $this->user = $this->factory->user->create( array( + $this->user = $this->factory->user->create( array( 'role' => 'administrator', ) ); } @@ -47,7 +54,7 @@ class WC_Tests_REST_System_Status extends WC_REST_Unit_Test_Case { public function test_get_system_status_info_returns_root_properties() { wp_set_current_user( $this->user ); $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v2/system_status' ) ); - $data = $response->get_data(); + $data = $response->get_data(); $this->assertArrayHasKey( 'environment', $data ); $this->assertArrayHasKey( 'database', $data ); @@ -69,10 +76,10 @@ class WC_Tests_REST_System_Status extends WC_REST_Unit_Test_Case { $data = $response->get_data(); $environment = (array) $data['environment']; - // Make sure all expected data is present + // Make sure all expected data is present. $this->assertEquals( 30, count( $environment ) ); - // Test some responses to make sure they match up + // Test some responses to make sure they match up. $this->assertEquals( get_option( 'home' ), $environment['home_url'] ); $this->assertEquals( get_option( 'siteurl' ), $environment['site_url'] ); $this->assertEquals( WC()->version, $environment['version'] ); @@ -131,7 +138,10 @@ class WC_Tests_REST_System_Status extends WC_REST_Unit_Test_Case { $theme = (array) $data['theme']; $this->assertEquals( 13, count( $theme ) ); + + // phpcs:disable WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar $this->assertEquals( $active_theme->Name, $theme['name'] ); + // phpcs:enable } /** @@ -194,9 +204,9 @@ class WC_Tests_REST_System_Status extends WC_REST_Unit_Test_Case { * @since 3.0.0 */ public function test_system_status_schema() { - $request = new WP_REST_Request( 'OPTIONS', '/wc/v2/system_status' ); - $response = $this->server->dispatch( $request ); - $data = $response->get_data(); + $request = new WP_REST_Request( 'OPTIONS', '/wc/v2/system_status' ); + $response = $this->server->dispatch( $request ); + $data = $response->get_data(); $properties = $data['schema']['properties']; $this->assertEquals( 7, count( $properties ) ); $this->assertArrayHasKey( 'environment', $properties ); @@ -216,7 +226,7 @@ class WC_Tests_REST_System_Status extends WC_REST_Unit_Test_Case { public function test_get_system_tools() { wp_set_current_user( $this->user ); - $tools_controller = new WC_REST_System_Status_Tools_Controller; + $tools_controller = new WC_REST_System_Status_Tools_Controller(); $raw_tools = $tools_controller->get_tools(); $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v2/system_status/tools' ) ); @@ -259,7 +269,7 @@ class WC_Tests_REST_System_Status extends WC_REST_Unit_Test_Case { public function test_get_system_tool() { wp_set_current_user( $this->user ); - $tools_controller = new WC_REST_System_Status_Tools_Controller; + $tools_controller = new WC_REST_System_Status_Tools_Controller(); $raw_tools = $tools_controller->get_tools(); $raw_tool = $raw_tools['recount_terms']; @@ -293,7 +303,7 @@ class WC_Tests_REST_System_Status extends WC_REST_Unit_Test_Case { public function test_execute_system_tool() { wp_set_current_user( $this->user ); - $tools_controller = new WC_REST_System_Status_Tools_Controller; + $tools_controller = new WC_REST_System_Status_Tools_Controller(); $raw_tools = $tools_controller->get_tools(); $raw_tool = $raw_tools['recount_terms']; @@ -305,6 +315,7 @@ class WC_Tests_REST_System_Status extends WC_REST_Unit_Test_Case { $this->assertEquals( 'Recount terms', $data['action'] ); $this->assertEquals( 'This tool will recount product terms - useful when changing your settings in a way which hides products from the catalog.', $data['description'] ); $this->assertTrue( $data['success'] ); + $this->assertEquals( 1, did_action( 'woocommerce_rest_insert_system_status_tool' ) ); $response = $this->server->dispatch( new WP_REST_Request( 'POST', '/wc/v2/system_status/tools/not_a_real_tool' ) ); $this->assertEquals( 404, $response->get_status() ); @@ -327,10 +338,11 @@ class WC_Tests_REST_System_Status extends WC_REST_Unit_Test_Case { * @since 3.0.0 */ public function test_system_status_tool_schema() { - $request = new WP_REST_Request( 'OPTIONS', '/wc/v2/system_status/tools' ); - $response = $this->server->dispatch( $request ); - $data = $response->get_data(); + $request = new WP_REST_Request( 'OPTIONS', '/wc/v2/system_status/tools' ); + $response = $this->server->dispatch( $request ); + $data = $response->get_data(); $properties = $data['schema']['properties']; + $this->assertEquals( 6, count( $properties ) ); $this->assertArrayHasKey( 'id', $properties ); $this->assertArrayHasKey( 'name', $properties );