Ticket #38412: 38412.3.diff
| File 38412.3.diff, 68.7 KB (added by , 10 years ago) |
|---|
-
src/wp-includes/capabilities.php
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 if ( empty( $sub_type ) ) { 247 295 $caps[] = 'do_not_allow'; 248 296 break; 249 297 } 250 298 251 $ post_type = get_post_type( $post);299 $caps = map_meta_cap( "edit_{$object_type}", $user_id, $object_id ); 252 300 253 $caps = map_meta_cap( 'edit_post', $user_id, $post->ID );254 255 301 $meta_key = isset( $args[ 1 ] ) ? $args[ 1 ] : false; 256 302 257 if ( $meta_key && ( has_filter( "auth_post_meta_{$meta_key}" ) || has_filter( "auth_post_{$post_type}_meta_{$meta_key}" ) ) ) { 303 $has_filter = has_filter( "auth_{$object_type}_meta_{$meta_key}" ) || has_filter( "auth_{$object_type}_{$sub_type}_meta_{$meta_key}" ); 304 if ( $meta_key && $has_filter ) { 258 305 /** 259 * Filters whether the user is allowed to add post meta to a post.306 * Filters whether the user is allowed to add meta to an object. 260 307 * 261 * The dynamic portion of the hook name, `$meta_key`, refers to the 262 * meta key passed to map_meta_cap(). 308 * The dynamic portions of the hook name `$object_type`, and `$meta_key`, refer 309 * to the object type (post, comment, term, user) and meta key passed to 310 * map_meta_cap(), respectively. 263 311 * 264 312 * @since 3.3.0 265 313 * 266 * @param bool $allowed Whether the user can add the postmeta. 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.314 * @param bool $allowed Whether the user can add the meta. Default false. 315 * @param string $meta_key The meta key. 316 * @param int $object_id Object ID. 317 * @param int $user_id User ID. 318 * @param string $cap Capability name. 319 * @param array $caps User capabilities. 272 320 */ 273 $allowed = apply_filters( "auth_ post_meta_{$meta_key}", false, $meta_key, $post->ID, $user_id, $cap, $caps );321 $allowed = apply_filters( "auth_{$object_type}_meta_{$meta_key}", false, $meta_key, $object_id, $user_id, $cap, $caps ); 274 322 275 323 /** 276 324 * Filters whether the user is allowed to add post meta to a post of a given type. 277 325 * 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. 326 * The dynamic portions of the hook name, `$meta_key`, `$object_type`, 327 * `$sub_type`, refer to the meta key passed to map_meta_cap(), the object type 328 * (post, comment, term, user) and the sub-type (post type, comment type, 329 * taxonomy), respectively. 280 330 * 281 331 * @since 4.6.0 282 332 * 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.333 * @param bool $allowed Whether the user can add the post meta. Default false. 334 * @param string $meta_key The meta key. 335 * @param int $object_id Object ID. 336 * @param int $user_id User ID. 337 * @param string $cap Capability name. 338 * @param array $caps User capabilities. 289 339 */ 290 $allowed = apply_filters( "auth_ post_{$post_type}_meta_{$meta_key}", $allowed, $meta_key, $post->ID, $user_id, $cap, $caps );340 $allowed = apply_filters( "auth_{$object_type}_{$sub_type}_meta_{$meta_key}", $allowed, $meta_key, $object_id, $user_id, $cap, $caps ); 291 341 292 342 if ( ! $allowed ) 293 343 $caps[] = $cap; 294 } elseif ( $meta_key && is_protected_meta( $meta_key, 'post') ) {344 } elseif ( $meta_key && is_protected_meta( $meta_key, $object_type ) ) { 295 345 $caps[] = $cap; 296 346 } 297 347 break; -
src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php
624 624 if ( ! $change ) { 625 625 return new WP_Error( 'rest_comment_failed_edit', __( 'Updating comment status failed.' ), array( 'status' => 500 ) ); 626 626 } 627 } else {627 } elseif( ! empty( $prepared_args ) ) { 628 628 if ( is_wp_error( $prepared_args ) ) { 629 629 return $prepared_args; 630 630 } -
src/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php
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; … … 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 ), … … 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.' ), … … 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 ), … … 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; … … 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.' ), … … 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.' ), … … 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 ), … … 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 -
tests/phpunit/tests/rest-api/rest-comment-meta-fields.php
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 $comment_id; 14 protected static $post_id; 15 16 public static function wpSetUpBeforeClass( $factory ) { 17 self::$post_id = $factory->post->create(); 18 self::$comment_id = $factory->comment->create_post_comments( self::$post_id, 1 )[0]; 19 } 20 21 public static function wpTearDownAfterClass() { 22 wp_delete_comment( self::$comment_id ); 23 wp_delete_post( self::$post_id ); 24 } 25 public function setUp() { 26 parent::setUp(); 27 28 register_meta( 'comment', 'test_single', array( 29 'show_in_rest' => true, 30 'single' => true, 31 )); 32 register_meta( 'comment', 'test_multi', array( 33 'show_in_rest' => true, 34 'single' => false, 35 )); 36 register_meta( 'comment', 'test_bad_auth', array( 37 'show_in_rest' => true, 38 'single' => true, 39 'auth_callback' => '__return_false', 40 )); 41 register_meta( 'comment', 'test_bad_auth_multi', array( 42 'show_in_rest' => true, 43 'single' => false, 44 'auth_callback' => '__return_false', 45 )); 46 register_meta( 'comment', 'test_no_rest', array() ); 47 register_meta( 'comment', 'test_rest_disabled', array( 48 'show_in_rest' => false, 49 )); 50 register_meta( 'comment', '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( 'comment', '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 self::$post_id = $this->factory->post->create(); 71 self::$comment_id = $this->factory->comment->create_post_comments( self::$post_id, 1 )[0]; 72 73 } 74 75 protected function grant_write_permission() { 76 // Ensure we have write permission. 77 $user = $this->factory->user->create( array( 78 'role' => 'editor', 79 )); 80 wp_set_current_user( $user ); 81 } 82 83 public function test_get_value() { 84 add_comment_meta( self::$comment_id, 'test_single', 'testvalue' ); 85 86 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 87 $response = $this->server->dispatch( $request ); 88 89 $this->assertEquals( 200, $response->get_status() ); 90 91 $data = $response->get_data(); 92 $this->assertArrayHasKey( 'meta', $data ); 93 94 $meta = (array) $data['meta']; 95 $this->assertArrayHasKey( 'test_single', $meta ); 96 $this->assertEquals( 'testvalue', $meta['test_single'] ); 97 } 98 99 /** 100 * @depends test_get_value 101 */ 102 public function test_get_multi_value() { 103 add_comment_meta( self::$comment_id, 'test_multi', 'value1' ); 104 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 105 106 $response = $this->server->dispatch( $request ); 107 $this->assertEquals( 200, $response->get_status() ); 108 109 $data = $response->get_data(); 110 $meta = (array) $data['meta']; 111 $this->assertArrayHasKey( 'test_multi', $meta ); 112 $this->assertInternalType( 'array', $meta['test_multi'] ); 113 $this->assertContains( 'value1', $meta['test_multi'] ); 114 115 // Check after an update. 116 add_comment_meta( self::$comment_id, 'test_multi', 'value2' ); 117 118 $response = $this->server->dispatch( $request ); 119 $this->assertEquals( 200, $response->get_status() ); 120 $data = $response->get_data(); 121 $meta = (array) $data['meta']; 122 $this->assertContains( 'value1', $meta['test_multi'] ); 123 $this->assertContains( 'value2', $meta['test_multi'] ); 124 } 125 126 /** 127 * @depends test_get_value 128 */ 129 public function test_get_unregistered() { 130 add_comment_meta( self::$comment_id, 'test_unregistered', 'value1' ); 131 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 132 133 $response = $this->server->dispatch( $request ); 134 $this->assertEquals( 200, $response->get_status() ); 135 136 $data = $response->get_data(); 137 $meta = (array) $data['meta']; 138 $this->assertArrayNotHasKey( 'test_unregistered', $meta ); 139 } 140 141 /** 142 * @depends test_get_value 143 */ 144 public function test_get_registered_no_api_access() { 145 add_comment_meta( self::$comment_id, 'test_no_rest', 'for_the_wicked' ); 146 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 147 148 $response = $this->server->dispatch( $request ); 149 $this->assertEquals( 200, $response->get_status() ); 150 151 $data = $response->get_data(); 152 $meta = (array) $data['meta']; 153 $this->assertArrayNotHasKey( 'test_no_rest', $meta ); 154 } 155 156 /** 157 * @depends test_get_value 158 */ 159 public function test_get_registered_api_disabled() { 160 add_comment_meta( self::$comment_id, 'test_rest_disabled', 'sleepless_nights' ); 161 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 162 163 $response = $this->server->dispatch( $request ); 164 $this->assertEquals( 200, $response->get_status() ); 165 166 $data = $response->get_data(); 167 $meta = (array) $data['meta']; 168 $this->assertArrayNotHasKey( 'test_rest_disabled', $meta ); 169 } 170 171 public function test_get_value_types() { 172 register_meta( 'comment', 'test_string', array( 173 'show_in_rest' => true, 174 'single' => true, 175 'type' => 'string', 176 )); 177 register_meta( 'comment', 'test_number', array( 178 'show_in_rest' => true, 179 'single' => true, 180 'type' => 'number', 181 )); 182 register_meta( 'comment', 'test_bool', array( 183 'show_in_rest' => true, 184 'single' => true, 185 'type' => 'boolean', 186 )); 187 188 /** @var WP_REST_Server $wp_rest_server */ 189 global $wp_rest_server; 190 $this->server = $wp_rest_server = new Spy_REST_Server; 191 do_action( 'rest_api_init' ); 192 193 add_comment_meta( self::$comment_id, 'test_string', 42 ); 194 add_comment_meta( self::$comment_id, 'test_number', '42' ); 195 add_comment_meta( self::$comment_id, 'test_bool', 1 ); 196 197 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 198 $response = $this->server->dispatch( $request ); 199 $this->assertEquals( 200, $response->get_status() ); 200 201 $data = $response->get_data(); 202 $meta = (array) $data['meta']; 203 204 $this->assertArrayHasKey( 'test_string', $meta ); 205 $this->assertInternalType( 'string', $meta['test_string'] ); 206 $this->assertSame( '42', $meta['test_string'] ); 207 208 $this->assertArrayHasKey( 'test_number', $meta ); 209 $this->assertInternalType( 'float', $meta['test_number'] ); 210 $this->assertSame( 42.0, $meta['test_number'] ); 211 212 $this->assertArrayHasKey( 'test_bool', $meta ); 213 $this->assertInternalType( 'boolean', $meta['test_bool'] ); 214 $this->assertSame( true, $meta['test_bool'] ); 215 } 216 217 /** 218 * @depends test_get_value 219 */ 220 public function test_set_value() { 221 // Ensure no data exists currently. 222 $values = get_comment_meta( self::$comment_id, 'test_single', false ); 223 $this->assertEmpty( $values ); 224 225 $this->grant_write_permission(); 226 227 $data = array( 228 'meta' => array( 229 'test_single' => 'test_value', 230 ), 231 ); 232 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 233 $request->set_body_params( $data ); 234 235 $response = $this->server->dispatch( $request ); 236 $this->assertEquals( 200, $response->get_status() ); 237 238 $meta = get_comment_meta( self::$comment_id, 'test_single', false ); 239 $this->assertNotEmpty( $meta ); 240 $this->assertCount( 1, $meta ); 241 $this->assertEquals( 'test_value', $meta[0] ); 242 243 $data = $response->get_data(); 244 $meta = (array) $data['meta']; 245 $this->assertArrayHasKey( 'test_single', $meta ); 246 $this->assertEquals( 'test_value', $meta['test_single'] ); 247 } 248 249 /** 250 * @depends test_get_value 251 */ 252 public function test_set_duplicate_single_value() { 253 // Start with an existing metakey and value. 254 $values = update_comment_meta( self::$comment_id, 'test_single', 'test_value' ); 255 $this->assertEquals( 'test_value', get_comment_meta( self::$comment_id, 'test_single', true ) ); 256 257 $this->grant_write_permission(); 258 259 $data = array( 260 'meta' => array( 261 'test_single' => 'test_value', 262 ), 263 ); 264 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 265 $request->set_body_params( $data ); 266 267 $response = $this->server->dispatch( $request ); 268 $this->assertEquals( 200, $response->get_status() ); 269 270 $meta = get_comment_meta( self::$comment_id, 'test_single', true ); 271 $this->assertNotEmpty( $meta ); 272 $this->assertEquals( 'test_value', $meta ); 273 274 $data = $response->get_data(); 275 $meta = (array) $data['meta']; 276 $this->assertArrayHasKey( 'test_single', $meta ); 277 $this->assertEquals( 'test_value', $meta['test_single'] ); 278 } 279 280 /** 281 * @depends test_set_value 282 */ 283 public function test_set_value_unauthenticated() { 284 $data = array( 285 'meta' => array( 286 'test_single' => 'test_value', 287 ), 288 ); 289 290 wp_set_current_user( 0 ); 291 292 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 293 $request->set_body_params( $data ); 294 295 $response = $this->server->dispatch( $request ); 296 $this->assertErrorResponse( 'rest_cannot_edit', $response, 401 ); 297 298 // Check that the value wasn't actually updated. 299 $this->assertEmpty( get_comment_meta( self::$comment_id, 'test_single', false ) ); 300 } 301 302 /** 303 * @depends test_set_value 304 */ 305 public function test_set_value_blocked() { 306 $data = array( 307 'meta' => array( 308 'test_bad_auth' => 'test_value', 309 ), 310 ); 311 312 $this->grant_write_permission(); 313 314 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 315 $request->set_body_params( $data ); 316 317 $response = $this->server->dispatch( $request ); 318 $this->assertErrorResponse( 'rest_cannot_update', $response, 403 ); 319 $this->assertEmpty( get_comment_meta( self::$comment_id, 'test_bad_auth', false ) ); 320 } 321 322 /** 323 * @depends test_set_value 324 */ 325 public function test_set_value_db_error() { 326 $data = array( 327 'meta' => array( 328 'test_single' => 'test_value', 329 ), 330 ); 331 332 $this->grant_write_permission(); 333 334 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 335 $request->set_body_params( $data ); 336 337 /** 338 * Disable showing error as the below is going to intentionally 339 * trigger a DB error. 340 */ 341 global $wpdb; 342 $wpdb->suppress_errors = true; 343 add_filter( 'query', array( $this, 'error_insert_query' ) ); 344 345 $response = $this->server->dispatch( $request ); 346 remove_filter( 'query', array( $this, 'error_insert_query' ) ); 347 $wpdb->show_errors = true; 348 } 349 350 public function test_set_value_multiple() { 351 // Ensure no data exists currently. 352 $values = get_comment_meta( self::$comment_id, 'test_multi', false ); 353 $this->assertEmpty( $values ); 354 355 $this->grant_write_permission(); 356 357 $data = array( 358 'meta' => array( 359 'test_multi' => array( 'val1' ), 360 ), 361 ); 362 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 363 $request->set_body_params( $data ); 364 365 $response = $this->server->dispatch( $request ); 366 $this->assertEquals( 200, $response->get_status() ); 367 368 $meta = get_comment_meta( self::$comment_id, 'test_multi', false ); 369 $this->assertNotEmpty( $meta ); 370 $this->assertCount( 1, $meta ); 371 $this->assertEquals( 'val1', $meta[0] ); 372 373 // Add another value. 374 $data = array( 375 'meta' => array( 376 'test_multi' => array( 'val1', 'val2' ), 377 ), 378 ); 379 $request->set_body_params( $data ); 380 381 $response = $this->server->dispatch( $request ); 382 $this->assertEquals( 200, $response->get_status() ); 383 384 $meta = get_comment_meta( self::$comment_id, 'test_multi', false ); 385 $this->assertNotEmpty( $meta ); 386 $this->assertCount( 2, $meta ); 387 $this->assertContains( 'val1', $meta ); 388 $this->assertContains( 'val2', $meta ); 389 } 390 391 /** 392 * Test removing only one item with duplicate items. 393 */ 394 public function test_set_value_remove_one() { 395 add_comment_meta( self::$comment_id, 'test_multi', 'c' ); 396 add_comment_meta( self::$comment_id, 'test_multi', 'n' ); 397 add_comment_meta( self::$comment_id, 'test_multi', 'n' ); 398 399 $this->grant_write_permission(); 400 401 $data = array( 402 'meta' => array( 403 'test_multi' => array( 'c', 'n' ), 404 ), 405 ); 406 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 407 $request->set_body_params( $data ); 408 409 $response = $this->server->dispatch( $request ); 410 $this->assertEquals( 200, $response->get_status() ); 411 412 $meta = get_comment_meta( self::$comment_id, 'test_multi', false ); 413 $this->assertNotEmpty( $meta ); 414 $this->assertCount( 2, $meta ); 415 $this->assertContains( 'c', $meta ); 416 $this->assertContains( 'n', $meta ); 417 } 418 419 /** 420 * @depends test_set_value_multiple 421 */ 422 public function test_set_value_multiple_unauthenticated() { 423 // Ensure no data exists currently. 424 $values = get_comment_meta( self::$comment_id, 'test_multi', false ); 425 $this->assertEmpty( $values ); 426 427 wp_set_current_user( 0 ); 428 429 $data = array( 430 'meta' => array( 431 'test_multi' => array( 'val1' ), 432 ), 433 ); 434 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 435 $request->set_body_params( $data ); 436 437 $response = $this->server->dispatch( $request ); 438 $this->assertErrorResponse( 'rest_cannot_edit', $response, 401 ); 439 440 $meta = get_comment_meta( self::$comment_id, 'test_multi', false ); 441 $this->assertEmpty( $meta ); 442 } 443 444 /** 445 * @depends test_set_value_multiple 446 */ 447 public function test_set_value_multiple_blocked() { 448 $data = array( 449 'meta' => array( 450 'test_bad_auth_multi' => array( 'test_value' ), 451 ), 452 ); 453 454 $this->grant_write_permission(); 455 456 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 457 $request->set_body_params( $data ); 458 459 $response = $this->server->dispatch( $request ); 460 $this->assertErrorResponse( 'rest_cannot_update', $response, 403 ); 461 $this->assertEmpty( get_comment_meta( self::$comment_id, 'test_bad_auth_multi', false ) ); 462 } 463 464 public function test_add_multi_value_db_error() { 465 // Ensure no data exists currently. 466 $values = get_comment_meta( self::$comment_id, 'test_multi', false ); 467 $this->assertEmpty( $values ); 468 469 $this->grant_write_permission(); 470 471 $data = array( 472 'meta' => array( 473 'test_multi' => array( 'val1' ), 474 ), 475 ); 476 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 477 $request->set_body_params( $data ); 478 479 /** 480 * Disable showing error as the below is going to intentionally 481 * trigger a DB error. 482 */ 483 global $wpdb; 484 $wpdb->suppress_errors = true; 485 add_filter( 'query', array( $this, 'error_insert_query' ) ); 486 487 $response = $this->server->dispatch( $request ); 488 remove_filter( 'query', array( $this, 'error_insert_query' ) ); 489 $wpdb->show_errors = true; 490 491 $this->assertErrorResponse( 'rest_meta_database_error', $response, 500 ); 492 } 493 494 public function test_remove_multi_value_db_error() { 495 add_comment_meta( self::$comment_id, 'test_multi', 'val1' ); 496 $values = get_comment_meta( self::$comment_id, 'test_multi', false ); 497 $this->assertEquals( array( 'val1' ), $values ); 498 499 $this->grant_write_permission(); 500 501 $data = array( 502 'meta' => array( 503 'test_multi' => array(), 504 ), 505 ); 506 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 507 $request->set_body_params( $data ); 508 509 /** 510 * Disable showing error as the below is going to intentionally 511 * trigger a DB error. 512 */ 513 global $wpdb; 514 $wpdb->suppress_errors = true; 515 add_filter( 'query', array( $this, 'error_delete_query' ) ); 516 517 $response = $this->server->dispatch( $request ); 518 remove_filter( 'query', array( $this, 'error_delete_query' ) ); 519 $wpdb->show_errors = true; 520 521 $this->assertErrorResponse( 'rest_meta_database_error', $response, 500 ); 522 } 523 524 public function test_delete_value() { 525 add_comment_meta( self::$comment_id, 'test_single', 'val1' ); 526 $current = get_comment_meta( self::$comment_id, 'test_single', true ); 527 $this->assertEquals( 'val1', $current ); 528 529 $this->grant_write_permission(); 530 531 $data = array( 532 'meta' => array( 533 'test_single' => null, 534 ), 535 ); 536 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 537 $request->set_body_params( $data ); 538 539 $response = $this->server->dispatch( $request ); 540 $this->assertEquals( 200, $response->get_status() ); 541 542 $meta = get_comment_meta( self::$comment_id, 'test_single', false ); 543 $this->assertEmpty( $meta ); 544 } 545 546 /** 547 * @depends test_delete_value 548 */ 549 public function test_delete_value_blocked() { 550 add_comment_meta( self::$comment_id, 'test_bad_auth', 'val1' ); 551 $current = get_comment_meta( self::$comment_id, 'test_bad_auth', true ); 552 $this->assertEquals( 'val1', $current ); 553 554 $this->grant_write_permission(); 555 556 $data = array( 557 'meta' => array( 558 'test_bad_auth' => null, 559 ), 560 ); 561 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 562 $request->set_body_params( $data ); 563 564 $response = $this->server->dispatch( $request ); 565 $this->assertErrorResponse( 'rest_cannot_delete', $response, 403 ); 566 567 $meta = get_comment_meta( self::$comment_id, 'test_bad_auth', true ); 568 $this->assertEquals( 'val1', $meta ); 569 } 570 571 /** 572 * @depends test_delete_value 573 */ 574 public function test_delete_value_db_error() { 575 add_comment_meta( self::$comment_id, 'test_single', 'val1' ); 576 $current = get_comment_meta( self::$comment_id, 'test_single', true ); 577 $this->assertEquals( 'val1', $current ); 578 579 $this->grant_write_permission(); 580 581 $data = array( 582 'meta' => array( 583 'test_single' => null, 584 ), 585 ); 586 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 587 $request->set_body_params( $data ); 588 /** 589 * Disable showing error as the below is going to intentionally 590 * trigger a DB error. 591 */ 592 global $wpdb; 593 $wpdb->suppress_errors = true; 594 add_filter( 'query', array( $this, 'error_delete_query' ) ); 595 596 $response = $this->server->dispatch( $request ); 597 remove_filter( 'query', array( $this, 'error_delete_query' ) ); 598 $wpdb->show_errors = true; 599 600 $this->assertErrorResponse( 'rest_meta_database_error', $response, 500 ); 601 } 602 603 public function test_get_schema() { 604 $request = new WP_REST_Request( 'OPTIONS', sprintf( '/wp/v2/comments/%d', self::$comment_id ) ); 605 $response = $this->server->dispatch( $request ); 606 607 $data = $response->get_data(); 608 $schema = $data['schema']; 609 610 $this->assertArrayHasKey( 'meta', $schema['properties'] ); 611 $meta_schema = $schema['properties']['meta']['properties']; 612 613 $this->assertArrayHasKey( 'test_single', $meta_schema ); 614 $this->assertEquals( 'string', $meta_schema['test_single']['type'] ); 615 616 $this->assertArrayHasKey( 'test_multi', $meta_schema ); 617 $this->assertEquals( 'array', $meta_schema['test_multi']['type'] ); 618 $this->assertArrayHasKey( 'items', $meta_schema['test_multi'] ); 619 $this->assertEquals( 'string', $meta_schema['test_multi']['items']['type'] ); 620 621 $this->assertArrayHasKey( 'test_custom_schema', $meta_schema ); 622 $this->assertEquals( 'number', $meta_schema['test_custom_schema']['type'] ); 623 624 $this->assertArrayNotHasKey( 'test_no_rest', $meta_schema ); 625 $this->assertArrayNotHasKey( 'test_rest_disabled', $meta_schema ); 626 $this->assertArrayNotHasKey( 'test_invalid_type', $meta_schema ); 627 } 628 629 /** 630 * Internal function used to disable an insert query which 631 * will trigger a wpdb error for testing purposes. 632 */ 633 public function error_insert_query( $query ) { 634 if ( strpos( $query, 'INSERT' ) === 0 ) { 635 $query = '],'; 636 } 637 return $query; 638 } 639 640 /** 641 * Internal function used to disable an insert query which 642 * will trigger a wpdb error for testing purposes. 643 */ 644 public function error_delete_query( $query ) { 645 if ( strpos( $query, 'DELETE' ) === 0 ) { 646 $query = '],'; 647 } 648 return $query; 649 } 650 } -
tests/phpunit/tests/rest-api/rest-term-meta-fields.php
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 14 public function setUp() { 15 parent::setUp(); 16 17 register_meta( 'term', 'test_single', array( 18 'show_in_rest' => true, 19 'single' => true, 20 )); 21 register_meta( 'term', 'test_multi', array( 22 'show_in_rest' => true, 23 'single' => false, 24 )); 25 register_meta( 'term', 'test_bad_auth', array( 26 'show_in_rest' => true, 27 'single' => true, 28 'auth_callback' => '__return_false', 29 )); 30 register_meta( 'term', 'test_bad_auth_multi', array( 31 'show_in_rest' => true, 32 'single' => false, 33 'auth_callback' => '__return_false', 34 )); 35 register_meta( 'term', 'test_no_rest', array() ); 36 register_meta( 'term', 'test_rest_disabled', array( 37 'show_in_rest' => false, 38 )); 39 register_meta( 'term', 'test_custom_schema', array( 40 'single' => true, 41 'type' => 'integer', 42 'show_in_rest' => array( 43 'schema' => array( 44 'type' => 'number', 45 ), 46 ), 47 )); 48 register_meta( 'term', 'test_invalid_type', array( 49 'single' => true, 50 'type' => false, 51 'show_in_rest' => true, 52 )); 53 54 /** @var WP_REST_Server $wp_rest_server */ 55 global $wp_rest_server; 56 $this->server = $wp_rest_server = new Spy_REST_Server; 57 do_action( 'rest_api_init' ); 58 59 register_taxonomy( 'wptests_tax', 'post', array( 'show_in_rest' => true ) ); 60 $controller = new WP_REST_Terms_Controller( 'wptests_tax' ); 61 $controller->register_routes(); 62 63 $this->term_id = $this->factory->term->create( array( 'taxonomy' => 'wptests_tax' ) ); 64 } 65 66 protected function grant_write_permission() { 67 // Ensure we have write permission. 68 $user = $this->factory->user->create( array( 69 'role' => 'administrator', 70 )); 71 wp_set_current_user( $user ); 72 } 73 74 public function test_get_value() { 75 add_term_meta( $this->term_id, 'test_single', 'testvalue' ); 76 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/wptests_tax/%d', $this->term_id ) ); 77 78 $response = $this->server->dispatch( $request ); 79 80 $this->assertEquals( 200, $response->get_status() ); 81 82 $data = $response->get_data(); 83 $this->assertArrayHasKey( 'meta', $data ); 84 85 $meta = (array) $data['meta']; 86 $this->assertArrayHasKey( 'test_single', $meta ); 87 $this->assertEquals( 'testvalue', $meta['test_single'] ); 88 } 89 90 /** 91 * @depends test_get_value 92 */ 93 public function test_get_multi_value() { 94 add_term_meta( $this->term_id, 'test_multi', 'value1' ); 95 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/wptests_tax/%d', $this->term_id ) ); 96 97 $response = $this->server->dispatch( $request ); 98 $this->assertEquals( 200, $response->get_status() ); 99 100 $data = $response->get_data(); 101 $meta = (array) $data['meta']; 102 $this->assertArrayHasKey( 'test_multi', $meta ); 103 $this->assertInternalType( 'array', $meta['test_multi'] ); 104 $this->assertContains( 'value1', $meta['test_multi'] ); 105 106 // Check after an update. 107 add_term_meta( $this->term_id, 'test_multi', 'value2' ); 108 109 $response = $this->server->dispatch( $request ); 110 $this->assertEquals( 200, $response->get_status() ); 111 $data = $response->get_data(); 112 $meta = (array) $data['meta']; 113 $this->assertContains( 'value1', $meta['test_multi'] ); 114 $this->assertContains( 'value2', $meta['test_multi'] ); 115 } 116 117 /** 118 * @depends test_get_value 119 */ 120 public function test_get_unregistered() { 121 add_term_meta( $this->term_id, 'test_unregistered', 'value1' ); 122 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/wptests_tax/%d', $this->term_id ) ); 123 124 $response = $this->server->dispatch( $request ); 125 $this->assertEquals( 200, $response->get_status() ); 126 127 $data = $response->get_data(); 128 $meta = (array) $data['meta']; 129 $this->assertArrayNotHasKey( 'test_unregistered', $meta ); 130 } 131 132 /** 133 * @depends test_get_value 134 */ 135 public function test_get_registered_no_api_access() { 136 add_term_meta( $this->term_id, 'test_no_rest', 'for_the_wicked' ); 137 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/wptests_tax/%d', $this->term_id ) ); 138 139 $response = $this->server->dispatch( $request ); 140 $this->assertEquals( 200, $response->get_status() ); 141 142 $data = $response->get_data(); 143 $meta = (array) $data['meta']; 144 $this->assertArrayNotHasKey( 'test_no_rest', $meta ); 145 } 146 147 /** 148 * @depends test_get_value 149 */ 150 public function test_get_registered_api_disabled() { 151 add_term_meta( $this->term_id, 'test_rest_disabled', 'sleepless_nights' ); 152 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/wptests_tax/%d', $this->term_id ) ); 153 154 $response = $this->server->dispatch( $request ); 155 $this->assertEquals( 200, $response->get_status() ); 156 157 $data = $response->get_data(); 158 $meta = (array) $data['meta']; 159 $this->assertArrayNotHasKey( 'test_rest_disabled', $meta ); 160 } 161 162 public function test_get_value_types() { 163 register_meta( 'term', 'test_string', array( 164 'show_in_rest' => true, 165 'single' => true, 166 'type' => 'string', 167 )); 168 register_meta( 'term', 'test_number', array( 169 'show_in_rest' => true, 170 'single' => true, 171 'type' => 'number', 172 )); 173 register_meta( 'term', 'test_bool', array( 174 'show_in_rest' => true, 175 'single' => true, 176 'type' => 'boolean', 177 )); 178 179 /** @var WP_REST_Server $wp_rest_server */ 180 global $wp_rest_server; 181 $this->server = $wp_rest_server = new Spy_REST_Server; 182 do_action( 'rest_api_init' ); 183 184 add_term_meta( $this->term_id, 'test_string', 42 ); 185 add_term_meta( $this->term_id, 'test_number', '42' ); 186 add_term_meta( $this->term_id, 'test_bool', 1 ); 187 188 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/wptests_tax/%d', $this->term_id ) ); 189 $response = $this->server->dispatch( $request ); 190 $this->assertEquals( 200, $response->get_status() ); 191 192 $data = $response->get_data(); 193 $meta = (array) $data['meta']; 194 195 $this->assertArrayHasKey( 'test_string', $meta ); 196 $this->assertInternalType( 'string', $meta['test_string'] ); 197 $this->assertSame( '42', $meta['test_string'] ); 198 199 $this->assertArrayHasKey( 'test_number', $meta ); 200 $this->assertInternalType( 'float', $meta['test_number'] ); 201 $this->assertSame( 42.0, $meta['test_number'] ); 202 203 $this->assertArrayHasKey( 'test_bool', $meta ); 204 $this->assertInternalType( 'boolean', $meta['test_bool'] ); 205 $this->assertSame( true, $meta['test_bool'] ); 206 } 207 208 /** 209 * @depends test_get_value 210 */ 211 public function test_set_value() { 212 // Ensure no data exists currently. 213 $values = get_term_meta( $this->term_id, 'test_single', false ); 214 $this->assertEmpty( $values ); 215 216 $this->grant_write_permission(); 217 218 $data = array( 219 'meta' => array( 220 'test_single' => 'test_value', 221 ), 222 ); 223 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', $this->term_id ) ); 224 $request->set_body_params( $data ); 225 226 $response = $this->server->dispatch( $request ); 227 $this->assertEquals( 200, $response->get_status() ); 228 229 $meta = get_term_meta( $this->term_id, 'test_single', false ); 230 $this->assertNotEmpty( $meta ); 231 $this->assertCount( 1, $meta ); 232 $this->assertEquals( 'test_value', $meta[0] ); 233 234 $data = $response->get_data(); 235 $meta = (array) $data['meta']; 236 $this->assertArrayHasKey( 'test_single', $meta ); 237 $this->assertEquals( 'test_value', $meta['test_single'] ); 238 } 239 240 /** 241 * @depends test_get_value 242 */ 243 public function test_set_duplicate_single_value() { 244 // Start with an existing metakey and value. 245 $values = update_term_meta( $this->term_id, 'test_single', 'test_value' ); 246 $this->assertEquals( 'test_value', get_term_meta( $this->term_id, 'test_single', true ) ); 247 248 $this->grant_write_permission(); 249 250 $data = array( 251 'meta' => array( 252 'test_single' => 'test_value', 253 ), 254 ); 255 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', $this->term_id ) ); 256 $request->set_body_params( $data ); 257 258 $response = $this->server->dispatch( $request ); 259 $this->assertEquals( 200, $response->get_status() ); 260 261 $meta = get_term_meta( $this->term_id, 'test_single', true ); 262 $this->assertNotEmpty( $meta ); 263 $this->assertEquals( 'test_value', $meta ); 264 265 $data = $response->get_data(); 266 $meta = (array) $data['meta']; 267 $this->assertArrayHasKey( 'test_single', $meta ); 268 $this->assertEquals( 'test_value', $meta['test_single'] ); 269 } 270 271 /** 272 * @depends test_set_value 273 */ 274 public function test_set_value_unauthenticated() { 275 $data = array( 276 'meta' => array( 277 'test_single' => 'test_value', 278 ), 279 ); 280 281 wp_set_current_user( 0 ); 282 283 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', $this->term_id ) ); 284 $request->set_body_params( $data ); 285 286 $response = $this->server->dispatch( $request ); 287 $this->assertErrorResponse( 'rest_cannot_update', $response, 401 ); 288 289 // Check that the value wasn't actually updated. 290 $this->assertEmpty( get_term_meta( $this->term_id, 'test_single', false ) ); 291 } 292 293 /** 294 * @depends test_set_value 295 */ 296 public function test_set_value_blocked() { 297 $data = array( 298 'meta' => array( 299 'test_bad_auth' => 'test_value', 300 ), 301 ); 302 303 $this->grant_write_permission(); 304 305 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', $this->term_id ) ); 306 $request->set_body_params( $data ); 307 308 $response = $this->server->dispatch( $request ); 309 $this->assertErrorResponse( 'rest_cannot_update', $response, 403 ); 310 $this->assertEmpty( get_term_meta( $this->term_id, 'test_bad_auth', false ) ); 311 } 312 313 /** 314 * @depends test_set_value 315 */ 316 public function test_set_value_db_error() { 317 $data = array( 318 'meta' => array( 319 'test_single' => 'test_value', 320 ), 321 ); 322 323 $this->grant_write_permission(); 324 325 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', $this->term_id ) ); 326 $request->set_body_params( $data ); 327 328 /** 329 * Disable showing error as the below is going to intentionally 330 * trigger a DB error. 331 */ 332 global $wpdb; 333 $wpdb->suppress_errors = true; 334 add_filter( 'query', array( $this, 'error_insert_query' ) ); 335 336 $response = $this->server->dispatch( $request ); 337 remove_filter( 'query', array( $this, 'error_insert_query' ) ); 338 $wpdb->show_errors = true; 339 } 340 341 public function test_set_value_multiple() { 342 // Ensure no data exists currently. 343 $values = get_term_meta( $this->term_id, 'test_multi', false ); 344 $this->assertEmpty( $values ); 345 346 $this->grant_write_permission(); 347 348 $data = array( 349 'meta' => array( 350 'test_multi' => array( 'val1' ), 351 ), 352 ); 353 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', $this->term_id ) ); 354 $request->set_body_params( $data ); 355 356 $response = $this->server->dispatch( $request ); 357 $this->assertEquals( 200, $response->get_status() ); 358 359 $meta = get_term_meta( $this->term_id, 'test_multi', false ); 360 $this->assertNotEmpty( $meta ); 361 $this->assertCount( 1, $meta ); 362 $this->assertEquals( 'val1', $meta[0] ); 363 364 // Add another value. 365 $data = array( 366 'meta' => array( 367 'test_multi' => array( 'val1', 'val2' ), 368 ), 369 ); 370 $request->set_body_params( $data ); 371 372 $response = $this->server->dispatch( $request ); 373 $this->assertEquals( 200, $response->get_status() ); 374 375 $meta = get_term_meta( $this->term_id, 'test_multi', false ); 376 $this->assertNotEmpty( $meta ); 377 $this->assertCount( 2, $meta ); 378 $this->assertContains( 'val1', $meta ); 379 $this->assertContains( 'val2', $meta ); 380 } 381 382 /** 383 * Test removing only one item with duplicate items. 384 */ 385 public function test_set_value_remove_one() { 386 add_term_meta( $this->term_id, 'test_multi', 'c' ); 387 add_term_meta( $this->term_id, 'test_multi', 'n' ); 388 add_term_meta( $this->term_id, 'test_multi', 'n' ); 389 390 $this->grant_write_permission(); 391 392 $data = array( 393 'meta' => array( 394 'test_multi' => array( 'c', 'n' ), 395 ), 396 ); 397 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', $this->term_id ) ); 398 $request->set_body_params( $data ); 399 400 $response = $this->server->dispatch( $request ); 401 $this->assertEquals( 200, $response->get_status() ); 402 403 $meta = get_term_meta( $this->term_id, 'test_multi', false ); 404 $this->assertNotEmpty( $meta ); 405 $this->assertCount( 2, $meta ); 406 $this->assertContains( 'c', $meta ); 407 $this->assertContains( 'n', $meta ); 408 } 409 410 /** 411 * @depends test_set_value_multiple 412 */ 413 public function test_set_value_multiple_unauthenticated() { 414 // Ensure no data exists currently. 415 $values = get_term_meta( $this->term_id, 'test_multi', false ); 416 $this->assertEmpty( $values ); 417 418 wp_set_current_user( 0 ); 419 420 $data = array( 421 'meta' => array( 422 'test_multi' => array( 'val1' ), 423 ), 424 ); 425 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', $this->term_id ) ); 426 $request->set_body_params( $data ); 427 428 $response = $this->server->dispatch( $request ); 429 $this->assertErrorResponse( 'rest_cannot_update', $response, 401 ); 430 431 $meta = get_term_meta( $this->term_id, 'test_multi', false ); 432 $this->assertEmpty( $meta ); 433 } 434 435 /** 436 * @depends test_set_value_multiple 437 */ 438 public function test_set_value_multiple_blocked() { 439 $data = array( 440 'meta' => array( 441 'test_bad_auth_multi' => array( 'test_value' ), 442 ), 443 ); 444 445 $this->grant_write_permission(); 446 447 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', $this->term_id ) ); 448 $request->set_body_params( $data ); 449 450 $response = $this->server->dispatch( $request ); 451 $this->assertErrorResponse( 'rest_cannot_update', $response, 403 ); 452 $this->assertEmpty( get_term_meta( $this->term_id, 'test_bad_auth_multi', false ) ); 453 } 454 455 public function test_add_multi_value_db_error() { 456 // Ensure no data exists currently. 457 $values = get_term_meta( $this->term_id, 'test_multi', false ); 458 $this->assertEmpty( $values ); 459 460 $this->grant_write_permission(); 461 462 $data = array( 463 'meta' => array( 464 'test_multi' => array( 'val1' ), 465 ), 466 ); 467 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', $this->term_id ) ); 468 $request->set_body_params( $data ); 469 470 /** 471 * Disable showing error as the below is going to intentionally 472 * trigger a DB error. 473 */ 474 global $wpdb; 475 $wpdb->suppress_errors = true; 476 add_filter( 'query', array( $this, 'error_insert_query' ) ); 477 478 $response = $this->server->dispatch( $request ); 479 remove_filter( 'query', array( $this, 'error_insert_query' ) ); 480 $wpdb->show_errors = true; 481 482 $this->assertErrorResponse( 'rest_meta_database_error', $response, 500 ); 483 } 484 485 public function test_remove_multi_value_db_error() { 486 add_term_meta( $this->term_id, 'test_multi', 'val1' ); 487 $values = get_term_meta( $this->term_id, 'test_multi', false ); 488 $this->assertEquals( array( 'val1' ), $values ); 489 490 $this->grant_write_permission(); 491 492 $data = array( 493 'meta' => array( 494 'test_multi' => array(), 495 ), 496 ); 497 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', $this->term_id ) ); 498 $request->set_body_params( $data ); 499 500 /** 501 * Disable showing error as the below is going to intentionally 502 * trigger a DB error. 503 */ 504 global $wpdb; 505 $wpdb->suppress_errors = true; 506 add_filter( 'query', array( $this, 'error_delete_query' ) ); 507 508 $response = $this->server->dispatch( $request ); 509 remove_filter( 'query', array( $this, 'error_delete_query' ) ); 510 $wpdb->show_errors = true; 511 512 $this->assertErrorResponse( 'rest_meta_database_error', $response, 500 ); 513 } 514 515 public function test_delete_value() { 516 add_term_meta( $this->term_id, 'test_single', 'val1' ); 517 $current = get_term_meta( $this->term_id, 'test_single', true ); 518 $this->assertEquals( 'val1', $current ); 519 520 $this->grant_write_permission(); 521 522 $data = array( 523 'meta' => array( 524 'test_single' => null, 525 ), 526 ); 527 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', $this->term_id ) ); 528 $request->set_body_params( $data ); 529 530 $response = $this->server->dispatch( $request ); 531 $this->assertEquals( 200, $response->get_status() ); 532 533 $meta = get_term_meta( $this->term_id, 'test_single', false ); 534 $this->assertEmpty( $meta ); 535 } 536 537 /** 538 * @depends test_delete_value 539 */ 540 public function test_delete_value_blocked() { 541 add_term_meta( $this->term_id, 'test_bad_auth', 'val1' ); 542 $current = get_term_meta( $this->term_id, 'test_bad_auth', true ); 543 $this->assertEquals( 'val1', $current ); 544 545 $this->grant_write_permission(); 546 547 $data = array( 548 'meta' => array( 549 'test_bad_auth' => null, 550 ), 551 ); 552 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', $this->term_id ) ); 553 $request->set_body_params( $data ); 554 555 $response = $this->server->dispatch( $request ); 556 $this->assertErrorResponse( 'rest_cannot_delete', $response, 403 ); 557 558 $meta = get_term_meta( $this->term_id, 'test_bad_auth', true ); 559 $this->assertEquals( 'val1', $meta ); 560 } 561 562 /** 563 * @depends test_delete_value 564 */ 565 public function test_delete_value_db_error() { 566 add_term_meta( $this->term_id, 'test_single', 'val1' ); 567 $current = get_term_meta( $this->term_id, 'test_single', true ); 568 $this->assertEquals( 'val1', $current ); 569 570 $this->grant_write_permission(); 571 572 $data = array( 573 'meta' => array( 574 'test_single' => null, 575 ), 576 ); 577 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/wptests_tax/%d', $this->term_id ) ); 578 $request->set_body_params( $data ); 579 /** 580 * Disable showing error as the below is going to intentionally 581 * trigger a DB error. 582 */ 583 global $wpdb; 584 $wpdb->suppress_errors = true; 585 add_filter( 'query', array( $this, 'error_delete_query' ) ); 586 587 $response = $this->server->dispatch( $request ); 588 remove_filter( 'query', array( $this, 'error_delete_query' ) ); 589 $wpdb->show_errors = true; 590 591 $this->assertErrorResponse( 'rest_meta_database_error', $response, 500 ); 592 } 593 594 public function test_get_schema() { 595 $request = new WP_REST_Request( 'OPTIONS', sprintf( '/wp/v2/wptests_tax/%d', $this->term_id ) ); 596 $response = $this->server->dispatch( $request ); 597 598 $data = $response->get_data(); 599 $schema = $data['schema']; 600 601 $this->assertArrayHasKey( 'meta', $schema['properties'] ); 602 $meta_schema = $schema['properties']['meta']['properties']; 603 604 $this->assertArrayHasKey( 'test_single', $meta_schema ); 605 $this->assertEquals( 'string', $meta_schema['test_single']['type'] ); 606 607 $this->assertArrayHasKey( 'test_multi', $meta_schema ); 608 $this->assertEquals( 'array', $meta_schema['test_multi']['type'] ); 609 $this->assertArrayHasKey( 'items', $meta_schema['test_multi'] ); 610 $this->assertEquals( 'string', $meta_schema['test_multi']['items']['type'] ); 611 612 $this->assertArrayHasKey( 'test_custom_schema', $meta_schema ); 613 $this->assertEquals( 'number', $meta_schema['test_custom_schema']['type'] ); 614 615 $this->assertArrayNotHasKey( 'test_no_rest', $meta_schema ); 616 $this->assertArrayNotHasKey( 'test_rest_disabled', $meta_schema ); 617 $this->assertArrayNotHasKey( 'test_invalid_type', $meta_schema ); 618 } 619 620 /** 621 * Internal function used to disable an insert query which 622 * will trigger a wpdb error for testing purposes. 623 */ 624 public function error_insert_query( $query ) { 625 if ( strpos( $query, 'INSERT' ) === 0 ) { 626 $query = '],'; 627 } 628 return $query; 629 } 630 631 /** 632 * Internal function used to disable an insert query which 633 * will trigger a wpdb error for testing purposes. 634 */ 635 public function error_delete_query( $query ) { 636 if ( strpos( $query, 'DELETE' ) === 0 ) { 637 $query = '],'; 638 } 639 return $query; 640 } 641 } -
tests/phpunit/tests/rest-api/rest-user-meta-fields.php
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 $user; 14 15 public static function wpSetUpBeforeClass( $factory ) { 16 self::$user = $factory->user->create( array( 17 'role' => 'author', 18 ) ); 19 } 20 21 public static function wpTearDownAfterClass() { 22 wp_delete_user( self::$user ); 23 } 24 25 public function setUp() { 26 parent::setUp(); 27 28 register_meta( 'user', 'test_single', array( 29 'show_in_rest' => true, 30 'single' => true, 31 )); 32 register_meta( 'user', 'test_multi', array( 33 'show_in_rest' => true, 34 'single' => false, 35 )); 36 register_meta( 'user', 'test_bad_auth', array( 37 'show_in_rest' => true, 38 'single' => true, 39 'auth_callback' => '__return_false', 40 )); 41 register_meta( 'user', 'test_bad_auth_multi', array( 42 'show_in_rest' => true, 43 'single' => false, 44 'auth_callback' => '__return_false', 45 )); 46 register_meta( 'user', 'test_no_rest', array() ); 47 register_meta( 'user', 'test_rest_disabled', array( 48 'show_in_rest' => false, 49 )); 50 register_meta( 'user', '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( 'user', '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 } 71 72 protected function grant_write_permission() { 73 // Ensure we have write permission. 74 $user = $this->factory->user->create( array( 75 'role' => 'administrator', 76 )); 77 wp_set_current_user( $user ); 78 } 79 80 public function test_get_value() { 81 add_user_meta( self::$user, 'test_single', 'testvalue' ); 82 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$user ) ); 83 84 $this->grant_write_permission(); 85 86 $response = $this->server->dispatch( $request ); 87 88 $this->assertEquals( 200, $response->get_status() ); 89 90 $data = $response->get_data(); 91 $this->assertArrayHasKey( 'meta', $data ); 92 93 $meta = (array) $data['meta']; 94 $this->assertArrayHasKey( 'test_single', $meta ); 95 $this->assertEquals( 'testvalue', $meta['test_single'] ); 96 } 97 98 /** 99 * @depends test_get_value 100 */ 101 public function test_get_multi_value() { 102 add_user_meta( self::$user, 'test_multi', 'value1' ); 103 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$user ) ); 104 105 $this->grant_write_permission(); 106 107 $response = $this->server->dispatch( $request ); 108 $this->assertEquals( 200, $response->get_status() ); 109 110 $data = $response->get_data(); 111 $meta = (array) $data['meta']; 112 $this->assertArrayHasKey( 'test_multi', $meta ); 113 $this->assertInternalType( 'array', $meta['test_multi'] ); 114 $this->assertContains( 'value1', $meta['test_multi'] ); 115 116 // Check after an update. 117 add_user_meta( self::$user, 'test_multi', 'value2' ); 118 119 $response = $this->server->dispatch( $request ); 120 $this->assertEquals( 200, $response->get_status() ); 121 $data = $response->get_data(); 122 $meta = (array) $data['meta']; 123 $this->assertContains( 'value1', $meta['test_multi'] ); 124 $this->assertContains( 'value2', $meta['test_multi'] ); 125 } 126 127 /** 128 * @depends test_get_value 129 */ 130 public function test_get_unregistered() { 131 add_user_meta( self::$user, 'test_unregistered', 'value1' ); 132 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$user ) ); 133 134 $this->grant_write_permission(); 135 136 $response = $this->server->dispatch( $request ); 137 $this->assertEquals( 200, $response->get_status() ); 138 139 $data = $response->get_data(); 140 $meta = (array) $data['meta']; 141 $this->assertArrayNotHasKey( 'test_unregistered', $meta ); 142 } 143 144 /** 145 * @depends test_get_value 146 */ 147 public function test_get_registered_no_api_access() { 148 add_user_meta( self::$user, 'test_no_rest', 'for_the_wicked' ); 149 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$user ) ); 150 151 $this->grant_write_permission(); 152 153 $response = $this->server->dispatch( $request ); 154 $this->assertEquals( 200, $response->get_status() ); 155 156 $data = $response->get_data(); 157 $meta = (array) $data['meta']; 158 $this->assertArrayNotHasKey( 'test_no_rest', $meta ); 159 } 160 161 /** 162 * @depends test_get_value 163 */ 164 public function test_get_registered_api_disabled() { 165 add_user_meta( self::$user, 'test_rest_disabled', 'sleepless_nights' ); 166 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$user ) ); 167 168 $this->grant_write_permission(); 169 170 $response = $this->server->dispatch( $request ); 171 $this->assertEquals( 200, $response->get_status() ); 172 173 $data = $response->get_data(); 174 $meta = (array) $data['meta']; 175 $this->assertArrayNotHasKey( 'test_rest_disabled', $meta ); 176 } 177 178 public function test_get_value_types() { 179 register_meta( 'user', 'test_string', array( 180 'show_in_rest' => true, 181 'single' => true, 182 'type' => 'string', 183 )); 184 register_meta( 'user', 'test_number', array( 185 'show_in_rest' => true, 186 'single' => true, 187 'type' => 'number', 188 )); 189 register_meta( 'user', 'test_bool', array( 190 'show_in_rest' => true, 191 'single' => true, 192 'type' => 'boolean', 193 )); 194 195 /** @var WP_REST_Server $wp_rest_server */ 196 global $wp_rest_server; 197 $this->server = $wp_rest_server = new Spy_REST_Server; 198 do_action( 'rest_api_init' ); 199 200 add_user_meta( self::$user, 'test_string', 42 ); 201 add_user_meta( self::$user, 'test_number', '42' ); 202 add_user_meta( self::$user, 'test_bool', 1 ); 203 204 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$user ) ); 205 206 $this->grant_write_permission(); 207 208 $response = $this->server->dispatch( $request ); 209 $this->assertEquals( 200, $response->get_status() ); 210 211 $data = $response->get_data(); 212 $meta = (array) $data['meta']; 213 214 $this->assertArrayHasKey( 'test_string', $meta ); 215 $this->assertInternalType( 'string', $meta['test_string'] ); 216 $this->assertSame( '42', $meta['test_string'] ); 217 218 $this->assertArrayHasKey( 'test_number', $meta ); 219 $this->assertInternalType( 'float', $meta['test_number'] ); 220 $this->assertSame( 42.0, $meta['test_number'] ); 221 222 $this->assertArrayHasKey( 'test_bool', $meta ); 223 $this->assertInternalType( 'boolean', $meta['test_bool'] ); 224 $this->assertSame( true, $meta['test_bool'] ); 225 } 226 227 /** 228 * @depends test_get_value 229 */ 230 public function test_set_value() { 231 // Ensure no data exists currently. 232 $values = get_user_meta( self::$user, 'test_single', false ); 233 $this->assertEmpty( $values ); 234 235 $this->grant_write_permission(); 236 237 $data = array( 238 'meta' => array( 239 'test_single' => 'test_value', 240 ), 241 ); 242 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 243 $request->set_body_params( $data ); 244 245 $response = $this->server->dispatch( $request ); 246 $this->assertEquals( 200, $response->get_status() ); 247 248 $meta = get_user_meta( self::$user, 'test_single', false ); 249 $this->assertNotEmpty( $meta ); 250 $this->assertCount( 1, $meta ); 251 $this->assertEquals( 'test_value', $meta[0] ); 252 253 $data = $response->get_data(); 254 $meta = (array) $data['meta']; 255 $this->assertArrayHasKey( 'test_single', $meta ); 256 $this->assertEquals( 'test_value', $meta['test_single'] ); 257 } 258 259 /** 260 * @depends test_get_value 261 */ 262 public function test_set_duplicate_single_value() { 263 // Start with an existing metakey and value. 264 $values = update_user_meta( self::$user, 'test_single', 'test_value' ); 265 $this->assertEquals( 'test_value', get_user_meta( self::$user, 'test_single', true ) ); 266 267 $this->grant_write_permission(); 268 269 $data = array( 270 'meta' => array( 271 'test_single' => 'test_value', 272 ), 273 ); 274 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 275 $request->set_body_params( $data ); 276 277 $response = $this->server->dispatch( $request ); 278 $this->assertEquals( 200, $response->get_status() ); 279 280 $meta = get_user_meta( self::$user, 'test_single', true ); 281 $this->assertNotEmpty( $meta ); 282 $this->assertEquals( 'test_value', $meta ); 283 284 $data = $response->get_data(); 285 $meta = (array) $data['meta']; 286 $this->assertArrayHasKey( 'test_single', $meta ); 287 $this->assertEquals( 'test_value', $meta['test_single'] ); 288 } 289 290 /** 291 * @depends test_set_value 292 */ 293 public function test_set_value_unauthenticated() { 294 $data = array( 295 'meta' => array( 296 'test_single' => 'test_value', 297 ), 298 ); 299 300 wp_set_current_user( 0 ); 301 302 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 303 $request->set_body_params( $data ); 304 305 $response = $this->server->dispatch( $request ); 306 $this->assertErrorResponse( 'rest_cannot_edit', $response, 401 ); 307 308 // Check that the value wasn't actually updated. 309 $this->assertEmpty( get_user_meta( self::$user, 'test_single', false ) ); 310 } 311 312 /** 313 * @depends test_set_value 314 */ 315 public function test_set_value_blocked() { 316 $data = array( 317 'meta' => array( 318 'test_bad_auth' => 'test_value', 319 ), 320 ); 321 322 $this->grant_write_permission(); 323 324 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 325 $request->set_body_params( $data ); 326 327 $response = $this->server->dispatch( $request ); 328 $this->assertErrorResponse( 'rest_cannot_update', $response, 403 ); 329 $this->assertEmpty( get_user_meta( self::$user, 'test_bad_auth', false ) ); 330 } 331 332 /** 333 * @depends test_set_value 334 */ 335 public function test_set_value_db_error() { 336 $data = array( 337 'meta' => array( 338 'test_single' => 'test_value', 339 ), 340 ); 341 342 $this->grant_write_permission(); 343 344 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 345 $request->set_body_params( $data ); 346 347 /** 348 * Disable showing error as the below is going to intentionally 349 * trigger a DB error. 350 */ 351 global $wpdb; 352 $wpdb->suppress_errors = true; 353 add_filter( 'query', array( $this, 'error_insert_query' ) ); 354 355 $response = $this->server->dispatch( $request ); 356 remove_filter( 'query', array( $this, 'error_insert_query' ) ); 357 $wpdb->show_errors = true; 358 } 359 360 public function test_set_value_multiple() { 361 // Ensure no data exists currently. 362 $values = get_user_meta( self::$user, 'test_multi', false ); 363 $this->assertEmpty( $values ); 364 365 $this->grant_write_permission(); 366 367 $data = array( 368 'meta' => array( 369 'test_multi' => array( 'val1' ), 370 ), 371 ); 372 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 373 $request->set_body_params( $data ); 374 375 $response = $this->server->dispatch( $request ); 376 $this->assertEquals( 200, $response->get_status() ); 377 378 $meta = get_user_meta( self::$user, 'test_multi', false ); 379 $this->assertNotEmpty( $meta ); 380 $this->assertCount( 1, $meta ); 381 $this->assertEquals( 'val1', $meta[0] ); 382 383 // Add another value. 384 $data = array( 385 'meta' => array( 386 'test_multi' => array( 'val1', 'val2' ), 387 ), 388 ); 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( 2, $meta ); 397 $this->assertContains( 'val1', $meta ); 398 $this->assertContains( 'val2', $meta ); 399 } 400 401 /** 402 * Test removing only one item with duplicate items. 403 */ 404 public function test_set_value_remove_one() { 405 add_user_meta( self::$user, 'test_multi', 'c' ); 406 add_user_meta( self::$user, 'test_multi', 'n' ); 407 add_user_meta( self::$user, 'test_multi', 'n' ); 408 409 $this->grant_write_permission(); 410 411 $data = array( 412 'meta' => array( 413 'test_multi' => array( 'c', 'n' ), 414 ), 415 ); 416 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 417 $request->set_body_params( $data ); 418 419 $response = $this->server->dispatch( $request ); 420 $this->assertEquals( 200, $response->get_status() ); 421 422 $meta = get_user_meta( self::$user, 'test_multi', false ); 423 $this->assertNotEmpty( $meta ); 424 $this->assertCount( 2, $meta ); 425 $this->assertContains( 'c', $meta ); 426 $this->assertContains( 'n', $meta ); 427 } 428 429 /** 430 * @depends test_set_value_multiple 431 */ 432 public function test_set_value_multiple_unauthenticated() { 433 // Ensure no data exists currently. 434 $values = get_user_meta( self::$user, 'test_multi', false ); 435 $this->assertEmpty( $values ); 436 437 wp_set_current_user( 0 ); 438 439 $data = array( 440 'meta' => array( 441 'test_multi' => array( 'val1' ), 442 ), 443 ); 444 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 445 $request->set_body_params( $data ); 446 447 $response = $this->server->dispatch( $request ); 448 $this->assertErrorResponse( 'rest_cannot_edit', $response, 401 ); 449 450 $meta = get_user_meta( self::$user, 'test_multi', false ); 451 $this->assertEmpty( $meta ); 452 } 453 454 /** 455 * @depends test_set_value_multiple 456 */ 457 public function test_set_value_multiple_blocked() { 458 $data = array( 459 'meta' => array( 460 'test_bad_auth_multi' => array( 'test_value' ), 461 ), 462 ); 463 464 $this->grant_write_permission(); 465 466 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 467 $request->set_body_params( $data ); 468 469 $response = $this->server->dispatch( $request ); 470 $this->assertErrorResponse( 'rest_cannot_update', $response, 403 ); 471 $this->assertEmpty( get_user_meta( self::$user, 'test_bad_auth_multi', false ) ); 472 } 473 474 public function test_add_multi_value_db_error() { 475 // Ensure no data exists currently. 476 $values = get_user_meta( self::$user, 'test_multi', false ); 477 $this->assertEmpty( $values ); 478 479 $this->grant_write_permission(); 480 481 $data = array( 482 'meta' => array( 483 'test_multi' => array( 'val1' ), 484 ), 485 ); 486 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 487 $request->set_body_params( $data ); 488 489 /** 490 * Disable showing error as the below is going to intentionally 491 * trigger a DB error. 492 */ 493 global $wpdb; 494 $wpdb->suppress_errors = true; 495 add_filter( 'query', array( $this, 'error_insert_query' ) ); 496 497 $response = $this->server->dispatch( $request ); 498 remove_filter( 'query', array( $this, 'error_insert_query' ) ); 499 $wpdb->show_errors = true; 500 501 $this->assertErrorResponse( 'rest_meta_database_error', $response, 500 ); 502 } 503 504 public function test_remove_multi_value_db_error() { 505 add_user_meta( self::$user, 'test_multi', 'val1' ); 506 $values = get_user_meta( self::$user, 'test_multi', false ); 507 $this->assertEquals( array( 'val1' ), $values ); 508 509 $this->grant_write_permission(); 510 511 $data = array( 512 'meta' => array( 513 'test_multi' => array(), 514 ), 515 ); 516 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 517 $request->set_body_params( $data ); 518 519 /** 520 * Disable showing error as the below is going to intentionally 521 * trigger a DB error. 522 */ 523 global $wpdb; 524 $wpdb->suppress_errors = true; 525 add_filter( 'query', array( $this, 'error_delete_query' ) ); 526 527 $response = $this->server->dispatch( $request ); 528 remove_filter( 'query', array( $this, 'error_delete_query' ) ); 529 $wpdb->show_errors = true; 530 531 $this->assertErrorResponse( 'rest_meta_database_error', $response, 500 ); 532 } 533 534 public function test_delete_value() { 535 add_user_meta( self::$user, 'test_single', 'val1' ); 536 $current = get_user_meta( self::$user, 'test_single', true ); 537 $this->assertEquals( 'val1', $current ); 538 539 $this->grant_write_permission(); 540 541 $data = array( 542 'meta' => array( 543 'test_single' => null, 544 ), 545 ); 546 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 547 $request->set_body_params( $data ); 548 549 $response = $this->server->dispatch( $request ); 550 $this->assertEquals( 200, $response->get_status() ); 551 552 $meta = get_user_meta( self::$user, 'test_single', false ); 553 $this->assertEmpty( $meta ); 554 } 555 556 /** 557 * @depends test_delete_value 558 */ 559 public function test_delete_value_blocked() { 560 add_user_meta( self::$user, 'test_bad_auth', 'val1' ); 561 $current = get_user_meta( self::$user, 'test_bad_auth', true ); 562 $this->assertEquals( 'val1', $current ); 563 564 $this->grant_write_permission(); 565 566 $data = array( 567 'meta' => array( 568 'test_bad_auth' => null, 569 ), 570 ); 571 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 572 $request->set_body_params( $data ); 573 574 $response = $this->server->dispatch( $request ); 575 $this->assertErrorResponse( 'rest_cannot_delete', $response, 403 ); 576 577 $meta = get_user_meta( self::$user, 'test_bad_auth', true ); 578 $this->assertEquals( 'val1', $meta ); 579 } 580 581 /** 582 * @depends test_delete_value 583 */ 584 public function test_delete_value_db_error() { 585 add_user_meta( self::$user, 'test_single', 'val1' ); 586 $current = get_user_meta( self::$user, 'test_single', true ); 587 $this->assertEquals( 'val1', $current ); 588 589 $this->grant_write_permission(); 590 591 $data = array( 592 'meta' => array( 593 'test_single' => null, 594 ), 595 ); 596 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) ); 597 $request->set_body_params( $data ); 598 /** 599 * Disable showing error as the below is going to intentionally 600 * trigger a DB error. 601 */ 602 global $wpdb; 603 $wpdb->suppress_errors = true; 604 add_filter( 'query', array( $this, 'error_delete_query' ) ); 605 606 $response = $this->server->dispatch( $request ); 607 remove_filter( 'query', array( $this, 'error_delete_query' ) ); 608 $wpdb->show_errors = true; 609 610 $this->assertErrorResponse( 'rest_meta_database_error', $response, 500 ); 611 } 612 613 public function test_get_schema() { 614 $request = new WP_REST_Request( 'OPTIONS', sprintf( '/wp/v2/users/%d', self::$user ) ); 615 $response = $this->server->dispatch( $request ); 616 617 $data = $response->get_data(); 618 $schema = $data['schema']; 619 620 $this->assertArrayHasKey( 'meta', $schema['properties'] ); 621 $meta_schema = $schema['properties']['meta']['properties']; 622 623 $this->assertArrayHasKey( 'test_single', $meta_schema ); 624 $this->assertEquals( 'string', $meta_schema['test_single']['type'] ); 625 626 $this->assertArrayHasKey( 'test_multi', $meta_schema ); 627 $this->assertEquals( 'array', $meta_schema['test_multi']['type'] ); 628 $this->assertArrayHasKey( 'items', $meta_schema['test_multi'] ); 629 $this->assertEquals( 'string', $meta_schema['test_multi']['items']['type'] ); 630 631 $this->assertArrayHasKey( 'test_custom_schema', $meta_schema ); 632 $this->assertEquals( 'number', $meta_schema['test_custom_schema']['type'] ); 633 634 $this->assertArrayNotHasKey( 'test_no_rest', $meta_schema ); 635 $this->assertArrayNotHasKey( 'test_rest_disabled', $meta_schema ); 636 $this->assertArrayNotHasKey( 'test_invalid_type', $meta_schema ); 637 } 638 639 /** 640 * Internal function used to disable an insert query which 641 * will trigger a wpdb error for testing purposes. 642 */ 643 public function error_insert_query( $query ) { 644 if ( strpos( $query, 'INSERT' ) === 0 ) { 645 $query = '],'; 646 } 647 return $query; 648 } 649 650 /** 651 * Internal function used to disable an insert query which 652 * will trigger a wpdb error for testing purposes. 653 */ 654 public function error_delete_query( $query ) { 655 if ( strpos( $query, 'DELETE' ) === 0 ) { 656 $query = '],'; 657 } 658 return $query; 659 } 660 }