diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php index cfe3f6dbc8..2d6c47a125 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php @@ -380,7 +380,7 @@ class WP_REST_Terms_Controller extends WP_REST_Controller { $prepared_term = $this->prepare_item_for_database( $request ); - $term = wp_insert_term( $prepared_term->name, $this->taxonomy, $prepared_term ); + $term = wp_insert_term( addslashes( $prepared_term->name ), $this->taxonomy, wp_slash( (array) $prepared_term ) ); if ( is_wp_error( $term ) ) { /* * If we're going to inform the client that the term already exists, @@ -491,7 +491,7 @@ class WP_REST_Terms_Controller extends WP_REST_Controller { // Only update the term if we haz something to update. if ( ! empty( $prepared_term ) ) { - $update = wp_update_term( $term->term_id, $term->taxonomy, (array) $prepared_term ); + $update = wp_update_term( $term->term_id, $term->taxonomy, wp_slash( (array) $prepared_term ) ); if ( is_wp_error( $update ) ) { return $update; @@ -821,9 +821,6 @@ class WP_REST_Terms_Controller extends WP_REST_Controller { 'description' => __( 'HTML description of the resource.' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'wp_filter_post_kses', - ), ), 'link' => array( 'description' => __( 'URL to the resource.' ), diff --git a/tests/phpunit/tests/rest-api/rest-tags-controller.php b/tests/phpunit/tests/rest-api/rest-tags-controller.php index df2c030d49..aa5d654526 100644 --- a/tests/phpunit/tests/rest-api/rest-tags-controller.php +++ b/tests/phpunit/tests/rest-api/rest-tags-controller.php @@ -10,16 +10,28 @@ * @group restapi */ class WP_Test_REST_Tags_Controller extends WP_Test_REST_Controller_Testcase { + protected static $superadmin; protected static $administrator; + protected static $editor; protected static $subscriber; public static function wpSetUpBeforeClass( $factory ) { + self::$superadmin = $factory->user->create( array( + 'role' => 'administrator', + 'user_login' => 'superadmin', + ) ); self::$administrator = $factory->user->create( array( 'role' => 'administrator', ) ); + self::$editor = $factory->user->create( array( + 'role' => 'editor', + ) ); self::$subscriber = $factory->user->create( array( 'role' => 'subscriber', ) ); + if ( is_multisite() ) { + update_site_option( 'site_admins', array( 'superadmin' ) ); + } } public static function wpTearDownAfterClass() { @@ -617,6 +629,103 @@ class WP_Test_REST_Tags_Controller extends WP_Test_REST_Controller_Testcase { $this->assertErrorResponse( 'rest_taxonomy_not_hierarchical', $response, 400 ); } + public function verify_tag_roundtrip( $input = array(), $expected_output = array() ) { + // Create the tag + $request = new WP_REST_Request( 'POST', '/wp/v2/tags' ); + foreach ( $input as $name => $value ) { + $request->set_param( $name, $value ); + } + $response = $this->server->dispatch( $request ); + $this->assertEquals( 201, $response->get_status() ); + $actual_output = $response->get_data(); + + // Compare expected API output to actual API output + $this->assertEquals( $expected_output['name'], $actual_output['name'] ); + $this->assertEquals( $expected_output['description'], $actual_output['description'] ); + + // Compare expected API output to WP internal values + $tag = get_term_by( 'id', $actual_output['id'], 'post_tag' ); + $this->assertEquals( $expected_output['name'], $tag->name ); + $this->assertEquals( $expected_output['description'], $tag->description ); + + // Update the tag + $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/tags/%d', $actual_output['id'] ) ); + foreach ( $input as $name => $value ) { + $request->set_param( $name, $value ); + } + $response = $this->server->dispatch( $request ); + $this->assertEquals( 200, $response->get_status() ); + $actual_output = $response->get_data(); + + // Compare expected API output to actual API output + $this->assertEquals( $expected_output['name'], $actual_output['name'] ); + $this->assertEquals( $expected_output['description'], $actual_output['description'] ); + + // Compare expected API output to WP internal values + $tag = get_term_by( 'id', $actual_output['id'], 'post_tag' ); + $this->assertEquals( $expected_output['name'], $tag->name ); + $this->assertEquals( $expected_output['description'], $tag->description ); + } + + public function test_tag_roundtrip_as_editor() { + wp_set_current_user( self::$editor ); + $this->assertEquals( ! is_multisite(), current_user_can( 'unfiltered_html' ) ); + $this->verify_tag_roundtrip( array( + 'name' => '\o/ ¯\_(ツ)_/¯', + 'description' => '\o/ ¯\_(ツ)_/¯', + ), array( + 'name' => '\o/ ¯\_(ツ)_/¯', + 'description' => '\o/ ¯\_(ツ)_/¯', + ) ); + } + + public function test_tag_roundtrip_as_editor_html() { + wp_set_current_user( self::$editor ); + if ( is_multisite() ) { + $this->assertFalse( current_user_can( 'unfiltered_html' ) ); + $this->verify_tag_roundtrip( array( + 'name' => '
div
strong ', + 'description' => '
div
strong ', + ), array( + 'name' => 'div strong', + 'description' => 'div strong', + ) ); + } else { + $this->assertTrue( current_user_can( 'unfiltered_html' ) ); + $this->verify_tag_roundtrip( array( + 'name' => '
div
strong ', + 'description' => '
div
strong ', + ), array( + 'name' => 'div strong', + 'description' => 'div strong oh noes', + ) ); + } + } + + public function test_tag_roundtrip_as_superadmin() { + wp_set_current_user( self::$superadmin ); + $this->assertTrue( current_user_can( 'unfiltered_html' ) ); + $this->verify_tag_roundtrip( array( + 'name' => '\\\&\\\ & &invalid; < < &lt;', + 'description' => '\\\&\\\ & &invalid; < < &lt;', + ), array( + 'name' => '\\\&\\\ & &invalid; < < &lt;', + 'description' => '\\\&\\\ & &invalid; < < &lt;', + ) ); + } + + public function test_tag_roundtrip_as_superadmin_html() { + wp_set_current_user( self::$superadmin ); + $this->assertTrue( current_user_can( 'unfiltered_html' ) ); + $this->verify_tag_roundtrip( array( + 'name' => '
div
strong ', + 'description' => '
div
strong ', + ), array( + 'name' => 'div strong', + 'description' => 'div strong oh noes', + ) ); + } + public function test_delete_item() { wp_set_current_user( self::$administrator ); $term = get_term_by( 'id', $this->factory->tag->create( array( 'name' => 'Deleted Tag' ) ), 'post_tag' );