Ticket #38412: 38412.4.diff
| File 38412.4.diff, 81.2 KB (added by , 10 years ago) |
|---|
-
src/wp-includes/capabilities.php
diff --git a/src/wp-includes/capabilities.php b/src/wp-includes/capabilities.php index fe87bc8..4027379 100644
a b function map_meta_cap( $cap, $user_id ) { 242 242 case 'edit_post_meta': 243 243 case 'delete_post_meta': 244 244 case 'add_post_meta': 245 $post = get_post( $args[0] ); 246 if ( ! $post ) { 245 case 'edit_comment_meta': 246 case 'delete_comment_meta': 247 case 'add_comment_meta': 248 case 'edit_term_meta': 249 case 'delete_term_meta': 250 case 'add_term_meta': 251 case 'edit_user_meta': 252 case 'delete_user_meta': 253 case 'add_user_meta': 254 list( $_, $object_type, $_ ) = explode( '_', $cap ); 255 $object_id = (int) $args[0]; 256 257 switch ( $object_type ) { 258 case 'post': 259 $post = get_post( $object_id ); 260 if ( ! $post ) { 261 break; 262 } 263 264 $sub_type = get_post_type( $post ); 265 break; 266 267 case 'comment': 268 $comment = get_comment( $object_id ); 269 if ( ! $comment ) { 270 break; 271 } 272 273 $sub_type = empty( $comment->comment_type ) ? 'comment' : $comment->comment_type; 274 break; 275 276 case 'term': 277 $term = get_term( $object_id ); 278 if ( ! $term ) { 279 break; 280 } 281 282 $sub_type = $term->taxonomy; 283 break; 284 285 case 'user': 286 $user = get_user_by( 'id', $object_id ); 287 if ( ! $user ) { 288 break; 289 } 290 291 $sub_type = 'user'; 292 break; 293 } 294 295 if ( empty( $sub_type ) ) { 247 296 $caps[] = 'do_not_allow'; 248 297 break; 249 298 } 250 299 251 $ post_type = get_post_type( $post);300 $caps = map_meta_cap( "edit_{$object_type}", $user_id, $object_id ); 252 301 253 $ caps = map_meta_cap( 'edit_post', $user_id, $post->ID );302 $meta_key = isset( $args[1] ) ? $args[1] : false; 254 303 255 $meta_key = isset( $args[ 1 ] ) ? $args[ 1 ] : false; 304 $has_filter = has_filter( "auth_{$object_type}_meta_{$meta_key}" ) || has_filter( "auth_{$object_type}_{$sub_type}_meta_{$meta_key}" ); 305 if ( $meta_key && $has_filter ) { 306 /** This filter is documented in wp-includes/meta.php */ 307 $allowed = apply_filters( "auth_{$object_type}_meta_{$meta_key}", false, $meta_key, $object_id, $user_id, $cap, $caps ); 256 308 257 if ( $meta_key && ( has_filter( "auth_post_meta_{$meta_key}" ) || has_filter( "auth_post_{$post_type}_meta_{$meta_key}" ) ) ) { 258 /** 259 * Filters whether the user is allowed to add post meta to a post. 260 * 261 * The dynamic portion of the hook name, `$meta_key`, refers to the 262 * meta key passed to map_meta_cap(). 263 * 264 * @since 3.3.0 265 * 266 * @param bool $allowed Whether the user can add the post meta. Default false. 267 * @param string $meta_key The meta key. 268 * @param int $post_id Post ID. 269 * @param int $user_id User ID. 270 * @param string $cap Capability name. 271 * @param array $caps User capabilities. 272 */ 273 $allowed = apply_filters( "auth_post_meta_{$meta_key}", false, $meta_key, $post->ID, $user_id, $cap, $caps ); 309 /** This filter is documented in wp-includes/meta.php */ 310 $allowed = apply_filters( "auth_{$object_type}_{$sub_type}_meta_{$meta_key}", $allowed, $meta_key, $object_id, $user_id, $cap, $caps ); 274 311 275 /** 276 * Filters whether the user is allowed to add post meta to a post of a given type. 277 * 278 * The dynamic portions of the hook name, `$meta_key` and `$post_type`, 279 * refer to the meta key passed to map_meta_cap() and the post type, respectively. 280 * 281 * @since 4.6.0 282 * 283 * @param bool $allowed Whether the user can add the post meta. Default false. 284 * @param string $meta_key The meta key. 285 * @param int $post_id Post ID. 286 * @param int $user_id User ID. 287 * @param string $cap Capability name. 288 * @param array $caps User capabilities. 289 */ 290 $allowed = apply_filters( "auth_post_{$post_type}_meta_{$meta_key}", $allowed, $meta_key, $post->ID, $user_id, $cap, $caps ); 291 292 if ( ! $allowed ) 312 if ( ! $allowed ) { 293 313 $caps[] = $cap; 294 } elseif ( $meta_key && is_protected_meta( $meta_key, 'post' ) ) { 314 } 315 } elseif ( $meta_key && is_protected_meta( $meta_key, $object_type ) ) { 295 316 $caps[] = $cap; 296 317 } 297 318 break; -
src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php
diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php index e6f7920..255667e 100644
a b class WP_REST_Comments_Controller extends WP_REST_Controller { 631 631 if ( ! $change ) { 632 632 return new WP_Error( 'rest_comment_failed_edit', __( 'Updating comment status failed.' ), array( 'status' => 500 ) ); 633 633 } 634 } else {634 } elseif ( ! empty( $prepared_args ) ) { 635 635 if ( is_wp_error( $prepared_args ) ) { 636 636 return $prepared_args; 637 637 } -
src/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php
diff --git a/src/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php b/src/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php index 2c765ca..e48a307 100644
a b abstract class WP_REST_Meta_Fields { 122 122 */ 123 123 public function update_value( $request, $object_id ) { 124 124 $fields = $this->get_registered_fields(); 125 126 125 foreach ( $fields as $name => $args ) { 127 126 if ( ! array_key_exists( $name, $request ) ) { 128 127 continue; … … abstract class WP_REST_Meta_Fields { 159 158 * @return bool|WP_Error True if meta field is deleted, WP_Error otherwise. 160 159 */ 161 160 protected function delete_meta_value( $object_id, $name ) { 162 if ( ! current_user_can( 'delete_post_meta', $object_id, $name ) ) { 161 $meta_type = $this->get_meta_type(); 162 if ( ! current_user_can( "delete_{$meta_type}_meta", $object_id, $name ) ) { 163 163 return new WP_Error( 164 164 'rest_cannot_delete', 165 165 sprintf( __( 'You do not have permission to edit the %s custom field.' ), $name ), … … abstract class WP_REST_Meta_Fields { 167 167 ); 168 168 } 169 169 170 if ( ! delete_metadata( $ this->get_meta_type(), $object_id, wp_slash( $name ) ) ) {170 if ( ! delete_metadata( $meta_type, $object_id, wp_slash( $name ) ) ) { 171 171 return new WP_Error( 172 172 'rest_meta_database_error', 173 173 __( 'Could not delete meta value from database.' ), … … abstract class WP_REST_Meta_Fields { 192 192 * @return bool|WP_Error True if meta fields are updated, WP_Error otherwise. 193 193 */ 194 194 protected function update_multi_meta_value( $object_id, $name, $values ) { 195 if ( ! current_user_can( 'edit_post_meta', $object_id, $name ) ) { 195 $meta_type = $this->get_meta_type(); 196 if ( ! current_user_can( "edit_{$meta_type}_meta", $object_id, $name ) ) { 196 197 return new WP_Error( 197 198 'rest_cannot_update', 198 199 sprintf( __( 'You do not have permission to edit the %s custom field.' ), $name ), … … abstract class WP_REST_Meta_Fields { 200 201 ); 201 202 } 202 203 203 $current = get_metadata( $ this->get_meta_type(), $object_id, $name, false );204 $current = get_metadata( $meta_type, $object_id, $name, false ); 204 205 205 206 $to_remove = $current; 206 207 $to_add = $values; … … abstract class WP_REST_Meta_Fields { 227 228 $to_remove = array_unique( $to_remove ); 228 229 229 230 foreach ( $to_remove as $value ) { 230 if ( ! delete_metadata( $ this->get_meta_type(), $object_id, wp_slash( $name ), wp_slash( $value ) ) ) {231 if ( ! delete_metadata( $meta_type, $object_id, wp_slash( $name ), wp_slash( $value ) ) ) { 231 232 return new WP_Error( 232 233 'rest_meta_database_error', 233 234 __( 'Could not update meta value in database.' ), … … abstract class WP_REST_Meta_Fields { 237 238 } 238 239 239 240 foreach ( $to_add as $value ) { 240 if ( ! add_metadata( $ this->get_meta_type(), $object_id, wp_slash( $name ), wp_slash( $value ) ) ) {241 if ( ! add_metadata( $meta_type, $object_id, wp_slash( $name ), wp_slash( $value ) ) ) { 241 242 return new WP_Error( 242 243 'rest_meta_database_error', 243 244 __( 'Could not update meta value in database.' ), … … abstract class WP_REST_Meta_Fields { 261 262 * @return bool|WP_Error True if the meta field was updated, WP_Error otherwise. 262 263 */ 263 264 protected function update_meta_value( $object_id, $name, $value ) { 264 if ( ! current_user_can( 'edit_post_meta', $object_id, $name ) ) { 265 $meta_type = $this->get_meta_type(); 266 if ( ! current_user_can( "edit_{$meta_type}_meta", $object_id, $name ) ) { 265 267 return new WP_Error( 266 268 'rest_cannot_update', 267 269 sprintf( __( 'You do not have permission to edit the %s custom field.' ), $name ), … … abstract class WP_REST_Meta_Fields { 269 271 ); 270 272 } 271 273 272 $meta_type = $this->get_meta_type();273 274 $meta_key = wp_slash( $name ); 274 275 $meta_value = wp_slash( $value ); 275 276 -
new file tests/phpunit/tests/comment/capabilities.php
diff --git a/tests/phpunit/tests/comment/capabilities.php b/tests/phpunit/tests/comment/capabilities.php new file mode 100644 index 0000000..7d82b18
- + 1 <?php 2 3 /** 4 * @group comment 5 * @group capabilities 6 */ 7 8 class Tests_Comment_Capabilities extends WP_UnitTestCase { 9 protected static $admin; 10 protected static $u1; 11 protected static $u2; 12 protected static $post_id; 13 protected static $comment_id; 14 15 public static function wpSetUpBeforeClass( $factory ) { 16 self::$admin = $factory->user->create( array( 'role' => 'administrator' ) ); 17 self::$u1 = $factory->user->create( array( 'role' => 'author' ) ); 18 self::$u2 = $factory->user->create( array( 'role' => 'author' ) ); 19 20 self::$post_id = $factory->post->create( array( 'post_author' => self::$u1 ) ); 21 self::$comment_id = $factory->comment->create( array( 'comment_post_ID' => self::$post_id ) ); 22 } 23 24 public static function wpTearDownAfterClass() { 25 self::delete_user( self::$u1 ); 26 self::delete_user( self::$u2 ); 27 self::delete_user( self::$admin ); 28 29 wp_delete_post( self::$post_id, true ); 30 wp_delete_comment( self::$comment_id, true ); 31 } 32 33 public function test_no_one_can_edit_comment_meta_for_non_existent_comment() { 34 wp_set_current_user( self::$admin ); 35 $this->assertFalse( current_user_can( 'edit_comment_meta', 999999, 'foo' ) ); 36 } 37 38 public function test_user_can_edit_comment_meta() { 39 wp_set_current_user( self::$u1 ); 40 $this->assertTrue( current_user_can( 'edit_comment_meta', self::$comment_id, 'foo' ) ); 41 } 42 43 public function test_user_cannot_edit_comment_meta() { 44 wp_set_current_user( self::$u2 ); 45 $this->assertFalse( current_user_can( 'edit_comment_meta', self::$comment_id, 'foo' ) ); 46 } 47 48 public function test_no_one_can_delete_comment_meta_for_non_existent_comment() { 49 wp_set_current_user( self::$admin ); 50 $this->assertFalse( current_user_can( 'delete_comment_meta', 999999, 'foo' ) ); 51 } 52 53 public function test_user_can_delete_comment_meta() { 54 wp_set_current_user( self::$u1 ); 55 $this->assertTrue( current_user_can( 'delete_comment_meta', self::$comment_id, 'foo' ) ); 56 } 57 58 public function test_user_cannot_delete_comment_meta() { 59 wp_set_current_user( self::$u2 ); 60 $this->assertFalse( current_user_can( 'delete_comment_meta', self::$comment_id, 'foo' ) ); 61 } 62 63 public function test_no_one_can_add_comment_meta_for_non_existent_comment() { 64 wp_set_current_user( self::$admin ); 65 $this->assertFalse( current_user_can( 'add_comment_meta', 999999, 'foo' ) ); 66 } 67 68 public function test_user_can_add_comment_meta() { 69 wp_set_current_user( self::$u1 ); 70 $this->assertTrue( current_user_can( 'add_comment_meta', self::$comment_id, 'foo' ) ); 71 } 72 73 public function test_user_cannot_add_comment_meta() { 74 wp_set_current_user( self::$u2 ); 75 $this->assertFalse( current_user_can( 'add_comment_meta', self::$comment_id, 'foo' ) ); 76 } 77 } -
new file tests/phpunit/tests/post/capabilities.php
diff --git a/tests/phpunit/tests/post/capabilities.php b/tests/phpunit/tests/post/capabilities.php new file mode 100644 index 0000000..9e6503e
- + 1 <?php 2 3 /** 4 * @group post 5 * @group capabilities 6 */ 7 8 class Tests_Post_Capabilities extends WP_UnitTestCase { 9 protected static $admin; 10 protected static $u1; 11 protected static $u2; 12 protected static $post_id; 13 14 public static function wpSetUpBeforeClass( $factory ) { 15 self::$admin = $factory->user->create( array( 'role' => 'administrator' ) ); 16 self::$u1 = $factory->user->create( array( 'role' => 'author' ) ); 17 self::$u2 = $factory->user->create( array( 'role' => 'author' ) ); 18 19 self::$post_id = $factory->post->create( array( 'post_author' => self::$u1 ) ); 20 } 21 22 public static function wpTearDownAfterClass() { 23 self::delete_user( self::$u1 ); 24 self::delete_user( self::$u2 ); 25 self::delete_user( self::$admin ); 26 27 wp_delete_post( self::$post_id, true ); 28 } 29 30 public function test_no_one_can_edit_post_meta_for_non_existent_post() { 31 wp_set_current_user( self::$admin ); 32 $this->assertFalse( current_user_can( 'edit_post_meta', 999999, 'foo' ) ); 33 } 34 35 public function test_user_can_edit_post_meta() { 36 wp_set_current_user( self::$u1 ); 37 $this->assertTrue( current_user_can( 'edit_post_meta', self::$post_id, 'foo' ) ); 38 } 39 40 public function test_user_cannot_edit_post_meta() { 41 wp_set_current_user( self::$u2 ); 42 $this->assertFalse( current_user_can( 'edit_post_meta', self::$post_id, 'foo' ) ); 43 } 44 45 public function test_no_one_can_delete_post_meta_for_non_existent_post() { 46 wp_set_current_user( self::$admin ); 47 $this->assertFalse( current_user_can( 'delete_post_meta', 999999, 'foo' ) ); 48 } 49 50 public function test_user_can_delete_post_meta() { 51 wp_set_current_user( self::$u1 ); 52 $this->assertTrue( current_user_can( 'delete_post_meta', self::$post_id, 'foo' ) ); 53 } 54 55 public function test_user_cannot_delete_post_meta() { 56 wp_set_current_user( self::$u2 ); 57 $this->assertFalse( current_user_can( 'delete_post_meta', self::$post_id, 'foo' ) ); 58 } 59 60 public function test_no_one_can_add_post_meta_for_non_existent_post() { 61 wp_set_current_user( self::$admin ); 62 $this->assertFalse( current_user_can( 'add_post_meta', 999999, 'foo' ) ); 63 } 64 65 public function test_user_can_add_post_meta() { 66 wp_set_current_user( self::$u1 ); 67 $this->assertTrue( current_user_can( 'add_post_meta', self::$post_id, 'foo' ) ); 68 } 69 70 public function test_user_cannot_add_post_meta() { 71 wp_set_current_user( self::$u2 ); 72 $this->assertFalse( current_user_can( 'add_post_meta', self::$post_id, 'foo' ) ); 73 } 74 } -
new file tests/phpunit/tests/rest-api/rest-comment-meta-fields.php
diff --git a/tests/phpunit/tests/rest-api/rest-comment-meta-fields.php b/tests/phpunit/tests/rest-api/rest-comment-meta-fields.php new file mode 100644 index 0000000..c7ec51c
- + 1 <?php 2 /** 3 * Unit tests covering WP_REST_Posts meta functionality. 4 * 5 * @package WordPress 6 * @subpackage REST API 7 */ 8 9 /** 10 * @group restapi 11 */ 12 class WP_Test_REST_Comment_Meta_Fields extends WP_Test_REST_TestCase { 13 protected static $editor_id; 14 protected static $post_id; 15 protected static $comment_id; 16 17 public static function wpSetUpBeforeClass( $factory ) { 18 // Ensure we have write permission. 19 self::$editor_id = $factory->user->create( array( 20 'role' => 'editor', 21 ) ); 22 self::$post_id = $factory->post->create(); 23 self::$comment_id = $factory->comment->create_post_comments( self::$post_id, 1 )[0]; 24 } 25 26 public static function wpTearDownAfterClass() { 27 wp_delete_comment( self::$comment_id ); 28 wp_delete_post( self::$post_id ); 29 } 30 31 public function setUp() { 32 parent::setUp(); 33 34 register_meta( 'comment', 'test_single', array( 35 'show_in_rest' => true, 36 'single' => true, 37 )); 38 register_meta( 'comment', 'test_multi', array( 39 'show_in_rest' => true, 40 'single' => false, 41 )); 42 register_meta( 'comment', 'test_bad_auth', array( 43 'show_in_rest' => true, 44 'single' => true, 45 'auth_callback' => '__return_false', 46 )); 47 register_meta( 'comment', 'test_bad_auth_multi', array( 48 'show_in_rest' => true, 49 'single' => false, 50 'auth_callback' => '__return_false', 51 )); 52 register_meta( 'comment', 'test_no_rest', array() ); 53 register_meta( 'comment', 'test_rest_disabled', array( 54 'show_in_rest' => false, 55 )); 56 register_meta( 'comment', 'test_custom_schema', array( 57 'single' => true, 58 'type' => 'integer', 59 'show_in_rest' => array( 60 'schema' => array( 61 'type' => 'number', 62 ), 63 ), 64 )); 65 register_meta( 'comment', 'test_invalid_type', array( 66 'single' => true, 67 'type' => false, 68 'show_in_rest' => true, 69 )); 70 71 /** @var WP_REST_Server $wp_rest_server */ 72 global $wp_rest_server; 73 $this->server = $wp_rest_server = new Spy_REST_Server; 74 do_action( 'rest_api_init' ); 75 } 76 77 public function test_get_value() { 78 add_comment_meta( self::$comment_id, 'test_single', 'testvalue' ); 79 80 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 81 $response = $this->server->dispatch( $request ); 82 83 $this->assertEquals( 200, $response->get_status() ); 84 85 $data = $response->get_data(); 86 $this->assertArrayHasKey( 'meta', $data ); 87 88 $meta = (array) $data['meta']; 89 $this->assertArrayHasKey( 'test_single', $meta ); 90 $this->assertEquals( 'testvalue', $meta['test_single'] ); 91 } 92 93 /** 94 * @depends test_get_value 95 */ 96 public function test_get_multi_value() { 97 add_comment_meta( self::$comment_id, 'test_multi', 'value1' ); 98 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 99 100 $response = $this->server->dispatch( $request ); 101 $this->assertEquals( 200, $response->get_status() ); 102 103 $data = $response->get_data(); 104 $meta = (array) $data['meta']; 105 $this->assertArrayHasKey( 'test_multi', $meta ); 106 $this->assertInternalType( 'array', $meta['test_multi'] ); 107 $this->assertContains( 'value1', $meta['test_multi'] ); 108 109 // Check after an update. 110 add_comment_meta( self::$comment_id, 'test_multi', 'value2' ); 111 112 $response = $this->server->dispatch( $request ); 113 $this->assertEquals( 200, $response->get_status() ); 114 $data = $response->get_data(); 115 $meta = (array) $data['meta']; 116 $this->assertContains( 'value1', $meta['test_multi'] ); 117 $this->assertContains( 'value2', $meta['test_multi'] ); 118 } 119 120 /** 121 * @depends test_get_value 122 */ 123 public function test_get_unregistered() { 124 add_comment_meta( self::$comment_id, 'test_unregistered', 'value1' ); 125 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 126 127 $response = $this->server->dispatch( $request ); 128 $this->assertEquals( 200, $response->get_status() ); 129 130 $data = $response->get_data(); 131 $meta = (array) $data['meta']; 132 $this->assertArrayNotHasKey( 'test_unregistered', $meta ); 133 } 134 135 /** 136 * @depends test_get_value 137 */ 138 public function test_get_registered_no_api_access() { 139 add_comment_meta( self::$comment_id, 'test_no_rest', 'for_the_wicked' ); 140 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 141 142 $response = $this->server->dispatch( $request ); 143 $this->assertEquals( 200, $response->get_status() ); 144 145 $data = $response->get_data(); 146 $meta = (array) $data['meta']; 147 $this->assertArrayNotHasKey( 'test_no_rest', $meta ); 148 } 149 150 /** 151 * @depends test_get_value 152 */ 153 public function test_get_registered_api_disabled() { 154 add_comment_meta( self::$comment_id, 'test_rest_disabled', 'sleepless_nights' ); 155 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 156 157 $response = $this->server->dispatch( $request ); 158 $this->assertEquals( 200, $response->get_status() ); 159 160 $data = $response->get_data(); 161 $meta = (array) $data['meta']; 162 $this->assertArrayNotHasKey( 'test_rest_disabled', $meta ); 163 } 164 165 public function test_get_value_types() { 166 register_meta( 'comment', 'test_string', array( 167 'show_in_rest' => true, 168 'single' => true, 169 'type' => 'string', 170 )); 171 register_meta( 'comment', 'test_number', array( 172 'show_in_rest' => true, 173 'single' => true, 174 'type' => 'number', 175 )); 176 register_meta( 'comment', 'test_bool', array( 177 'show_in_rest' => true, 178 'single' => true, 179 'type' => 'boolean', 180 )); 181 182 /** @var WP_REST_Server $wp_rest_server */ 183 global $wp_rest_server; 184 $this->server = $wp_rest_server = new Spy_REST_Server; 185 do_action( 'rest_api_init' ); 186 187 add_comment_meta( self::$comment_id, 'test_string', 42 ); 188 add_comment_meta( self::$comment_id, 'test_number', '42' ); 189 add_comment_meta( self::$comment_id, 'test_bool', 1 ); 190 191 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 192 $response = $this->server->dispatch( $request ); 193 $this->assertEquals( 200, $response->get_status() ); 194 195 $data = $response->get_data(); 196 $meta = (array) $data['meta']; 197 198 $this->assertArrayHasKey( 'test_string', $meta ); 199 $this->assertInternalType( 'string', $meta['test_string'] ); 200 $this->assertSame( '42', $meta['test_string'] ); 201 202 $this->assertArrayHasKey( 'test_number', $meta ); 203 $this->assertInternalType( 'float', $meta['test_number'] ); 204 $this->assertSame( 42.0, $meta['test_number'] ); 205 206 $this->assertArrayHasKey( 'test_bool', $meta ); 207 $this->assertInternalType( 'boolean', $meta['test_bool'] ); 208 $this->assertSame( true, $meta['test_bool'] ); 209 } 210 211 /** 212 * @depends test_get_value 213 */ 214 public function test_set_value() { 215 // Ensure no data exists currently. 216 $values = get_comment_meta( self::$comment_id, 'test_single', false ); 217 $this->assertEmpty( $values ); 218 219 wp_set_current_user( self::$editor_id ); 220 221 $data = array( 222 'meta' => array( 223 'test_single' => 'test_value', 224 ), 225 ); 226 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 227 $request->set_body_params( $data ); 228 229 $response = $this->server->dispatch( $request ); 230 $this->assertEquals( 200, $response->get_status() ); 231 232 $meta = get_comment_meta( self::$comment_id, 'test_single', false ); 233 $this->assertNotEmpty( $meta ); 234 $this->assertCount( 1, $meta ); 235 $this->assertEquals( 'test_value', $meta[0] ); 236 237 $data = $response->get_data(); 238 $meta = (array) $data['meta']; 239 $this->assertArrayHasKey( 'test_single', $meta ); 240 $this->assertEquals( 'test_value', $meta['test_single'] ); 241 } 242 243 /** 244 * @depends test_get_value 245 */ 246 public function test_set_duplicate_single_value() { 247 // Start with an existing metakey and value. 248 $values = update_comment_meta( self::$comment_id, 'test_single', 'test_value' ); 249 $this->assertEquals( 'test_value', get_comment_meta( self::$comment_id, 'test_single', true ) ); 250 251 wp_set_current_user( self::$editor_id ); 252 253 $data = array( 254 'meta' => array( 255 'test_single' => 'test_value', 256 ), 257 ); 258 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 259 $request->set_body_params( $data ); 260 261 $response = $this->server->dispatch( $request ); 262 $this->assertEquals( 200, $response->get_status() ); 263 264 $meta = get_comment_meta( self::$comment_id, 'test_single', true ); 265 $this->assertNotEmpty( $meta ); 266 $this->assertEquals( 'test_value', $meta ); 267 268 $data = $response->get_data(); 269 $meta = (array) $data['meta']; 270 $this->assertArrayHasKey( 'test_single', $meta ); 271 $this->assertEquals( 'test_value', $meta['test_single'] ); 272 } 273 274 /** 275 * @depends test_set_value 276 */ 277 public function test_set_value_unauthenticated() { 278 $data = array( 279 'meta' => array( 280 'test_single' => 'test_value', 281 ), 282 ); 283 284 wp_set_current_user( 0 ); 285 286 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 287 $request->set_body_params( $data ); 288 289 $response = $this->server->dispatch( $request ); 290 $this->assertErrorResponse( 'rest_cannot_edit', $response, 401 ); 291 292 // Check that the value wasn't actually updated. 293 $this->assertEmpty( get_comment_meta( self::$comment_id, 'test_single', false ) ); 294 } 295 296 /** 297 * @depends test_set_value 298 */ 299 public function test_set_value_blocked() { 300 $data = array( 301 'meta' => array( 302 'test_bad_auth' => 'test_value', 303 ), 304 ); 305 306 wp_set_current_user( self::$editor_id ); 307 308 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 309 $request->set_body_params( $data ); 310 311 $response = $this->server->dispatch( $request ); 312 $this->assertErrorResponse( 'rest_cannot_update', $response, 403 ); 313 $this->assertEmpty( get_comment_meta( self::$comment_id, 'test_bad_auth', false ) ); 314 } 315 316 /** 317 * @depends test_set_value 318 */ 319 public function test_set_value_db_error() { 320 $data = array( 321 'meta' => array( 322 'test_single' => 'test_value', 323 ), 324 ); 325 326 wp_set_current_user( self::$editor_id ); 327 328 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 329 $request->set_body_params( $data ); 330 331 /** 332 * Disable showing error as the below is going to intentionally 333 * trigger a DB error. 334 */ 335 global $wpdb; 336 $wpdb->suppress_errors = true; 337 add_filter( 'query', array( $this, 'error_insert_query' ) ); 338 339 $response = $this->server->dispatch( $request ); 340 remove_filter( 'query', array( $this, 'error_insert_query' ) ); 341 $wpdb->show_errors = true; 342 } 343 344 public function test_set_value_multiple() { 345 // Ensure no data exists currently. 346 $values = get_comment_meta( self::$comment_id, 'test_multi', false ); 347 $this->assertEmpty( $values ); 348 349 wp_set_current_user( self::$editor_id ); 350 351 $data = array( 352 'meta' => array( 353 'test_multi' => array( 'val1' ), 354 ), 355 ); 356 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 357 $request->set_body_params( $data ); 358 359 $response = $this->server->dispatch( $request ); 360 $this->assertEquals( 200, $response->get_status() ); 361 362 $meta = get_comment_meta( self::$comment_id, 'test_multi', false ); 363 $this->assertNotEmpty( $meta ); 364 $this->assertCount( 1, $meta ); 365 $this->assertEquals( 'val1', $meta[0] ); 366 367 // Add another value. 368 $data = array( 369 'meta' => array( 370 'test_multi' => array( 'val1', 'val2' ), 371 ), 372 ); 373 $request->set_body_params( $data ); 374 375 $response = $this->server->dispatch( $request ); 376 $this->assertEquals( 200, $response->get_status() ); 377 378 $meta = get_comment_meta( self::$comment_id, 'test_multi', false ); 379 $this->assertNotEmpty( $meta ); 380 $this->assertCount( 2, $meta ); 381 $this->assertContains( 'val1', $meta ); 382 $this->assertContains( 'val2', $meta ); 383 } 384 385 /** 386 * Test removing only one item with duplicate items. 387 */ 388 public function test_set_value_remove_one() { 389 add_comment_meta( self::$comment_id, 'test_multi', 'c' ); 390 add_comment_meta( self::$comment_id, 'test_multi', 'n' ); 391 add_comment_meta( self::$comment_id, 'test_multi', 'n' ); 392 393 wp_set_current_user( self::$editor_id ); 394 395 $data = array( 396 'meta' => array( 397 'test_multi' => array( 'c', 'n' ), 398 ), 399 ); 400 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 401 $request->set_body_params( $data ); 402 403 $response = $this->server->dispatch( $request ); 404 $this->assertEquals( 200, $response->get_status() ); 405 406 $meta = get_comment_meta( self::$comment_id, 'test_multi', false ); 407 $this->assertNotEmpty( $meta ); 408 $this->assertCount( 2, $meta ); 409 $this->assertContains( 'c', $meta ); 410 $this->assertContains( 'n', $meta ); 411 } 412 413 /** 414 * @depends test_set_value_multiple 415 */ 416 public function test_set_value_multiple_unauthenticated() { 417 // Ensure no data exists currently. 418 $values = get_comment_meta( self::$comment_id, 'test_multi', false ); 419 $this->assertEmpty( $values ); 420 421 wp_set_current_user( 0 ); 422 423 $data = array( 424 'meta' => array( 425 'test_multi' => array( 'val1' ), 426 ), 427 ); 428 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 429 $request->set_body_params( $data ); 430 431 $response = $this->server->dispatch( $request ); 432 $this->assertErrorResponse( 'rest_cannot_edit', $response, 401 ); 433 434 $meta = get_comment_meta( self::$comment_id, 'test_multi', false ); 435 $this->assertEmpty( $meta ); 436 } 437 438 /** 439 * @depends test_set_value_multiple 440 */ 441 public function test_set_value_multiple_blocked() { 442 $data = array( 443 'meta' => array( 444 'test_bad_auth_multi' => array( 'test_value' ), 445 ), 446 ); 447 448 wp_set_current_user( self::$editor_id ); 449 450 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 451 $request->set_body_params( $data ); 452 453 $response = $this->server->dispatch( $request ); 454 $this->assertErrorResponse( 'rest_cannot_update', $response, 403 ); 455 $this->assertEmpty( get_comment_meta( self::$comment_id, 'test_bad_auth_multi', false ) ); 456 } 457 458 public function test_add_multi_value_db_error() { 459 // Ensure no data exists currently. 460 $values = get_comment_meta( self::$comment_id, 'test_multi', false ); 461 $this->assertEmpty( $values ); 462 463 wp_set_current_user( self::$editor_id ); 464 465 $data = array( 466 'meta' => array( 467 'test_multi' => array( 'val1' ), 468 ), 469 ); 470 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 471 $request->set_body_params( $data ); 472 473 /** 474 * Disable showing error as the below is going to intentionally 475 * trigger a DB error. 476 */ 477 global $wpdb; 478 $wpdb->suppress_errors = true; 479 add_filter( 'query', array( $this, 'error_insert_query' ) ); 480 481 $response = $this->server->dispatch( $request ); 482 remove_filter( 'query', array( $this, 'error_insert_query' ) ); 483 $wpdb->show_errors = true; 484 485 $this->assertErrorResponse( 'rest_meta_database_error', $response, 500 ); 486 } 487 488 public function test_remove_multi_value_db_error() { 489 add_comment_meta( self::$comment_id, 'test_multi', 'val1' ); 490 $values = get_comment_meta( self::$comment_id, 'test_multi', false ); 491 $this->assertEquals( array( 'val1' ), $values ); 492 493 wp_set_current_user( self::$editor_id ); 494 495 $data = array( 496 'meta' => array( 497 'test_multi' => array(), 498 ), 499 ); 500 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 501 $request->set_body_params( $data ); 502 503 /** 504 * Disable showing error as the below is going to intentionally 505 * trigger a DB error. 506 */ 507 global $wpdb; 508 $wpdb->suppress_errors = true; 509 add_filter( 'query', array( $this, 'error_delete_query' ) ); 510 511 $response = $this->server->dispatch( $request ); 512 remove_filter( 'query', array( $this, 'error_delete_query' ) ); 513 $wpdb->show_errors = true; 514 515 $this->assertErrorResponse( 'rest_meta_database_error', $response, 500 ); 516 } 517 518 public function test_delete_value() { 519 add_comment_meta( self::$comment_id, 'test_single', 'val1' ); 520 $current = get_comment_meta( self::$comment_id, 'test_single', true ); 521 $this->assertEquals( 'val1', $current ); 522 523 wp_set_current_user( self::$editor_id ); 524 525 $data = array( 526 'meta' => array( 527 'test_single' => null, 528 ), 529 ); 530 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 531 $request->set_body_params( $data ); 532 533 $response = $this->server->dispatch( $request ); 534 $this->assertEquals( 200, $response->get_status() ); 535 536 $meta = get_comment_meta( self::$comment_id, 'test_single', false ); 537 $this->assertEmpty( $meta ); 538 } 539 540 /** 541 * @depends test_delete_value 542 */ 543 public function test_delete_value_blocked() { 544 add_comment_meta( self::$comment_id, 'test_bad_auth', 'val1' ); 545 $current = get_comment_meta( self::$comment_id, 'test_bad_auth', true ); 546 $this->assertEquals( 'val1', $current ); 547 548 wp_set_current_user( self::$editor_id ); 549 550 $data = array( 551 'meta' => array( 552 'test_bad_auth' => null, 553 ), 554 ); 555 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 556 $request->set_body_params( $data ); 557 558 $response = $this->server->dispatch( $request ); 559 $this->assertErrorResponse( 'rest_cannot_delete', $response, 403 ); 560 561 $meta = get_comment_meta( self::$comment_id, 'test_bad_auth', true ); 562 $this->assertEquals( 'val1', $meta ); 563 } 564 565 /** 566 * @depends test_delete_value 567 */ 568 public function test_delete_value_db_error() { 569 add_comment_meta( self::$comment_id, 'test_single', 'val1' ); 570 $current = get_comment_meta( self::$comment_id, 'test_single', true ); 571 $this->assertEquals( 'val1', $current ); 572 573 wp_set_current_user( self::$editor_id ); 574 575 $data = array( 576 'meta' => array( 577 'test_single' => null, 578 ), 579 ); 580 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 581 $request->set_body_params( $data ); 582 /** 583 * Disable showing error as the below is going to intentionally 584 * trigger a DB error. 585 */ 586 global $wpdb; 587 $wpdb->suppress_errors = true; 588 add_filter( 'query', array( $this, 'error_delete_query' ) ); 589 590 $response = $this->server->dispatch( $request ); 591 remove_filter( 'query', array( $this, 'error_delete_query' ) ); 592 $wpdb->show_errors = true; 593 594 $this->assertErrorResponse( 'rest_meta_database_error', $response, 500 ); 595 } 596 597 public function test_get_schema() { 598 $request = new WP_REST_Request( 'OPTIONS', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 599 $response = $this->server->dispatch( $request ); 600 601 $data = $response->get_data(); 602 $schema = $data['schema']; 603 604 $this->assertArrayHasKey( 'meta', $schema['properties'] ); 605 $meta_schema = $schema['properties']['meta']['properties']; 606 607 $this->assertArrayHasKey( 'test_single', $meta_schema ); 608 $this->assertEquals( 'string', $meta_schema['test_single']['type'] ); 609 610 $this->assertArrayHasKey( 'test_multi', $meta_schema ); 611 $this->assertEquals( 'array', $meta_schema['test_multi']['type'] ); 612 $this->assertArrayHasKey( 'items', $meta_schema['test_multi'] ); 613 $this->assertEquals( 'string', $meta_schema['test_multi']['items']['type'] ); 614 615 $this->assertArrayHasKey( 'test_custom_schema', $meta_schema ); 616 $this->assertEquals( 'number', $meta_schema['test_custom_schema']['type'] ); 617 618 $this->assertArrayNotHasKey( 'test_no_rest', $meta_schema ); 619 $this->assertArrayNotHasKey( 'test_rest_disabled', $meta_schema ); 620 $this->assertArrayNotHasKey( 'test_invalid_type', $meta_schema ); 621 } 622 623 /** 624 * Internal function used to disable an insert query which 625 * will trigger a wpdb error for testing purposes. 626 */ 627 public function error_insert_query( $query ) { 628 if ( strpos( $query, 'INSERT' ) === 0 ) { 629 $query = '],'; 630 } 631 return $query; 632 } 633 634 /** 635 * Internal function used to disable an insert query which 636 * will trigger a wpdb error for testing purposes. 637 */ 638 public function error_delete_query( $query ) { 639 if ( strpos( $query, 'DELETE' ) === 0 ) { 640 $query = '],'; 641 } 642 return $query; 643 } 644 } -
new file tests/phpunit/tests/rest-api/rest-term-meta-fields.php
diff --git a/tests/phpunit/tests/rest-api/rest-term-meta-fields.php b/tests/phpunit/tests/rest-api/rest-term-meta-fields.php new file mode 100644 index 0000000..bfc3418
- + 1 <?php 2 /** 3 * Unit tests covering WP_REST_Taxonomies terms meta functionality. 4 * 5 * @package WordPress 6 * @subpackage REST API 7 */ 8 9 /** 10 * @group restapi 11 */ 12 class WP_Test_REST_Term_Meta_Fields extends WP_Test_REST_TestCase { 13 protected static $administrator_id; 14 protected static $term_id; 15 16 public static function wpSetUpBeforeClass( $factory ) { 17 self::$administrator_id = $factory->user->create( array( 18 'role' => 'administrator', 19 ) ); 20 21 register_taxonomy( 'wptests_tax', 'post', array( 'show_in_rest' => true ) ); 22 self::$term_id = $factory->term->create( array( 'taxonomy' => 'wptests_tax' ) ); 23 } 24 25 public function setUp() { 26 parent::setUp(); 27 28 register_meta( 'term', 'test_single', array( 29 'show_in_rest' => true, 30 'single' => true, 31 ) ); 32 register_meta( 'term', 'test_multi', array( 33 'show_in_rest' => true, 34 'single' => false, 35 ) ); 36 register_meta( 'term', 'test_bad_auth', array( 37 'show_in_rest' => true, 38 'single' => true, 39 'auth_callback' => '__return_false', 40 ) ); 41 register_meta( 'term', 'test_bad_auth_multi', array( 42 'show_in_rest' => true, 43 'single' => false, 44 'auth_callback' => '__return_false', 45 ) ); 46 register_meta( 'term', 'test_no_rest', array() ); 47 register_meta( 'term', 'test_rest_disabled', array( 48 'show_in_rest' => false, 49 ) ); 50 register_meta( 'term', 'test_custom_schema', array( 51 'single' => true, 52 'type' => 'integer', 53 'show_in_rest' => array( 54 'schema' => array( 55 'type' => 'number', 56 ), 57 ), 58 ) ); 59 register_meta( 'term', 'test_invalid_type', array( 60 'single' => true, 61 'type' => false, 62 'show_in_rest' => true, 63 ) ); 64 65 /** @var WP_REST_Server $wp_rest_server */ 66 global $wp_rest_server; 67 $this->server = $wp_rest_server = new Spy_REST_Server; 68 do_action( 'rest_api_init' ); 69 70 register_taxonomy( 'wptests_tax', 'post', array( 'show_in_rest' => true ) ); 71 $controller = new WP_REST_Terms_Controller( 'wptests_tax' ); 72 $controller->register_routes(); 73 } 74 75 public function test_get_value() { 76 add_term_meta( self::$term_id, 'test_single', 'testvalue' ); 77 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/wptests_tax/%d', self::$term_id ) ); 78 79 $response = $this->server->dispatch( $request ); 80 81 $this->assertEquals( 200, $response->get_status() ); 82 83 $data = $response->get_data(); 84 $this->assertArrayHasKey( 'meta', $data ); 85 86 $meta = (array) $data['meta']; 87 $this->assertArrayHasKey( 'test_single', $meta ); 88 $this->assertEquals( 'testvalue', $meta['test_single'] ); 89 } 90 91 /** 92 * @depends test_get_value 93 */ 94 public function test_get_multi_value() { 95 add_term_meta( self::$term_id, 'test_multi', 'value1' ); 96 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/wptests_tax/%d', self::$term_id ) ); 97 98 $response = $this->server->dispatch( $request ); 99 $this->assertEquals( 200, $response->get_status() ); 100 101 $data = $response->get_data(); 102 $meta = (array) $data['meta']; 103 $this->assertArrayHasKey( 'test_multi', $meta ); 104 $this->assertInternalType( 'array', $meta['test_multi'] ); 105 $this->assertContains( 'value1', $meta['test_multi'] ); 106 107 // Check after an update. 108 add_term_meta( self::$term_id, 'test_multi', 'value2' ); 109 110 $response = $this->server->dispatch( $request ); 111 $this->assertEquals( 200, $response->get_status() ); 112 $data = $response->get_data(); 113 $meta = (array) $data['meta']; 114 $this->assertContains( 'value1', $meta['test_multi'] ); 115 $this->assertContains( 'value2', $meta['test_multi'] ); 116 } 117 118 /** 119 * @depends test_get_value 120 */ 121 public function test_get_unregistered() { 122 add_term_meta( self::$term_id, 'test_unregistered', 'value1' ); 123 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/wptests_tax/%d', self::$term_id ) ); 124 125 $response = $this->server->dispatch( $request ); 126 $this->assertEquals( 200, $response->get_status() ); 127 128 $data = $response->get_data(); 129 $meta = (array) $data['meta']; 130 $this->assertArrayNotHasKey( 'test_unregistered', $meta ); 131 } 132 133 /** 134 * @depends test_get_value 135 */ 136 public function test_get_registered_no_api_access() { 137 add_term_meta( self::$term_id, 'test_no_rest', 'for_the_wicked' ); 138 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/wptests_tax/%d', self::$term_id ) ); 139 140 $response = $this->server->dispatch( $request ); 141 $this->assertEquals( 200, $response->get_status() ); 142 143 $data = $response->get_data(); 144 $meta = (array) $data['meta']; 145 $this->assertArrayNotHasKey( 'test_no_rest', $meta ); 146 } 147 148 /** 149 * @depends test_get_value 150 */ 151 public function test_get_registered_api_disabled() { 152 add_term_meta( self::$term_id, 'test_rest_disabled', 'sleepless_nights' ); 153 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/wptests_tax/%d', self::$term_id ) ); 154 155 $response = $this->server->dispatch( $request ); 156 $this->assertEquals( 200, $response->get_status() ); 157 158 $data = $response->get_data(); 159 $meta = (array) $data['meta']; 160 $this->assertArrayNotHasKey( 'test_rest_disabled', $meta ); 161 } 162 163 public function test_get_value_types() { 164 register_meta( 'term', 'test_string', array( 165 'show_in_rest' => true, 166 'single' => true, 167 'type' => 'string', 168 )); 169 register_meta( 'term', 'test_number', array( 170 'show_in_rest' => true, 171 'single' => true, 172 'type' => 'number', 173 )); 174 register_meta( 'term', 'test_bool', array( 175 'show_in_rest' => true, 176 'single' => true, 177 'type' => 'boolean', 178 )); 179 180 /** @var WP_REST_Server $wp_rest_server */ 181 global $wp_rest_server; 182 $this->server = $wp_rest_server = new Spy_REST_Server; 183 do_action( 'rest_api_init' ); 184 185 add_term_meta( self::$term_id, 'test_string', 42 ); 186 add_term_meta( self::$term_id, 'test_number', '42' ); 187 add_term_meta( self::$term_id, 'test_bool', 1 ); 188 189 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/wptests_tax/%d', self::$term_id ) ); 190 $response = $this->server->dispatch( $request ); 191 $this->assertEquals( 200, $response->get_status() ); 192 193 $data = $response->get_data(); 194 $meta = (array) $data['meta']; 195 196 $this->assertArrayHasKey( 'test_string', $meta ); 197 $this->assertInternalType( 'string', $meta['test_string'] ); 198 $this->assertSame( '42', $meta['test_string'] ); 199 200 $this->assertArrayHasKey( 'test_number', $meta ); 201 $this->assertInternalType( 'float', $meta['test_number'] ); 202 $this->assertSame( 42.0, $meta['test_number'] ); 203 204 $this->assertArrayHasKey( 'test_bool', $meta ); 205 $this->assertInternalType( 'boolean', $meta['test_bool'] ); 206 $this->assertSame( true, $meta['test_bool'] ); 207 } 208 209 /** 210 * @depends test_get_value 211 */ 212 public function test_set_value() { 213 // Ensure no data exists currently. 214 $values = get_term_meta( self::$term_id, 'test_single', false ); 215 $this->assertEmpty( $values ); 216 217 wp_set_current_user( self::$administrator_id ); 218 219 $data = array( 220 'meta' => array( 221 'test_single' => 'test_value', 222 ), 223 ); 224 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', self::$term_id ) ); 225 $request->set_body_params( $data ); 226 227 $response = $this->server->dispatch( $request ); 228 $this->assertEquals( 200, $response->get_status() ); 229 230 $meta = get_term_meta( self::$term_id, 'test_single', false ); 231 $this->assertNotEmpty( $meta ); 232 $this->assertCount( 1, $meta ); 233 $this->assertEquals( 'test_value', $meta[0] ); 234 235 $data = $response->get_data(); 236 $meta = (array) $data['meta']; 237 $this->assertArrayHasKey( 'test_single', $meta ); 238 $this->assertEquals( 'test_value', $meta['test_single'] ); 239 } 240 241 /** 242 * @depends test_get_value 243 */ 244 public function test_set_duplicate_single_value() { 245 // Start with an existing metakey and value. 246 $values = update_term_meta( self::$term_id, 'test_single', 'test_value' ); 247 $this->assertEquals( 'test_value', get_term_meta( self::$term_id, 'test_single', true ) ); 248 249 wp_set_current_user( self::$administrator_id ); 250 251 $data = array( 252 'meta' => array( 253 'test_single' => 'test_value', 254 ), 255 ); 256 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', self::$term_id ) ); 257 $request->set_body_params( $data ); 258 259 $response = $this->server->dispatch( $request ); 260 $this->assertEquals( 200, $response->get_status() ); 261 262 $meta = get_term_meta( self::$term_id, 'test_single', true ); 263 $this->assertNotEmpty( $meta ); 264 $this->assertEquals( 'test_value', $meta ); 265 266 $data = $response->get_data(); 267 $meta = (array) $data['meta']; 268 $this->assertArrayHasKey( 'test_single', $meta ); 269 $this->assertEquals( 'test_value', $meta['test_single'] ); 270 } 271 272 /** 273 * @depends test_set_value 274 */ 275 public function test_set_value_unauthenticated() { 276 $data = array( 277 'meta' => array( 278 'test_single' => 'test_value', 279 ), 280 ); 281 282 wp_set_current_user( 0 ); 283 284 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', self::$term_id ) ); 285 $request->set_body_params( $data ); 286 287 $response = $this->server->dispatch( $request ); 288 $this->assertErrorResponse( 'rest_cannot_update', $response, 401 ); 289 290 // Check that the value wasn't actually updated. 291 $this->assertEmpty( get_term_meta( self::$term_id, 'test_single', false ) ); 292 } 293 294 /** 295 * @depends test_set_value 296 */ 297 public function test_set_value_blocked() { 298 $data = array( 299 'meta' => array( 300 'test_bad_auth' => 'test_value', 301 ), 302 ); 303 304 wp_set_current_user( self::$administrator_id ); 305 306 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', self::$term_id ) ); 307 $request->set_body_params( $data ); 308 309 $response = $this->server->dispatch( $request ); 310 $this->assertErrorResponse( 'rest_cannot_update', $response, 403 ); 311 $this->assertEmpty( get_term_meta( self::$term_id, 'test_bad_auth', false ) ); 312 } 313 314 /** 315 * @depends test_set_value 316 */ 317 public function test_set_value_db_error() { 318 $data = array( 319 'meta' => array( 320 'test_single' => 'test_value', 321 ), 322 ); 323 324 wp_set_current_user( self::$administrator_id ); 325 326 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', self::$term_id ) ); 327 $request->set_body_params( $data ); 328 329 /** 330 * Disable showing error as the below is going to intentionally 331 * trigger a DB error. 332 */ 333 global $wpdb; 334 $wpdb->suppress_errors = true; 335 add_filter( 'query', array( $this, 'error_insert_query' ) ); 336 337 $response = $this->server->dispatch( $request ); 338 remove_filter( 'query', array( $this, 'error_insert_query' ) ); 339 $wpdb->show_errors = true; 340 } 341 342 public function test_set_value_multiple() { 343 // Ensure no data exists currently. 344 $values = get_term_meta( self::$term_id, 'test_multi', false ); 345 $this->assertEmpty( $values ); 346 347 wp_set_current_user( self::$administrator_id ); 348 349 $data = array( 350 'meta' => array( 351 'test_multi' => array( 'val1' ), 352 ), 353 ); 354 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', self::$term_id ) ); 355 $request->set_body_params( $data ); 356 357 $response = $this->server->dispatch( $request ); 358 $this->assertEquals( 200, $response->get_status() ); 359 360 $meta = get_term_meta( self::$term_id, 'test_multi', false ); 361 $this->assertNotEmpty( $meta ); 362 $this->assertCount( 1, $meta ); 363 $this->assertEquals( 'val1', $meta[0] ); 364 365 // Add another value. 366 $data = array( 367 'meta' => array( 368 'test_multi' => array( 'val1', 'val2' ), 369 ), 370 ); 371 $request->set_body_params( $data ); 372 373 $response = $this->server->dispatch( $request ); 374 $this->assertEquals( 200, $response->get_status() ); 375 376 $meta = get_term_meta( self::$term_id, 'test_multi', false ); 377 $this->assertNotEmpty( $meta ); 378 $this->assertCount( 2, $meta ); 379 $this->assertContains( 'val1', $meta ); 380 $this->assertContains( 'val2', $meta ); 381 } 382 383 /** 384 * Test removing only one item with duplicate items. 385 */ 386 public function test_set_value_remove_one() { 387 add_term_meta( self::$term_id, 'test_multi', 'c' ); 388 add_term_meta( self::$term_id, 'test_multi', 'n' ); 389 add_term_meta( self::$term_id, 'test_multi', 'n' ); 390 391 wp_set_current_user( self::$administrator_id ); 392 393 $data = array( 394 'meta' => array( 395 'test_multi' => array( 'c', 'n' ), 396 ), 397 ); 398 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', self::$term_id ) ); 399 $request->set_body_params( $data ); 400 401 $response = $this->server->dispatch( $request ); 402 $this->assertEquals( 200, $response->get_status() ); 403 404 $meta = get_term_meta( self::$term_id, 'test_multi', false ); 405 $this->assertNotEmpty( $meta ); 406 $this->assertCount( 2, $meta ); 407 $this->assertContains( 'c', $meta ); 408 $this->assertContains( 'n', $meta ); 409 } 410 411 /** 412 * @depends test_set_value_multiple 413 */ 414 public function test_set_value_multiple_unauthenticated() { 415 // Ensure no data exists currently. 416 $values = get_term_meta( self::$term_id, 'test_multi', false ); 417 $this->assertEmpty( $values ); 418 419 wp_set_current_user( 0 ); 420 421 $data = array( 422 'meta' => array( 423 'test_multi' => array( 'val1' ), 424 ), 425 ); 426 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', self::$term_id ) ); 427 $request->set_body_params( $data ); 428 429 $response = $this->server->dispatch( $request ); 430 $this->assertErrorResponse( 'rest_cannot_update', $response, 401 ); 431 432 $meta = get_term_meta( self::$term_id, 'test_multi', false ); 433 $this->assertEmpty( $meta ); 434 } 435 436 /** 437 * @depends test_set_value_multiple 438 */ 439 public function test_set_value_multiple_blocked() { 440 $data = array( 441 'meta' => array( 442 'test_bad_auth_multi' => array( 'test_value' ), 443 ), 444 ); 445 446 wp_set_current_user( self::$administrator_id ); 447 448 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', self::$term_id ) ); 449 $request->set_body_params( $data ); 450 451 $response = $this->server->dispatch( $request ); 452 $this->assertErrorResponse( 'rest_cannot_update', $response, 403 ); 453 $this->assertEmpty( get_term_meta( self::$term_id, 'test_bad_auth_multi', false ) ); 454 } 455 456 public function test_add_multi_value_db_error() { 457 // Ensure no data exists currently. 458 $values = get_term_meta( self::$term_id, 'test_multi', false ); 459 $this->assertEmpty( $values ); 460 461 wp_set_current_user( self::$administrator_id ); 462 463 $data = array( 464 'meta' => array( 465 'test_multi' => array( 'val1' ), 466 ), 467 ); 468 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', self::$term_id ) ); 469 $request->set_body_params( $data ); 470 471 /** 472 * Disable showing error as the below is going to intentionally 473 * trigger a DB error. 474 */ 475 global $wpdb; 476 $wpdb->suppress_errors = true; 477 add_filter( 'query', array( $this, 'error_insert_query' ) ); 478 479 $response = $this->server->dispatch( $request ); 480 remove_filter( 'query', array( $this, 'error_insert_query' ) ); 481 $wpdb->show_errors = true; 482 483 $this->assertErrorResponse( 'rest_meta_database_error', $response, 500 ); 484 } 485 486 public function test_remove_multi_value_db_error() { 487 add_term_meta( self::$term_id, 'test_multi', 'val1' ); 488 $values = get_term_meta( self::$term_id, 'test_multi', false ); 489 $this->assertEquals( array( 'val1' ), $values ); 490 491 wp_set_current_user( self::$administrator_id ); 492 493 $data = array( 494 'meta' => array( 495 'test_multi' => array(), 496 ), 497 ); 498 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', self::$term_id ) ); 499 $request->set_body_params( $data ); 500 501 /** 502 * Disable showing error as the below is going to intentionally 503 * trigger a DB error. 504 */ 505 global $wpdb; 506 $wpdb->suppress_errors = true; 507 add_filter( 'query', array( $this, 'error_delete_query' ) ); 508 509 $response = $this->server->dispatch( $request ); 510 remove_filter( 'query', array( $this, 'error_delete_query' ) ); 511 $wpdb->show_errors = true; 512 513 $this->assertErrorResponse( 'rest_meta_database_error', $response, 500 ); 514 } 515 516 public function test_delete_value() { 517 add_term_meta( self::$term_id, 'test_single', 'val1' ); 518 $current = get_term_meta( self::$term_id, 'test_single', true ); 519 $this->assertEquals( 'val1', $current ); 520 521 wp_set_current_user( self::$administrator_id ); 522 523 $data = array( 524 'meta' => array( 525 'test_single' => null, 526 ), 527 ); 528 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', self::$term_id ) ); 529 $request->set_body_params( $data ); 530 531 $response = $this->server->dispatch( $request ); 532 $this->assertEquals( 200, $response->get_status() ); 533 534 $meta = get_term_meta( self::$term_id, 'test_single', false ); 535 $this->assertEmpty( $meta ); 536 } 537 538 /** 539 * @depends test_delete_value 540 */ 541 public function test_delete_value_blocked() { 542 add_term_meta( self::$term_id, 'test_bad_auth', 'val1' ); 543 $current = get_term_meta( self::$term_id, 'test_bad_auth', true ); 544 $this->assertEquals( 'val1', $current ); 545 546 wp_set_current_user( self::$administrator_id ); 547 548 $data = array( 549 'meta' => array( 550 'test_bad_auth' => null, 551 ), 552 ); 553 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', self::$term_id ) ); 554 $request->set_body_params( $data ); 555 556 $response = $this->server->dispatch( $request ); 557 $this->assertErrorResponse( 'rest_cannot_delete', $response, 403 ); 558 559 $meta = get_term_meta( self::$term_id, 'test_bad_auth', true ); 560 $this->assertEquals( 'val1', $meta ); 561 } 562 563 /** 564 * @depends test_delete_value 565 */ 566 public function test_delete_value_db_error() { 567 add_term_meta( self::$term_id, 'test_single', 'val1' ); 568 $current = get_term_meta( self::$term_id, 'test_single', true ); 569 $this->assertEquals( 'val1', $current ); 570 571 wp_set_current_user( self::$administrator_id ); 572 573 $data = array( 574 'meta' => array( 575 'test_single' => null, 576 ), 577 ); 578 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', self::$term_id ) ); 579 $request->set_body_params( $data ); 580 /** 581 * Disable showing error as the below is going to intentionally 582 * trigger a DB error. 583 */ 584 global $wpdb; 585 $wpdb->suppress_errors = true; 586 add_filter( 'query', array( $this, 'error_delete_query' ) ); 587 588 $response = $this->server->dispatch( $request ); 589 remove_filter( 'query', array( $this, 'error_delete_query' ) ); 590 $wpdb->show_errors = true; 591 592 $this->assertErrorResponse( 'rest_meta_database_error', $response, 500 ); 593 } 594 595 public function test_get_schema() { 596 $request = new WP_REST_Request( 'OPTIONS', sprintf( '/wp/v2/wptests_tax/%d', self::$term_id ) ); 597 $response = $this->server->dispatch( $request ); 598 599 $data = $response->get_data(); 600 $schema = $data['schema']; 601 602 $this->assertArrayHasKey( 'meta', $schema['properties'] ); 603 $meta_schema = $schema['properties']['meta']['properties']; 604 605 $this->assertArrayHasKey( 'test_single', $meta_schema ); 606 $this->assertEquals( 'string', $meta_schema['test_single']['type'] ); 607 608 $this->assertArrayHasKey( 'test_multi', $meta_schema ); 609 $this->assertEquals( 'array', $meta_schema['test_multi']['type'] ); 610 $this->assertArrayHasKey( 'items', $meta_schema['test_multi'] ); 611 $this->assertEquals( 'string', $meta_schema['test_multi']['items']['type'] ); 612 613 $this->assertArrayHasKey( 'test_custom_schema', $meta_schema ); 614 $this->assertEquals( 'number', $meta_schema['test_custom_schema']['type'] ); 615 616 $this->assertArrayNotHasKey( 'test_no_rest', $meta_schema ); 617 $this->assertArrayNotHasKey( 'test_rest_disabled', $meta_schema ); 618 $this->assertArrayNotHasKey( 'test_invalid_type', $meta_schema ); 619 } 620 621 /** 622 * Internal function used to disable an insert query which 623 * will trigger a wpdb error for testing purposes. 624 */ 625 public function error_insert_query( $query ) { 626 if ( strpos( $query, 'INSERT' ) === 0 ) { 627 $query = '],'; 628 } 629 return $query; 630 } 631 632 /** 633 * Internal function used to disable an insert query which 634 * will trigger a wpdb error for testing purposes. 635 */ 636 public function error_delete_query( $query ) { 637 if ( strpos( $query, 'DELETE' ) === 0 ) { 638 $query = '],'; 639 } 640 return $query; 641 } 642 } -
new file tests/phpunit/tests/rest-api/rest-user-meta-fields.php
diff --git a/tests/phpunit/tests/rest-api/rest-user-meta-fields.php b/tests/phpunit/tests/rest-api/rest-user-meta-fields.php new file mode 100644 index 0000000..a52898b
- + 1 <?php 2 /** 3 * Unit tests covering WP_REST_Users meta functionality. 4 * 5 * @package WordPress 6 * @subpackage REST API 7 */ 8 9 /** 10 * @group restapi 11 */ 12 class WP_Test_REST_User_Meta_Fields extends WP_Test_REST_TestCase { 13 protected static $administrator_id; 14 protected static $user; 15 16 public static function wpSetUpBeforeClass( $factory ) { 17 self::$administrator_id = $factory->user->create( array( 18 'role' => 'administrator', 19 ) ); 20 self::$user = $factory->user->create( array( 21 'role' => 'author', 22 ) ); 23 } 24 25 public static function wpTearDownAfterClass() { 26 wp_delete_user( self::$administrator_id ); 27 wp_delete_user( self::$user ); 28 } 29 30 public function setUp() { 31 parent::setUp(); 32 33 // Editing users requires 'manage_network_users' on multisite. 34 if ( is_multisite() ) { 35 add_filter( 'user_has_cap', array( $this, 'grant_manage_network_users_to_admin' ), 10, 4 ); 36 } 37 38 register_meta( 'user', 'test_single', array( 39 'show_in_rest' => true, 40 'single' => true, 41 ) ); 42 register_meta( 'user', 'test_multi', array( 43 'show_in_rest' => true, 44 'single' => false, 45 ) ); 46 register_meta( 'user', 'test_bad_auth', array( 47 'show_in_rest' => true, 48 'single' => true, 49 'auth_callback' => '__return_false', 50 ) ); 51 register_meta( 'user', 'test_bad_auth_multi', array( 52 'show_in_rest' => true, 53 'single' => false, 54 'auth_callback' => '__return_false', 55 ) ); 56 register_meta( 'user', 'test_no_rest', array() ); 57 register_meta( 'user', 'test_rest_disabled', array( 58 'show_in_rest' => false, 59 ) ); 60 register_meta( 'user', 'test_custom_schema', array( 61 'single' => true, 62 'type' => 'integer', 63 'show_in_rest' => array( 64 'schema' => array( 65 'type' => 'number', 66 ), 67 ), 68 ) ); 69 register_meta( 'user', 'test_invalid_type', array( 70 'single' => true, 71 'type' => false, 72 'show_in_rest' => true, 73 ) ); 74 75 /** @var WP_REST_Server $wp_rest_server */ 76 global $wp_rest_server; 77 $this->server = $wp_rest_server = new Spy_REST_Server; 78 do_action( 'rest_api_init' ); 79 } 80 81 public function tearDown() { 82 if ( is_multisite() ) { 83 remove_filter( 'user_has_cap', array( $this, 'grant_manage_network_users_to_admin' ), 10, 4 ); 84 } 85 } 86 87 public function grant_manage_network_users_to_admin( $allcaps, $caps, $args, WP_User $user ) { 88 if ( array( 'manage_network_users' ) == $caps && self::$administrator_id === $user->ID ) { 89 $allcaps['manage_network_users'] = 1; 90 } 91 92 return $allcaps; 93 94 } 95 96 public function test_get_value() { 97 add_user_meta( self::$user, 'test_single', 'testvalue' ); 98 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$user ) ); 99 100 wp_set_current_user( self::$administrator_id ); 101 102 $response = $this->server->dispatch( $request ); 103 104 $this->assertEquals( 200, $response->get_status() ); 105 106 $data = $response->get_data(); 107 $this->assertArrayHasKey( 'meta', $data ); 108 109 $meta = (array) $data['meta']; 110 $this->assertArrayHasKey( 'test_single', $meta ); 111 $this->assertEquals( 'testvalue', $meta['test_single'] ); 112 } 113 114 /** 115 * @depends test_get_value 116 */ 117 public function test_get_multi_value() { 118 add_user_meta( self::$user, 'test_multi', 'value1' ); 119 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$user ) ); 120 121 wp_set_current_user( self::$administrator_id ); 122 123 $response = $this->server->dispatch( $request ); 124 $this->assertEquals( 200, $response->get_status() ); 125 126 $data = $response->get_data(); 127 $meta = (array) $data['meta']; 128 $this->assertArrayHasKey( 'test_multi', $meta ); 129 $this->assertInternalType( 'array', $meta['test_multi'] ); 130 $this->assertContains( 'value1', $meta['test_multi'] ); 131 132 // Check after an update. 133 add_user_meta( self::$user, 'test_multi', 'value2' ); 134 135 $response = $this->server->dispatch( $request ); 136 $this->assertEquals( 200, $response->get_status() ); 137 $data = $response->get_data(); 138 $meta = (array) $data['meta']; 139 $this->assertContains( 'value1', $meta['test_multi'] ); 140 $this->assertContains( 'value2', $meta['test_multi'] ); 141 } 142 143 /** 144 * @depends test_get_value 145 */ 146 public function test_get_unregistered() { 147 add_user_meta( self::$user, 'test_unregistered', 'value1' ); 148 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$user ) ); 149 150 wp_set_current_user( self::$administrator_id ); 151 152 $response = $this->server->dispatch( $request ); 153 $this->assertEquals( 200, $response->get_status() ); 154 155 $data = $response->get_data(); 156 $meta = (array) $data['meta']; 157 $this->assertArrayNotHasKey( 'test_unregistered', $meta ); 158 } 159 160 /** 161 * @depends test_get_value 162 */ 163 public function test_get_registered_no_api_access() { 164 add_user_meta( self::$user, 'test_no_rest', 'for_the_wicked' ); 165 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$user ) ); 166 167 wp_set_current_user( self::$administrator_id ); 168 169 $response = $this->server->dispatch( $request ); 170 $this->assertEquals( 200, $response->get_status() ); 171 172 $data = $response->get_data(); 173 $meta = (array) $data['meta']; 174 $this->assertArrayNotHasKey( 'test_no_rest', $meta ); 175 } 176 177 /** 178 * @depends test_get_value 179 */ 180 public function test_get_registered_api_disabled() { 181 add_user_meta( self::$user, 'test_rest_disabled', 'sleepless_nights' ); 182 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$user ) ); 183 184 wp_set_current_user( self::$administrator_id ); 185 186 $response = $this->server->dispatch( $request ); 187 $this->assertEquals( 200, $response->get_status() ); 188 189 $data = $response->get_data(); 190 $meta = (array) $data['meta']; 191 $this->assertArrayNotHasKey( 'test_rest_disabled', $meta ); 192 } 193 194 public function test_get_value_types() { 195 register_meta( 'user', 'test_string', array( 196 'show_in_rest' => true, 197 'single' => true, 198 'type' => 'string', 199 )); 200 register_meta( 'user', 'test_number', array( 201 'show_in_rest' => true, 202 'single' => true, 203 'type' => 'number', 204 )); 205 register_meta( 'user', 'test_bool', array( 206 'show_in_rest' => true, 207 'single' => true, 208 'type' => 'boolean', 209 )); 210 211 /** @var WP_REST_Server $wp_rest_server */ 212 global $wp_rest_server; 213 $this->server = $wp_rest_server = new Spy_REST_Server; 214 do_action( 'rest_api_init' ); 215 216 add_user_meta( self::$user, 'test_string', 42 ); 217 add_user_meta( self::$user, 'test_number', '42' ); 218 add_user_meta( self::$user, 'test_bool', 1 ); 219 220 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$user ) ); 221 222 wp_set_current_user( self::$administrator_id ); 223 224 $response = $this->server->dispatch( $request ); 225 $this->assertEquals( 200, $response->get_status() ); 226 227 $data = $response->get_data(); 228 $meta = (array) $data['meta']; 229 230 $this->assertArrayHasKey( 'test_string', $meta ); 231 $this->assertInternalType( 'string', $meta['test_string'] ); 232 $this->assertSame( '42', $meta['test_string'] ); 233 234 $this->assertArrayHasKey( 'test_number', $meta ); 235 $this->assertInternalType( 'float', $meta['test_number'] ); 236 $this->assertSame( 42.0, $meta['test_number'] ); 237 238 $this->assertArrayHasKey( 'test_bool', $meta ); 239 $this->assertInternalType( 'boolean', $meta['test_bool'] ); 240 $this->assertSame( true, $meta['test_bool'] ); 241 } 242 243 /** 244 * @depends test_get_value 245 */ 246 public function test_set_value() { 247 // Ensure no data exists currently. 248 $values = get_user_meta( self::$user, 'test_single', false ); 249 $this->assertEmpty( $values ); 250 251 wp_set_current_user( self::$administrator_id ); 252 253 $data = array( 254 'meta' => array( 255 'test_single' => 'test_value', 256 ), 257 ); 258 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 259 $request->set_body_params( $data ); 260 261 $response = $this->server->dispatch( $request ); 262 $this->assertEquals( 200, $response->get_status() ); 263 264 $meta = get_user_meta( self::$user, 'test_single', false ); 265 $this->assertNotEmpty( $meta ); 266 $this->assertCount( 1, $meta ); 267 $this->assertEquals( 'test_value', $meta[0] ); 268 269 $data = $response->get_data(); 270 $meta = (array) $data['meta']; 271 $this->assertArrayHasKey( 'test_single', $meta ); 272 $this->assertEquals( 'test_value', $meta['test_single'] ); 273 } 274 275 /** 276 * @depends test_get_value 277 */ 278 public function test_set_duplicate_single_value() { 279 // Start with an existing metakey and value. 280 $values = update_user_meta( self::$user, 'test_single', 'test_value' ); 281 $this->assertEquals( 'test_value', get_user_meta( self::$user, 'test_single', true ) ); 282 283 wp_set_current_user( self::$administrator_id ); 284 285 $data = array( 286 'meta' => array( 287 'test_single' => 'test_value', 288 ), 289 ); 290 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 291 $request->set_body_params( $data ); 292 293 $response = $this->server->dispatch( $request ); 294 $this->assertEquals( 200, $response->get_status() ); 295 296 $meta = get_user_meta( self::$user, 'test_single', true ); 297 $this->assertNotEmpty( $meta ); 298 $this->assertEquals( 'test_value', $meta ); 299 300 $data = $response->get_data(); 301 $meta = (array) $data['meta']; 302 $this->assertArrayHasKey( 'test_single', $meta ); 303 $this->assertEquals( 'test_value', $meta['test_single'] ); 304 } 305 306 /** 307 * @depends test_set_value 308 */ 309 public function test_set_value_unauthenticated() { 310 $data = array( 311 'meta' => array( 312 'test_single' => 'test_value', 313 ), 314 ); 315 316 wp_set_current_user( 0 ); 317 318 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 319 $request->set_body_params( $data ); 320 321 $response = $this->server->dispatch( $request ); 322 $this->assertErrorResponse( 'rest_cannot_edit', $response, 401 ); 323 324 // Check that the value wasn't actually updated. 325 $this->assertEmpty( get_user_meta( self::$user, 'test_single', false ) ); 326 } 327 328 /** 329 * @depends test_set_value 330 */ 331 public function test_set_value_blocked() { 332 $data = array( 333 'meta' => array( 334 'test_bad_auth' => 'test_value', 335 ), 336 ); 337 338 wp_set_current_user( self::$administrator_id ); 339 340 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 341 $request->set_body_params( $data ); 342 343 $response = $this->server->dispatch( $request ); 344 $this->assertErrorResponse( 'rest_cannot_update', $response, 403 ); 345 $this->assertEmpty( get_user_meta( self::$user, 'test_bad_auth', false ) ); 346 } 347 348 /** 349 * @depends test_set_value 350 */ 351 public function test_set_value_db_error() { 352 $data = array( 353 'meta' => array( 354 'test_single' => 'test_value', 355 ), 356 ); 357 358 wp_set_current_user( self::$administrator_id ); 359 360 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 361 $request->set_body_params( $data ); 362 363 /** 364 * Disable showing error as the below is going to intentionally 365 * trigger a DB error. 366 */ 367 global $wpdb; 368 $wpdb->suppress_errors = true; 369 add_filter( 'query', array( $this, 'error_insert_query' ) ); 370 371 $response = $this->server->dispatch( $request ); 372 remove_filter( 'query', array( $this, 'error_insert_query' ) ); 373 $wpdb->show_errors = true; 374 } 375 376 public function test_set_value_multiple() { 377 // Ensure no data exists currently. 378 $values = get_user_meta( self::$user, 'test_multi', false ); 379 $this->assertEmpty( $values ); 380 381 wp_set_current_user( self::$administrator_id ); 382 383 $data = array( 384 'meta' => array( 385 'test_multi' => array( 'val1' ), 386 ), 387 ); 388 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 389 $request->set_body_params( $data ); 390 391 $response = $this->server->dispatch( $request ); 392 $this->assertEquals( 200, $response->get_status() ); 393 394 $meta = get_user_meta( self::$user, 'test_multi', false ); 395 $this->assertNotEmpty( $meta ); 396 $this->assertCount( 1, $meta ); 397 $this->assertEquals( 'val1', $meta[0] ); 398 399 // Add another value. 400 $data = array( 401 'meta' => array( 402 'test_multi' => array( 'val1', 'val2' ), 403 ), 404 ); 405 $request->set_body_params( $data ); 406 407 $response = $this->server->dispatch( $request ); 408 $this->assertEquals( 200, $response->get_status() ); 409 410 $meta = get_user_meta( self::$user, 'test_multi', false ); 411 $this->assertNotEmpty( $meta ); 412 $this->assertCount( 2, $meta ); 413 $this->assertContains( 'val1', $meta ); 414 $this->assertContains( 'val2', $meta ); 415 } 416 417 /** 418 * Test removing only one item with duplicate items. 419 */ 420 public function test_set_value_remove_one() { 421 add_user_meta( self::$user, 'test_multi', 'c' ); 422 add_user_meta( self::$user, 'test_multi', 'n' ); 423 add_user_meta( self::$user, 'test_multi', 'n' ); 424 425 wp_set_current_user( self::$administrator_id ); 426 427 $data = array( 428 'meta' => array( 429 'test_multi' => array( 'c', 'n' ), 430 ), 431 ); 432 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 433 $request->set_body_params( $data ); 434 435 $response = $this->server->dispatch( $request ); 436 $this->assertEquals( 200, $response->get_status() ); 437 438 $meta = get_user_meta( self::$user, 'test_multi', false ); 439 $this->assertNotEmpty( $meta ); 440 $this->assertCount( 2, $meta ); 441 $this->assertContains( 'c', $meta ); 442 $this->assertContains( 'n', $meta ); 443 } 444 445 /** 446 * @depends test_set_value_multiple 447 */ 448 public function test_set_value_multiple_unauthenticated() { 449 // Ensure no data exists currently. 450 $values = get_user_meta( self::$user, 'test_multi', false ); 451 $this->assertEmpty( $values ); 452 453 wp_set_current_user( 0 ); 454 455 $data = array( 456 'meta' => array( 457 'test_multi' => array( 'val1' ), 458 ), 459 ); 460 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 461 $request->set_body_params( $data ); 462 463 $response = $this->server->dispatch( $request ); 464 $this->assertErrorResponse( 'rest_cannot_edit', $response, 401 ); 465 466 $meta = get_user_meta( self::$user, 'test_multi', false ); 467 $this->assertEmpty( $meta ); 468 } 469 470 /** 471 * @depends test_set_value_multiple 472 */ 473 public function test_set_value_multiple_blocked() { 474 $data = array( 475 'meta' => array( 476 'test_bad_auth_multi' => array( 'test_value' ), 477 ), 478 ); 479 480 wp_set_current_user( self::$administrator_id ); 481 482 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 483 $request->set_body_params( $data ); 484 485 $response = $this->server->dispatch( $request ); 486 $this->assertErrorResponse( 'rest_cannot_update', $response, 403 ); 487 $this->assertEmpty( get_user_meta( self::$user, 'test_bad_auth_multi', false ) ); 488 } 489 490 public function test_add_multi_value_db_error() { 491 // Ensure no data exists currently. 492 $values = get_user_meta( self::$user, 'test_multi', false ); 493 $this->assertEmpty( $values ); 494 495 wp_set_current_user( self::$administrator_id ); 496 497 $data = array( 498 'meta' => array( 499 'test_multi' => array( 'val1' ), 500 ), 501 ); 502 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 503 $request->set_body_params( $data ); 504 505 /** 506 * Disable showing error as the below is going to intentionally 507 * trigger a DB error. 508 */ 509 global $wpdb; 510 $wpdb->suppress_errors = true; 511 add_filter( 'query', array( $this, 'error_insert_query' ) ); 512 513 $response = $this->server->dispatch( $request ); 514 remove_filter( 'query', array( $this, 'error_insert_query' ) ); 515 $wpdb->show_errors = true; 516 517 $this->assertErrorResponse( 'rest_meta_database_error', $response, 500 ); 518 } 519 520 public function test_remove_multi_value_db_error() { 521 add_user_meta( self::$user, 'test_multi', 'val1' ); 522 $values = get_user_meta( self::$user, 'test_multi', false ); 523 $this->assertEquals( array( 'val1' ), $values ); 524 525 wp_set_current_user( self::$administrator_id ); 526 527 $data = array( 528 'meta' => array( 529 'test_multi' => array(), 530 ), 531 ); 532 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 533 $request->set_body_params( $data ); 534 535 /** 536 * Disable showing error as the below is going to intentionally 537 * trigger a DB error. 538 */ 539 global $wpdb; 540 $wpdb->suppress_errors = true; 541 add_filter( 'query', array( $this, 'error_delete_query' ) ); 542 543 $response = $this->server->dispatch( $request ); 544 remove_filter( 'query', array( $this, 'error_delete_query' ) ); 545 $wpdb->show_errors = true; 546 547 $this->assertErrorResponse( 'rest_meta_database_error', $response, 500 ); 548 } 549 550 public function test_delete_value() { 551 add_user_meta( self::$user, 'test_single', 'val1' ); 552 $current = get_user_meta( self::$user, 'test_single', true ); 553 $this->assertEquals( 'val1', $current ); 554 555 wp_set_current_user( self::$administrator_id ); 556 557 $data = array( 558 'meta' => array( 559 'test_single' => null, 560 ), 561 ); 562 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 563 $request->set_body_params( $data ); 564 565 $response = $this->server->dispatch( $request ); 566 $this->assertEquals( 200, $response->get_status() ); 567 568 $meta = get_user_meta( self::$user, 'test_single', false ); 569 $this->assertEmpty( $meta ); 570 } 571 572 /** 573 * @depends test_delete_value 574 */ 575 public function test_delete_value_blocked() { 576 add_user_meta( self::$user, 'test_bad_auth', 'val1' ); 577 $current = get_user_meta( self::$user, 'test_bad_auth', true ); 578 $this->assertEquals( 'val1', $current ); 579 580 wp_set_current_user( self::$administrator_id ); 581 582 $data = array( 583 'meta' => array( 584 'test_bad_auth' => null, 585 ), 586 ); 587 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 588 $request->set_body_params( $data ); 589 590 $response = $this->server->dispatch( $request ); 591 $this->assertErrorResponse( 'rest_cannot_delete', $response, 403 ); 592 593 $meta = get_user_meta( self::$user, 'test_bad_auth', true ); 594 $this->assertEquals( 'val1', $meta ); 595 } 596 597 /** 598 * @depends test_delete_value 599 */ 600 public function test_delete_value_db_error() { 601 add_user_meta( self::$user, 'test_single', 'val1' ); 602 $current = get_user_meta( self::$user, 'test_single', true ); 603 $this->assertEquals( 'val1', $current ); 604 605 wp_set_current_user( self::$administrator_id ); 606 607 $data = array( 608 'meta' => array( 609 'test_single' => null, 610 ), 611 ); 612 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 613 $request->set_body_params( $data ); 614 /** 615 * Disable showing error as the below is going to intentionally 616 * trigger a DB error. 617 */ 618 global $wpdb; 619 $wpdb->suppress_errors = true; 620 add_filter( 'query', array( $this, 'error_delete_query' ) ); 621 622 $response = $this->server->dispatch( $request ); 623 remove_filter( 'query', array( $this, 'error_delete_query' ) ); 624 $wpdb->show_errors = true; 625 626 $this->assertErrorResponse( 'rest_meta_database_error', $response, 500 ); 627 } 628 629 public function test_get_schema() { 630 $request = new WP_REST_Request( 'OPTIONS', sprintf( '/wp/v2/users/%d', self::$user ) ); 631 $response = $this->server->dispatch( $request ); 632 633 $data = $response->get_data(); 634 $schema = $data['schema']; 635 636 $this->assertArrayHasKey( 'meta', $schema['properties'] ); 637 $meta_schema = $schema['properties']['meta']['properties']; 638 639 $this->assertArrayHasKey( 'test_single', $meta_schema ); 640 $this->assertEquals( 'string', $meta_schema['test_single']['type'] ); 641 642 $this->assertArrayHasKey( 'test_multi', $meta_schema ); 643 $this->assertEquals( 'array', $meta_schema['test_multi']['type'] ); 644 $this->assertArrayHasKey( 'items', $meta_schema['test_multi'] ); 645 $this->assertEquals( 'string', $meta_schema['test_multi']['items']['type'] ); 646 647 $this->assertArrayHasKey( 'test_custom_schema', $meta_schema ); 648 $this->assertEquals( 'number', $meta_schema['test_custom_schema']['type'] ); 649 650 $this->assertArrayNotHasKey( 'test_no_rest', $meta_schema ); 651 $this->assertArrayNotHasKey( 'test_rest_disabled', $meta_schema ); 652 $this->assertArrayNotHasKey( 'test_invalid_type', $meta_schema ); 653 } 654 655 /** 656 * Internal function used to disable an insert query which 657 * will trigger a wpdb error for testing purposes. 658 */ 659 public function error_insert_query( $query ) { 660 if ( strpos( $query, 'INSERT' ) === 0 ) { 661 $query = '],'; 662 } 663 return $query; 664 } 665 666 /** 667 * Internal function used to disable an insert query which 668 * will trigger a wpdb error for testing purposes. 669 */ 670 public function error_delete_query( $query ) { 671 if ( strpos( $query, 'DELETE' ) === 0 ) { 672 $query = '],'; 673 } 674 return $query; 675 } 676 } -
new file tests/phpunit/tests/term/capabilities.php
diff --git a/tests/phpunit/tests/term/capabilities.php b/tests/phpunit/tests/term/capabilities.php new file mode 100644 index 0000000..b6b4c2f
- + 1 <?php 2 3 /** 4 * @group taxonomy 5 * @group capabilities 6 */ 7 8 class Tests_Term_Capabilities extends WP_UnitTestCase { 9 protected static $admin; 10 protected static $u1; 11 protected static $u2; 12 protected static $tag; 13 14 public static function wpSetUpBeforeClass( $factory ) { 15 self::$admin = $factory->user->create( array( 'role' => 'administrator' ) ); 16 self::$u1 = $factory->user->create( array( 'role' => 'subscriber' ) ); 17 self::$u2 = $factory->user->create( array( 'role' => 'subscriber' ) ); 18 19 self::$tag = $factory->tag->create(); 20 } 21 22 public static function wpTearDownAfterClass() { 23 self::delete_user( self::$admin ); 24 self::delete_user( self::$u1 ); 25 self::delete_user( self::$u2 ); 26 27 wp_delete_term( self::$tag, 'post_tag' ); 28 } 29 30 public function setUp() { 31 parent::setUp(); 32 add_filter( 'user_has_cap', array( $this, 'grant_edit_term_to_u1' ), 10, 4 ); 33 } 34 35 public function tearDown() { 36 parent::tearDown(); 37 remove_filter( 'user_has_cap', array( $this, 'grant_edit_term_to_u1' ), 10, 4 ); 38 } 39 40 public function grant_edit_term_to_u1( $allcaps, $caps, $args, WP_User $user ) { 41 if ( array( 'manage_categories' ) == $caps && self::$u1 === $user->ID ) { 42 $allcaps['manage_categories'] = 1; 43 } 44 45 return $allcaps; 46 } 47 48 public function test_no_one_can_edit_term_meta_for_non_existent_term() { 49 wp_set_current_user( self::$admin ); 50 $this->assertFalse( current_user_can( 'edit_term_meta', 999999 ) ); 51 } 52 53 public function test_user_can_edit_term_meta() { 54 wp_set_current_user( self::$u1 ); 55 $this->assertTrue( current_user_can( 'edit_term_meta', self::$tag, 'foo' ) ); 56 } 57 58 public function test_user_cannot_edit_term_meta() { 59 wp_set_current_user( self::$u2 ); 60 $this->assertFalse( current_user_can( 'edit_term_meta', self::$tag, 'foo' ) ); 61 } 62 63 public function test_no_one_can_delete_term_meta_for_non_existent_term() { 64 wp_set_current_user( self::$admin ); 65 $this->assertFalse( current_user_can( 'delete_term_meta', 999999, 'foo' ) ); 66 } 67 68 public function test_user_can_delete_term_meta() { 69 wp_set_current_user( self::$u1 ); 70 $this->assertTrue( current_user_can( 'delete_term_meta', self::$tag, 'foo' ) ); 71 } 72 73 public function test_user_cannot_delete_term_meta() { 74 wp_set_current_user( self::$u2 ); 75 $this->assertFalse( current_user_can( 'delete_term_meta', self::$tag, 'foo' ) ); 76 } 77 78 public function test_no_one_can_add_term_meta_for_non_existent_term() { 79 wp_set_current_user( self::$admin ); 80 $this->assertFalse( current_user_can( 'add_term_meta', 999999, 'foo' ) ); 81 } 82 83 public function test_user_can_add_term_meta() { 84 wp_set_current_user( self::$u1 ); 85 $this->assertTrue( current_user_can( 'add_term_meta', self::$tag, 'foo' ) ); 86 } 87 88 public function test_user_cannot_add_term_meta() { 89 wp_set_current_user( self::$u2 ); 90 $this->assertFalse( current_user_can( 'add_term_meta', self::$tag, 'foo' ) ); 91 } 92 } -
tests/phpunit/tests/user/capabilities.php
diff --git a/tests/phpunit/tests/user/capabilities.php b/tests/phpunit/tests/user/capabilities.php index 8ed2c65..b440e67 100644
a b class Tests_User_Capabilities extends WP_UnitTestCase { 431 431 $expected['delete_post_meta'], 432 432 $expected['add_post_meta'], 433 433 $expected['edit_comment'], 434 $expected['edit_comment_meta'], 435 $expected['delete_comment_meta'], 436 $expected['add_comment_meta'], 434 437 $expected['edit_term'], 435 438 $expected['delete_term'], 436 439 $expected['assign_term'], 437 $expected['delete_user'] 440 $expected['edit_term_meta'], 441 $expected['delete_term_meta'], 442 $expected['add_term_meta'], 443 $expected['delete_user'], 444 $expected['edit_user_meta'], 445 $expected['delete_user_meta'], 446 $expected['add_user_meta'] 438 447 ); 439 448 440 449 $expected = array_keys( $expected ); … … class Tests_User_Capabilities extends WP_UnitTestCase { 1663 1672 $wp_roles = new WP_Roles(); 1664 1673 $wp_roles->reinit(); 1665 1674 } 1675 1676 /** 1677 * @ticket 38412 1678 */ 1679 public function test_no_one_can_edit_user_meta_for_non_existent_term() { 1680 wp_set_current_user( self::$super_admin->ID ); 1681 $this->assertFalse( current_user_can( 'edit_user_meta', 999999 ) ); 1682 } 1683 1684 /** 1685 * @ticket 38412 1686 */ 1687 public function test_user_can_edit_user_meta() { 1688 wp_set_current_user( self::$users['administrator']->ID ); 1689 if ( is_multisite() ) { 1690 grant_super_admin( self::$users['administrator']->ID ); 1691 } 1692 $this->assertTrue( current_user_can( 'edit_user_meta', self::$users['subscriber']->ID, 'foo' ) ); 1693 } 1694 1695 /** 1696 * @ticket 38412 1697 */ 1698 public function test_user_cannot_edit_user_meta() { 1699 wp_set_current_user( self::$users['editor']->ID ); 1700 $this->assertFalse( current_user_can( 'edit_user_meta', self::$users['subscriber']->ID, 'foo' ) ); 1701 } 1702 1703 /** 1704 * @ticket 38412 1705 */ 1706 public function test_no_one_can_delete_user_meta_for_non_existent_term() { 1707 wp_set_current_user( self::$super_admin->ID ); 1708 $this->assertFalse( current_user_can( 'delete_user_meta', 999999, 'foo' ) ); 1709 } 1710 1711 /** 1712 * @ticket 38412 1713 */ 1714 public function test_user_can_delete_user_meta() { 1715 wp_set_current_user( self::$users['administrator']->ID ); 1716 if ( is_multisite() ) { 1717 grant_super_admin( self::$users['administrator']->ID ); 1718 } 1719 $this->assertTrue( current_user_can( 'delete_user_meta', self::$users['subscriber']->ID, 'foo' ) ); 1720 } 1721 1722 /** 1723 * @ticket 38412 1724 */ 1725 public function test_user_cannot_delete_user_meta() { 1726 wp_set_current_user( self::$users['editor']->ID ); 1727 $this->assertFalse( current_user_can( 'delete_user_meta', self::$users['subscriber']->ID, 'foo' ) ); 1728 } 1729 1730 /** 1731 * @ticket 38412 1732 */ 1733 public function test_no_one_can_add_user_meta_for_non_existent_term() { 1734 wp_set_current_user( self::$super_admin->ID ); 1735 $this->assertFalse( current_user_can( 'add_user_meta', 999999, 'foo' ) ); 1736 } 1737 1738 /** 1739 * @ticket 38412 1740 */ 1741 public function test_user_can_add_user_meta() { 1742 wp_set_current_user( self::$users['administrator']->ID ); 1743 if ( is_multisite() ) { 1744 grant_super_admin( self::$users['administrator']->ID ); 1745 } 1746 $this->assertTrue( current_user_can( 'add_user_meta', self::$users['subscriber']->ID, 'foo' ) ); 1747 } 1748 1749 /** 1750 * @ticket 38412 1751 */ 1752 public function test_user_cannot_add_user_meta() { 1753 wp_set_current_user( self::$users['editor']->ID ); 1754 $this->assertFalse( current_user_can( 'add_user_meta', self::$users['subscriber']->ID, 'foo' ) ); 1755 } 1666 1756 }
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)