/** * Test we can update both description and title */ public function test_update_both() { wp_set_current_user($this->editor_id); $request = new WP_REST_Request('POST', sprintf('/wp/v2/posts/%d', $this->post_id)); $request->set_body_params(array('_yoast_wpseo_title' => '1 2 3', '_yoast_wpseo_metadesc' => '4 5 6')); $response = $this->server->dispatch($request); $this->assertNotInstanceOf('WP_Error', $response); $response = rest_ensure_response($response); $this->assertEquals(200, $response->get_status()); $this->assertEquals('1 2 3', get_post_meta($this->post_id, '_yoast_wpseo_title', true)); $this->assertEquals('4 5 6', get_post_meta($this->post_id, '_yoast_wpseo_metadesc', true)); }
/** * Ensure slashes aren't touched in data */ public function test_update_meta_slashed() { wp_set_current_user($this->admin_id); $meta_id = add_comment_meta($this->approved_id, 'testkey', 'testvalue'); $request = new WP_REST_Request('POST', sprintf('/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id)); $request->set_body_params(array('key' => 'testkey', 'value' => "test slashed \\' value")); $this->server->dispatch($request); $meta = get_comment_meta($this->approved_id, 'testkey', false); $this->assertNotEmpty($meta); $this->assertCount(1, $meta); $this->assertEquals("test slashed \\' value", $meta[0]); }
/** * Test creating a Shipping Zone Method. * @since 2.7.0 */ public function test_create_method() { wp_set_current_user($this->user); $zone = $this->create_shipping_zone('Zone 1'); $request = new WP_REST_Request('POST', '/wc/v1/shipping/zones/' . $zone->get_id() . '/methods'); $request->set_body_params(array('method_id' => 'flat_rate', 'enabled' => false, 'order' => 2)); $response = $this->server->dispatch($request); $data = $response->get_data(); $this->assertFalse($data['enabled']); $this->assertEquals(2, $data['order']); $this->assertArrayHasKey('cost', $data['settings']); $this->assertEquals('0', $data['settings']['cost']['value']); }
public function test_additional_field_update_errors() { $schema = array('type' => 'integer', 'description' => 'Some integer of mine', 'enum' => array(1, 2, 3, 4), 'context' => array('view', 'edit')); register_rest_field('user', 'my_custom_int', array('schema' => $schema, 'get_callback' => array($this, 'additional_field_get_callback'), 'update_callback' => array($this, 'additional_field_update_callback'))); wp_set_current_user(1); if (is_multisite()) { $current_user = wp_get_current_user(1); update_site_option('site_admins', array($current_user->user_login)); } // Check for error on update. $request = new WP_REST_Request('POST', sprintf('/wp/v2/users/%d', self::$user)); $request->set_body_params(array('my_custom_int' => 'returnError')); $response = $this->server->dispatch($request); $this->assertErrorResponse('rest_invalid_param', $response, 400); global $wp_rest_additional_fields; $wp_rest_additional_fields = array(); }
/** * Test batch managing products. */ public function test_products_batch() { wp_set_current_user($this->user); $product = WC_Helper_Product::create_simple_product(); $product_2 = WC_Helper_Product::create_simple_product(); $request = new WP_REST_Request('POST', '/wc/v1/products/batch'); $request->set_body_params(array('update' => array(array('id' => $product->get_id(), 'description' => 'Updated description.')), 'delete' => array($product_2->get_id()), 'create' => array(array('sku' => 'DUMMY SKU BATCH TEST 1', 'regular_price' => '10', 'name' => 'Test Batch Create 1', 'type' => 'external', 'button_text' => 'Test Button'), array('sku' => 'DUMMY SKU BATCH TEST 2', 'regular_price' => '20', 'name' => 'Test Batch Create 2', 'type' => 'simple')))); $response = $this->server->dispatch($request); $data = $response->get_data(); $this->assertContains('Updated description.', $data['update'][0]['description']); $this->assertEquals('DUMMY SKU BATCH TEST 1', $data['create'][0]['sku']); $this->assertEquals('DUMMY SKU BATCH TEST 2', $data['create'][1]['sku']); $this->assertEquals('Test Button', $data['create'][0]['button_text']); $this->assertEquals('external', $data['create'][0]['type']); $this->assertEquals('simple', $data['create'][1]['type']); $this->assertEquals($product_2->get_id(), $data['delete'][0]['id']); $request = new WP_REST_Request('GET', '/wc/v1/products'); $response = $this->server->dispatch($request); $data = $response->get_data(); $this->assertEquals(3, count($data)); $product->delete(true); $product_2->delete(true); }
public function test_delete_value_custom_name() { add_post_meta(self::$post_id, 'test_custom_name', 'janet'); $current = get_post_meta(self::$post_id, 'test_custom_name', true); $this->assertEquals('janet', $current); $this->grant_write_permission(); $data = array('meta' => array('new_name' => null)); $request = new WP_REST_Request('POST', sprintf('/wp/v2/posts/%d', self::$post_id)); $request->set_body_params($data); $response = $this->server->dispatch($request); $this->assertEquals(200, $response->get_status()); $meta = get_post_meta(self::$post_id, 'test_custom_name', false); $this->assertEmpty($meta); }
public function test_get_additional_field_registration() { $schema = array('type' => 'integer', 'description' => 'Some integer of mine', 'enum' => array(1, 2, 3, 4), 'context' => array('view', 'edit')); register_api_field('user', 'my_custom_int', array('schema' => $schema, 'get_callback' => array($this, 'additional_field_get_callback'), 'update_callback' => array($this, 'additional_field_update_callback'))); $request = new WP_REST_Request('OPTIONS', '/wp/v2/users'); $response = $this->server->dispatch($request); $data = $response->get_data(); $this->assertArrayHasKey('my_custom_int', $data['schema']['properties']); $this->assertEquals($schema, $data['schema']['properties']['my_custom_int']); wp_set_current_user(1); if (is_multisite()) { $current_user = wp_get_current_user(1); update_site_option('site_admins', array($current_user->user_login)); } $request = new WP_REST_Request('GET', '/wp/v2/users/1'); $response = $this->server->dispatch($request); $this->assertArrayHasKey('my_custom_int', $response->data); $request = new WP_REST_Request('POST', '/wp/v2/users/1'); $request->set_body_params(array('my_custom_int' => 123)); $response = $this->server->dispatch($request); $this->assertEquals(123, get_user_meta(1, 'my_custom_int', true)); $request = new WP_REST_Request('POST', '/wp/v2/users'); $request->set_body_params(array('my_custom_int' => 123, 'email' => '*****@*****.**', 'username' => 'abc123', 'password' => 'hello')); $response = $this->server->dispatch($request); $this->assertEquals(123, $response->data['my_custom_int']); global $wp_rest_additional_fields; $wp_rest_additional_fields = array(); }
/** * Ensure slashes aren't touched in data */ public function test_update_meta_slashed() { $post_id = $this->factory->post->create(); $meta_id = add_post_meta($post_id, 'testkey', 'testvalue'); $data = array('key' => 'testkey', 'value' => "test slashed \\' value"); $request = new WP_REST_Request('POST', sprintf('/wp/v2/posts/%d/meta/%d', $post_id, $meta_id)); $request->set_body_params($data); $response = $this->server->dispatch($request); $this->assertNotInstanceOf('WP_Error', $response); $meta = get_post_meta($post_id, 'testkey', false); $this->assertNotEmpty($meta); $this->assertCount(1, $meta); $this->assertEquals("test slashed \\' value", $meta[0]); }
/** * Do a REST Request * * @param string $method * */ private function do_request($method, $route, $assoc_args) { if ('internal' === $this->scope) { $request = new \WP_REST_Request($method, $route); if (in_array($method, array('POST', 'PUT'))) { $request->set_body_params($assoc_args); } else { foreach ($assoc_args as $key => $value) { $request->set_param($key, $value); } } $response = rest_do_request($request); if ($error = $response->as_error()) { WP_CLI::error($error); } return array($response->get_status(), $response->get_data(), $response->get_headers()); } else { if ('http' === $this->scope) { $response = Utils\http_request($method, rtrim($this->api_url, '/') . $route, $assoc_args); $body = json_decode($response->body, true); if ($response->status_code >= 400) { if (!empty($body['message'])) { WP_CLI::error($body['message'] . ' ' . json_encode(array('status' => $response->status_code))); } else { switch ($response->status_code) { case 404: WP_CLI::error("No {$this->name} found."); break; default: WP_CLI::error('Could not complete request.'); break; } } } return array($response->status_code, json_decode($response->body, true), $response->headers); } } WP_CLI::error('Invalid scope for REST command.'); }
/** * Test batch managing product reviews. */ public function test_orders_batch() { wp_set_current_user($this->user); $order1 = WC_Helper_Order::create_order(); $order2 = WC_Helper_Order::create_order(); $order3 = WC_Helper_Order::create_order(); $request = new WP_REST_Request('POST', '/wc/v1/orders/batch'); $request->set_body_params(array('update' => array(array('id' => $order1->get_id(), 'payment_method' => 'updated')), 'delete' => array($order2->get_id(), $order3->get_id()))); $response = $this->server->dispatch($request); $data = $response->get_data(); $this->assertEquals('updated', $data['update'][0]['payment_method']); $this->assertEquals($order2->get_id(), $data['delete'][0]['id']); $this->assertEquals($order3->get_id(), $data['delete'][1]['id']); $request = new WP_REST_Request('GET', '/wc/v1/orders'); $response = $this->server->dispatch($request); $data = $response->get_data(); $this->assertEquals(1, count($data)); wp_delete_post($order1->get_id(), true); wp_delete_post($order2->get_id(), true); wp_delete_post($order3->get_id(), true); }
/** * Test validation of image_width. * * @since 2.7.0 */ public function test_validation_image_width() { wp_set_current_user($this->user); $response = $this->server->dispatch(new WP_REST_Request('GET', sprintf('/wc/v1/settings/%s/%s', 'products', 'shop_thumbnail_image_size'))); $setting = $response->get_data(); $this->assertEquals(array('width' => 180, 'height' => 180, 'crop' => true), $setting['value']); // test bogus $request = new WP_REST_Request('PUT', sprintf('/wc/v1/settings/%s/%s', 'products', 'shop_thumbnail_image_size')); $request->set_body_params(array('value' => array('width' => 400, 'height' => 200, 'crop' => 'asdasdasd'))); $response = $this->server->dispatch($request); $setting = $response->get_data(); $this->assertEquals(array('width' => 400, 'height' => 200, 'crop' => true), $setting['value']); $request = new WP_REST_Request('PUT', sprintf('/wc/v1/settings/%s/%s', 'products', 'shop_thumbnail_image_size')); $request->set_body_params(array('value' => array('width' => 200, 'height' => 100, 'crop' => false))); $response = $this->server->dispatch($request); $setting = $response->get_data(); $this->assertEquals(array('width' => 200, 'height' => 100, 'crop' => false), $setting['value']); }
/** * Bulk create, update and delete items. * * @since 2.7.0 * @param WP_REST_Request $request Full details about the request. * @return array Of WP_Error or WP_REST_Response. */ public function batch_items($request) { // Get the request params. $items = array_filter($request->get_params()); /* * Since our batch settings update is group-specific and matches based on the route, * we inject the URL parameters (containing group) into the batch items */ if (!empty($items['update'])) { $to_update = array(); foreach ($items['update'] as $item) { $to_update[] = array_merge($request->get_url_params(), $item); } $request = new WP_REST_Request($request->get_method()); $request->set_body_params(array('update' => $to_update)); } return parent::batch_items($request); }
/** * Do a REST Request * * @param string $method * */ private function do_request($method, $route, $assoc_args) { if (!defined('REST_REQUEST')) { define('REST_REQUEST', true); } $request = new WP_REST_Request($method, $route); if (in_array($method, array('POST', 'PUT'))) { $request->set_body_params($assoc_args); } else { foreach ($assoc_args as $key => $value) { $request->set_param($key, $value); } } if (defined('SAVEQUERIES') && SAVEQUERIES) { $original_queries = is_array($GLOBALS['wpdb']->queries) ? array_keys($GLOBALS['wpdb']->queries) : array(); } $response = rest_do_request($request); if (defined('SAVEQUERIES') && SAVEQUERIES) { $performed_queries = array(); foreach ((array) $GLOBALS['wpdb']->queries as $key => $query) { if (in_array($key, $original_queries)) { continue; } $performed_queries[] = $query; } usort($performed_queries, function ($a, $b) { if ($a[1] === $b[1]) { return 0; } return $a[1] > $b[1] ? -1 : 1; }); $query_count = count($performed_queries); $query_total_time = 0; foreach ($performed_queries as $query) { $query_total_time += $query[1]; } $slow_query_message = ''; if ($performed_queries && 'wc' === WP_CLI::get_config('debug')) { $slow_query_message .= '. Ordered by slowness, the queries are:' . PHP_EOL; foreach ($performed_queries as $i => $query) { $i++; $bits = explode(', ', $query[2]); $backtrace = implode(', ', array_slice($bits, 13)); $seconds = round($query[1], 6); $slow_query_message .= <<<EOT {$i}: - {$seconds} seconds - {$backtrace} - {$query[0]} EOT; $slow_query_message .= PHP_EOL; } } elseif ('wc' !== WP_CLI::get_config('debug')) { $slow_query_message = '. Use --debug=wc to see all queries.'; } $query_total_time = round($query_total_time, 6); WP_CLI::debug("wc command executed {$query_count} queries in {$query_total_time} seconds{$slow_query_message}", 'wc'); } if ($error = $response->as_error()) { WP_CLI::error($error); } return array($response->get_status(), $response->get_data(), $response->get_headers()); }
/** * Test batch operations on coupons. * @since 2.7.0 */ public function test_batch_coupon() { wp_set_current_user($this->user); $coupon_1 = WC_Helper_Coupon::create_coupon('dummycoupon-1'); $coupon_2 = WC_Helper_Coupon::create_coupon('dummycoupon-2'); $coupon_3 = WC_Helper_Coupon::create_coupon('dummycoupon-3'); $coupon_4 = WC_Helper_Coupon::create_coupon('dummycoupon-4'); $request = new WP_REST_Request('POST', '/wc/v1/coupons/batch'); $request->set_body_params(array('update' => array(array('id' => $coupon_1->get_id(), 'amount' => '5.15')), 'delete' => array($coupon_2->get_id(), $coupon_3->get_id()), 'create' => array(array('code' => 'new-coupon', 'amount' => '11.00')))); $response = $this->server->dispatch($request); $data = $response->get_data(); $this->assertEquals('5.15', $data['update'][0]['amount']); $this->assertEquals('11.00', $data['create'][0]['amount']); $this->assertEquals('new-coupon', $data['create'][0]['code']); $this->assertEquals($coupon_2->get_id(), $data['delete'][0]['id']); $this->assertEquals($coupon_3->get_id(), $data['delete'][1]['id']); $request = new WP_REST_Request('GET', '/wc/v1/coupons'); $response = $this->server->dispatch($request); $data = $response->get_data(); $this->assertEquals(3, count($data)); }
/** * Ensure slashes aren't touched in data */ public function test_update_meta_slashed() { $meta_id = add_term_meta($this->category_id, 'testkey', 'testvalue'); $request = new WP_REST_Request('POST', sprintf('/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id)); $request->set_body_params(array('key' => 'testkey', 'value' => "test slashed \\' value")); $this->server->dispatch($request); $meta = get_term_meta($this->category_id, 'testkey', false); $this->assertNotEmpty($meta); $this->assertCount(1, $meta); $this->assertEquals("test slashed \\' value", $meta[0]); }
public function test_additional_field_update_errors() { $schema = array('type' => 'integer', 'description' => 'Some integer of mine', 'enum' => array(1, 2, 3, 4), 'context' => array('view', 'edit')); register_rest_field('tag', 'my_custom_int', array('schema' => $schema, 'get_callback' => array($this, 'additional_field_get_callback'), 'update_callback' => array($this, 'additional_field_update_callback'))); wp_set_current_user(self::$administrator); $tag_id = $this->factory->tag->create(); // Check for error on update. $request = new WP_REST_Request('POST', sprintf('/wp/v2/tags/%d', $tag_id)); $request->set_body_params(array('my_custom_int' => 'returnError')); $response = $this->server->dispatch($request); $this->assertErrorResponse('rest_invalid_param', $response, 400); global $wp_rest_additional_fields; $wp_rest_additional_fields = array(); }
/** * Ensure slashes aren't touched in data */ public function test_update_meta_slashed() { wp_set_current_user($this->user); $this->allow_user_to_manage_multisite(); $meta_id = add_user_meta($this->user, 'testkey', 'testvalue'); $data = array('key' => 'testkey', 'value' => "test slashed \\' value"); $request = new WP_REST_Request('POST', sprintf('/wp/v2/users/%d/meta/%d', $this->user, $meta_id)); $request->set_body_params($data); $this->server->dispatch($request); $meta = get_user_meta($this->user, 'testkey', false); $this->assertNotEmpty($meta); $this->assertCount(1, $meta); $this->assertEquals("test slashed \\' value", $meta[0]); }
/** * Test customer batch endpoint. * * @since 2.7.0 */ public function test_batch_customer() { wp_set_current_user(1); $customer_1 = WC_Helper_Customer::create_customer('test_batch_customer', 'test123', '*****@*****.**'); $customer_2 = WC_Helper_Customer::create_customer('test_batch_customer2', 'test123', '*****@*****.**'); $customer_3 = WC_Helper_Customer::create_customer('test_batch_customer3', 'test123', '*****@*****.**'); $customer_4 = WC_Helper_Customer::create_customer('test_batch_customer4', 'test123', '*****@*****.**'); $request = new WP_REST_Request('POST', '/wc/v1/customers/batch'); $request->set_body_params(array('update' => array(array('id' => $customer_1->get_id(), 'last_name' => 'McTest')), 'delete' => array($customer_2->get_id(), $customer_3->get_id()), 'create' => array(array('username' => 'newuser', 'password' => 'test123', 'email' => '*****@*****.**')))); $response = $this->server->dispatch($request); $data = $response->get_data(); $this->assertEquals('McTest', $data['update'][0]['last_name']); $this->assertEquals('newuser', $data['create'][0]['username']); $this->assertEmpty($data['create'][0]['last_name']); $this->assertEquals($customer_2->get_id(), $data['delete'][0]['id']); $this->assertEquals($customer_3->get_id(), $data['delete'][1]['id']); $request = new WP_REST_Request('GET', '/wc/v1/customers'); $response = $this->server->dispatch($request); $data = $response->get_data(); $this->assertEquals(3, count($data)); }
/** * Test batch managing product variations. */ public function test_product_variations_batch() { wp_set_current_user($this->user); $product = WC_Helper_Product::create_variation_product(); $children = $product->get_children(); $request = new WP_REST_Request('POST', '/wc/v1/products/' . $product->get_id() . '/variations/batch'); $request->set_body_params(array('update' => array(array('id' => $children[0], 'description' => 'Updated description.', 'image' => array(array('position' => 0, 'src' => 'https://cldup.com/Dr1Bczxq4q.png', 'alt' => 'test upload image')))), 'delete' => array(array('id' => $children[1])), 'create' => array(array('sku' => 'DUMMY SKU VARIABLE MEDIUM', 'regular_price' => '12', 'description' => 'A medium size.', 'attributes' => array(array('name' => 'pa_size', 'option' => 'medium')))))); $response = $this->server->dispatch($request); $data = $response->get_data(); $this->assertContains('Updated description.', $data['update'][0]['description']); $this->assertEquals('DUMMY SKU VARIABLE MEDIUM', $data['create'][0]['sku']); $this->assertEquals('medium', $data['create'][0]['attributes'][0]['option']); $this->assertEquals($children[1], $data['delete'][0]['id']); $request = new WP_REST_Request('GET', '/wc/v1/products/' . $product->get_id() . '/variations'); $response = $this->server->dispatch($request); $data = $response->get_data(); $this->assertEquals(2, count($data)); $product->delete(true); }
/** * Tests our classic setting registration to make sure settings added for WP-Admin are available over the API. * * @since 2.7.0 */ public function test_classic_settings() { wp_set_current_user($this->user); // Make sure the group is properly registered $response = $this->server->dispatch(new WP_REST_Request('GET', '/wc/v1/settings/products')); $data = $response->get_data(); $this->assertTrue(is_array($data)); $this->assertContains(array('id' => 'woocommerce_downloads_require_login', 'label' => 'Access Restriction', 'description' => 'Downloads require login', 'type' => 'checkbox', 'default' => 'no', 'tip' => 'This setting does not apply to guest purchases.', 'value' => 'no', '_links' => array('self' => array(array('href' => rest_url('/wc/v1/settings/products/woocommerce_downloads_require_login'))), 'collection' => array(array('href' => rest_url('/wc/v1/settings/products'))))), $data); // test get single $response = $this->server->dispatch(new WP_REST_Request('GET', '/wc/v1/settings/products/woocommerce_dimension_unit')); $data = $response->get_data(); $this->assertEquals('cm', $data['default']); // test update $request = new WP_REST_Request('PUT', sprintf('/wc/v1/settings/%s/%s', 'products', 'woocommerce_dimension_unit')); $request->set_body_params(array('value' => 'yd')); $response = $this->server->dispatch($request); $data = $response->get_data(); $this->assertEquals('yd', $data['value']); $this->assertEquals('yd', get_option('woocommerce_dimension_unit')); }
/** * Test updating a payment gateway with an invalid id. * * @since 2.7.0 */ public function test_update_payment_gateway_invalid_id() { wp_set_current_user($this->user); $request = new WP_REST_Request('POST', '/wc/v1/payment_gateways/totally_fake_method'); $request->set_body_params(array('enabled' => true)); $response = $this->server->dispatch($request); $this->assertEquals(404, $response->get_status()); }
/** * Handle serving an API request * * Matches the current server URI to a route and runs the first matching * callback then outputs a JSON representation of the returned value. * * @uses WP_REST_Server::dispatch() */ public function serve_request($path = null) { $content_type = isset($_GET['_jsonp']) ? 'application/javascript' : 'application/json'; $this->send_header('Content-Type', $content_type . '; charset=' . get_option('blog_charset')); // Mitigate possible JSONP Flash attacks // http://miki.it/blog/2014/7/8/abusing-jsonp-with-rosetta-flash/ $this->send_header('X-Content-Type-Options', 'nosniff'); // Proper filter for turning off the JSON API. It is on by default. $enabled = apply_filters('rest_enabled', true); $jsonp_enabled = apply_filters('rest_jsonp_enabled', true); if (!$enabled) { echo $this->json_error('rest_disabled', __('The REST API is disabled on this site.'), 404); return false; } if (isset($_GET['_jsonp'])) { if (!$jsonp_enabled) { echo $this->json_error('rest_callback_disabled', __('JSONP support is disabled on this site.'), 400); return false; } // Check for invalid characters (only alphanumeric allowed) if (!is_string($_GET['_jsonp']) || preg_match('/[^\\w\\.]/', $_GET['_jsonp'])) { echo $this->json_error('rest_callback_invalid', __('The JSONP callback function is invalid.'), 400); return false; } } if (empty($path)) { if (isset($_SERVER['PATH_INFO'])) { $path = $_SERVER['PATH_INFO']; } else { $path = '/'; } } $request = new WP_REST_Request($_SERVER['REQUEST_METHOD'], $path); $request->set_query_params($_GET); $request->set_body_params($_POST); $request->set_file_params($_FILES); $request->set_headers($this->get_headers($_SERVER)); $request->set_body($this->get_raw_data()); /** * HTTP method override for clients that can't use PUT/PATCH/DELETE. First, we check * $_GET['_method']. If that is not set, we check for the HTTP_X_HTTP_METHOD_OVERRIDE * header. */ if (isset($_GET['_method'])) { $request->set_method($_GET['_method']); } elseif (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) { $request->set_method($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']); } $result = $this->check_authentication(); if (!is_wp_error($result)) { $result = $this->dispatch($request); } // Normalize to either WP_Error or WP_REST_Response... $result = rest_ensure_response($result); // ...then convert WP_Error across if (is_wp_error($result)) { $result = $this->error_to_response($result); } /** * Allow modifying the response before returning * * @param WP_HTTP_ResponseInterface $result Result to send to the client. Usually a WP_REST_Response * @param WP_REST_Server $this Server instance * @param WP_REST_Request $request Request used to generate the response */ $result = apply_filters('rest_post_dispatch', rest_ensure_response($result), $this, $request); // Wrap the response in an envelope if asked for if (isset($_GET['_envelope'])) { $result = $this->envelope_response($result, isset($_GET['_embed'])); } // Send extra data from response objects $headers = $result->get_headers(); $this->send_headers($headers); $code = $result->get_status(); $this->set_status($code); /** * Allow sending the request manually * * If `$served` is true, the result will not be sent to the client. * * This is a filter rather than an action, since this is designed to be * re-entrant if needed. * * @param bool $served Whether the request has already been served * @param WP_HTTP_ResponseInterface $result Result to send to the client. Usually a WP_REST_Response * @param WP_REST_Request $request Request used to generate the response * @param WP_REST_Server $this Server instance */ $served = apply_filters('rest_pre_serve_request', false, $result, $request, $this); if (!$served) { if ('HEAD' === $request->get_method()) { return; } // Embed links inside the request $result = $this->response_to_data($result, isset($_GET['_embed'])); $result = wp_json_encode($result); $json_error_message = $this->get_json_last_error(); if ($json_error_message) { $json_error_obj = new WP_Error('rest_encode_error', $json_error_message, array('status' => 500)); $result = $this->error_to_response($json_error_obj); $result = wp_json_encode($result->data[0]); } if (isset($_GET['_jsonp'])) { // Prepend '/**/' to mitigate possible JSONP Flash attacks // http://miki.it/blog/2014/7/8/abusing-jsonp-with-rosetta-flash/ echo '/**/' . $_GET['_jsonp'] . '(' . $result . ')'; } else { echo $result; } } }
/** * Bulk create, update and delete items. * * @param WP_REST_Request $request Full details about the request. * @return array Of WP_Error or WP_REST_Response. */ public function batch_items($request) { /** @var WP_REST_Server $wp_rest_server */ global $wp_rest_server; // Get the request params. $items = array_filter($request->get_params()); $response = array(); // Check batch limit. $limit = $this->check_batch_limit($items); if (is_wp_error($limit)) { return $limit; } if (!empty($items['create'])) { foreach ($items['create'] as $item) { $_item = new WP_REST_Request('POST'); // Default parameters. $defaults = array(); $schema = $this->get_public_item_schema(); foreach ($schema['properties'] as $arg => $options) { if (isset($options['default'])) { $defaults[$arg] = $options['default']; } } $_item->set_default_params($defaults); // Set request parameters. $_item->set_body_params($item); $_response = $this->create_item($_item); if (is_wp_error($_response)) { $response['create'][] = array('id' => 0, 'error' => array('code' => $_response->get_error_code(), 'message' => $_response->get_error_message(), 'data' => $_response->get_error_data())); } else { $response['create'][] = $wp_rest_server->response_to_data($_response, ''); } } } if (!empty($items['update'])) { foreach ($items['update'] as $item) { $_item = new WP_REST_Request('PUT'); $_item->set_body_params($item); $_response = $this->update_item($_item); if (is_wp_error($_response)) { $response['update'][] = array('id' => $item['id'], 'error' => array('code' => $_response->get_error_code(), 'message' => $_response->get_error_message(), 'data' => $_response->get_error_data())); } else { $response['update'][] = $wp_rest_server->response_to_data($_response, ''); } } } if (!empty($items['delete'])) { foreach ($items['delete'] as $id) { $_item = new WP_REST_Request('DELETE'); $_item->set_query_params(array('id' => $id, 'force' => true)); $_response = $this->delete_item($_item); if (is_wp_error($_response)) { $response['delete'][] = array('id' => $id, 'error' => array('code' => $_response->get_error_code(), 'message' => $_response->get_error_message(), 'data' => $_response->get_error_data())); } else { $response['delete'][] = $wp_rest_server->response_to_data($_response, ''); } } } return $response; }
/** * Test batch managing product reviews. */ public function test_product_reviews_batch() { wp_set_current_user($this->user); $product = WC_Helper_Product::create_simple_product(); $review_1_id = WC_Helper_Product::create_product_review($product->get_id()); $review_2_id = WC_Helper_Product::create_product_review($product->get_id()); $review_3_id = WC_Helper_Product::create_product_review($product->get_id()); $review_4_id = WC_Helper_Product::create_product_review($product->get_id()); $request = new WP_REST_Request('POST', '/wc/v1/products/' . $product->get_id() . '/reviews/batch'); $request->set_body_params(array('update' => array(array('id' => $review_1_id, 'review' => 'Updated review.')), 'delete' => array(array('id' => $review_2_id), array('id' => $review_3_id)), 'create' => array(array('review' => 'New review.', 'name' => 'Justin', 'email' => '*****@*****.**')))); $response = $this->server->dispatch($request); $data = $response->get_data(); $this->assertEquals('Updated review.', $data['update'][0]['review']); $this->assertEquals('New review.', $data['create'][0]['review']); $this->assertEquals($review_2_id, $data['delete'][0]['id']); $this->assertEquals($review_3_id, $data['delete'][1]['id']); $request = new WP_REST_Request('GET', '/wc/v1/products/' . $product->get_id() . '/reviews'); $response = $this->server->dispatch($request); $data = $response->get_data(); $this->assertEquals(3, count($data)); }
/** * Bulk create, update and delete items. * * @since 2.7.0 * @param WP_REST_Request $request Full details about the request. * @return array Of WP_Error or WP_REST_Response. */ public function batch_items($request) { $items = array_filter($request->get_params()); $params = $request->get_url_params(); $product_id = $params['product_id']; $body_params = array(); foreach (array('update', 'create', 'delete') as $batch_type) { if (!empty($items[$batch_type])) { $injected_items = array(); foreach ($items[$batch_type] as $item) { $injected_items[] = array_merge(array('product_id' => $product_id), $item); } $body_params[$batch_type] = $injected_items; } } $request = new WP_REST_Request($request->get_method()); $request->set_body_params($body_params); return parent::batch_items($request); }
public function test_update_page_parent_zero() { $page_id1 = $this->factory->post->create(array('post_type' => 'page')); $page_id2 = $this->factory->post->create(array('post_type' => 'page', 'post_parent' => $page_id1)); wp_set_current_user(self::$editor_id); $request = new WP_REST_Request('PUT', sprintf('/wp/v2/pages/%d', $page_id2)); $request->set_body_params(array('parent' => 0)); $response = $this->server->dispatch($request); $new_data = $response->get_data(); $this->assertEquals(0, $new_data['parent']); }
/** * Handles serving an API request. * * Matches the current server URI to a route and runs the first matching * callback then outputs a JSON representation of the returned value. * * @since 4.4.0 * @access public * * @see WP_REST_Server::dispatch() * * @param string $path Optional. The request route. If not set, `$_SERVER['PATH_INFO']` will be used. * Default null. * @return false|null Null if not served and a HEAD request, false otherwise. */ public function serve_request($path = null) { $content_type = isset($_GET['_jsonp']) ? 'application/javascript' : 'application/json'; $this->send_header('Content-Type', $content_type . '; charset=' . get_option('blog_charset')); $this->send_header('X-Robots-Tag', 'noindex'); $api_root = get_rest_url(); if (!empty($api_root)) { $this->send_header('Link', '<' . esc_url_raw($api_root) . '>; rel="https://api.w.org/"'); } /* * Mitigate possible JSONP Flash attacks. * * https://miki.it/blog/2014/7/8/abusing-jsonp-with-rosetta-flash/ */ $this->send_header('X-Content-Type-Options', 'nosniff'); $this->send_header('Access-Control-Expose-Headers', 'X-WP-Total, X-WP-TotalPages'); $this->send_header('Access-Control-Allow-Headers', 'Authorization'); /** * Send nocache headers on authenticated requests. * * @since 4.4.0 * * @param bool $rest_send_nocache_headers Whether to send no-cache headers. */ $send_no_cache_headers = apply_filters('rest_send_nocache_headers', is_user_logged_in()); if ($send_no_cache_headers) { foreach (wp_get_nocache_headers() as $header => $header_value) { $this->send_header($header, $header_value); } } /** * Filters whether the REST API is enabled. * * @since 4.4.0 * * @param bool $rest_enabled Whether the REST API is enabled. Default true. */ $enabled = apply_filters('rest_enabled', true); /** * Filters whether jsonp is enabled. * * @since 4.4.0 * * @param bool $jsonp_enabled Whether jsonp is enabled. Default true. */ $jsonp_enabled = apply_filters('rest_jsonp_enabled', true); $jsonp_callback = null; if (!$enabled) { echo $this->json_error('rest_disabled', __('The REST API is disabled on this site.'), 404); return false; } if (isset($_GET['_jsonp'])) { if (!$jsonp_enabled) { echo $this->json_error('rest_callback_disabled', __('JSONP support is disabled on this site.'), 400); return false; } $jsonp_callback = $_GET['_jsonp']; if (!wp_check_jsonp_callback($jsonp_callback)) { echo $this->json_error('rest_callback_invalid', __('The JSONP callback function is invalid.'), 400); return false; } } if (empty($path)) { if (isset($_SERVER['PATH_INFO'])) { $path = $_SERVER['PATH_INFO']; } else { $path = '/'; } } $request = new WP_REST_Request($_SERVER['REQUEST_METHOD'], $path); $request->set_query_params(wp_unslash($_GET)); $request->set_body_params(wp_unslash($_POST)); $request->set_file_params($_FILES); $request->set_headers($this->get_headers(wp_unslash($_SERVER))); $request->set_body($this->get_raw_data()); /* * HTTP method override for clients that can't use PUT/PATCH/DELETE. First, we check * $_GET['_method']. If that is not set, we check for the HTTP_X_HTTP_METHOD_OVERRIDE * header. */ if (isset($_GET['_method'])) { $request->set_method($_GET['_method']); } elseif (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) { $request->set_method($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']); } $result = $this->check_authentication(); if (!is_wp_error($result)) { $result = $this->dispatch($request); } // Normalize to either WP_Error or WP_REST_Response... $result = rest_ensure_response($result); // ...then convert WP_Error across. if (is_wp_error($result)) { $result = $this->error_to_response($result); } /** * Filters the API response. * * Allows modification of the response before returning. * * @since 4.4.0 * @since 4.5.0 Applied to embedded responses. * * @param WP_HTTP_Response $result Result to send to the client. Usually a WP_REST_Response. * @param WP_REST_Server $this Server instance. * @param WP_REST_Request $request Request used to generate the response. */ $result = apply_filters('rest_post_dispatch', rest_ensure_response($result), $this, $request); // Wrap the response in an envelope if asked for. if (isset($_GET['_envelope'])) { $result = $this->envelope_response($result, isset($_GET['_embed'])); } // Send extra data from response objects. $headers = $result->get_headers(); $this->send_headers($headers); $code = $result->get_status(); $this->set_status($code); /** * Filters whether the request has already been served. * * Allow sending the request manually - by returning true, the API result * will not be sent to the client. * * @since 4.4.0 * * @param bool $served Whether the request has already been served. * Default false. * @param WP_HTTP_Response $result Result to send to the client. Usually a WP_REST_Response. * @param WP_REST_Request $request Request used to generate the response. * @param WP_REST_Server $this Server instance. */ $served = apply_filters('rest_pre_serve_request', false, $result, $request, $this); if (!$served) { if ('HEAD' === $request->get_method()) { return null; } // Embed links inside the request. $result = $this->response_to_data($result, isset($_GET['_embed'])); $result = wp_json_encode($result); $json_error_message = $this->get_json_last_error(); if ($json_error_message) { $json_error_obj = new WP_Error('rest_encode_error', $json_error_message, array('status' => 500)); $result = $this->error_to_response($json_error_obj); $result = wp_json_encode($result->data[0]); } if ($jsonp_callback) { // Prepend '/**/' to mitigate possible JSONP Flash attacks // https://miki.it/blog/2014/7/8/abusing-jsonp-with-rosetta-flash/ echo '/**/' . $jsonp_callback . '(' . $result . ')'; } else { echo $result; } } return null; }
public function test_get_additional_field_registration() { $schema = array('type' => 'integer', 'description' => 'Some integer of mine', 'enum' => array(1, 2, 3, 4), 'context' => array('view', 'edit')); register_api_field('comment', 'my_custom_int', array('schema' => $schema, 'get_callback' => array($this, 'additional_field_get_callback'), 'update_callback' => array($this, 'additional_field_update_callback'))); $request = new WP_REST_Request('OPTIONS', '/wp/v2/comments'); $response = $this->server->dispatch($request); $data = $response->get_data(); $this->assertArrayHasKey('my_custom_int', $data['schema']['properties']); $this->assertEquals($schema, $data['schema']['properties']['my_custom_int']); $request = new WP_REST_Request('GET', '/wp/v2/comments/' . $this->approved_id); $response = $this->server->dispatch($request); $this->assertArrayHasKey('my_custom_int', $response->data); $request = new WP_REST_Request('POST', '/wp/v2/comments/' . $this->approved_id); $request->set_body_params(array('my_custom_int' => 123, 'content' => 'abc')); wp_set_current_user(1); $response = $this->server->dispatch($request); $this->assertEquals(123, get_comment_meta($this->approved_id, 'my_custom_int', true)); $request = new WP_REST_Request('POST', '/wp/v2/comments'); $request->set_body_params(array('my_custom_int' => 123, 'title' => 'hello', 'post' => $this->post_id)); $response = $this->server->dispatch($request); $this->assertEquals(123, $response->data['my_custom_int']); global $wp_rest_additional_fields; $wp_rest_additional_fields = array(); }
public function test_additional_field_update_errors() { $schema = array('type' => 'integer', 'description' => 'Some integer of mine', 'enum' => array(1, 2, 3, 4), 'context' => array('view', 'edit')); register_rest_field('attachment', 'my_custom_int', array('schema' => $schema, 'get_callback' => array($this, 'additional_field_get_callback'), 'update_callback' => array($this, 'additional_field_update_callback'))); wp_set_current_user(self::$editor_id); $attachment_id = $this->factory->attachment->create_object($this->test_file, 0, array('post_mime_type' => 'image/jpeg', 'post_excerpt' => 'A sample caption', 'post_author' => self::$editor_id)); // Check for error on update. $request = new WP_REST_Request('POST', sprintf('/wp/v2/media/%d', $attachment_id)); $request->set_body_params(array('my_custom_int' => 'returnError')); $response = $this->server->dispatch($request); $this->assertErrorResponse('rest_invalid_param', $response, 400); global $wp_rest_additional_fields; $wp_rest_additional_fields = array(); }
/** * Test Shipping Zone update endpoint with a bad zone ID. * @since 2.7.0 */ public function test_update_shipping_zone_invalid_id() { wp_set_current_user($this->user); $request = new WP_REST_Request('PUT', '/wc/v1/shipping/zones/1'); $request->set_body_params(array('name' => 'Zone Test', 'order' => 2)); $response = $this->server->dispatch($request); $this->assertEquals(404, $response->get_status()); }