REST API: Support meta registration for specific object subtypes.

Introduce an `object_subtype` argument to the args array for `register_meta()` which can be used to limit meta registration to a single subtype (e.g. a custom post type or taxonomy, vs all posts or taxonomies).

Introduce `register_post_meta()` and `register_term_meta()` wrapper methods for `register_meta` to provide a convenient interface for the common case of registering meta for a specific taxonomy or post type. These methods work the way plugin developers have often expected `register_meta` to function, and should be used in place of direct `register_meta` where possible.

Props flixos90, tharsheblows, spacedmonkey.
Fixes #38323.



git-svn-id: https://develop.svn.wordpress.org/trunk@43378 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
K. Adam White
2018-06-21 21:06:50 +00:00
parent cdd9910f01
commit a830dbcab3
14 changed files with 1042 additions and 164 deletions

View File

@@ -12,15 +12,25 @@
class WP_Test_REST_Post_Meta_Fields extends WP_Test_REST_TestCase {
protected static $wp_meta_keys_saved;
protected static $post_id;
protected static $cpt_post_id;
public static function wpSetUpBeforeClass( $factory ) {
register_post_type( 'cpt', array(
'show_in_rest' => true,
'supports' => array( 'custom-fields' ),
) );
self::$wp_meta_keys_saved = isset( $GLOBALS['wp_meta_keys'] ) ? $GLOBALS['wp_meta_keys'] : array();
self::$post_id = $factory->post->create();
self::$cpt_post_id = $factory->post->create( array( 'post_type' => 'cpt' ) );
}
public static function wpTearDownAfterClass() {
$GLOBALS['wp_meta_keys'] = self::$wp_meta_keys_saved;
wp_delete_post( self::$post_id, true );
wp_delete_post( self::$cpt_post_id, true );
unregister_post_type( 'cpt' );
}
public function setUp() {
@@ -120,6 +130,28 @@ class WP_Test_REST_Post_Meta_Fields extends WP_Test_REST_TestCase {
)
);
register_post_type( 'cpt', array(
'show_in_rest' => true,
'supports' => array( 'custom-fields' ),
) );
register_post_meta( 'cpt', 'test_cpt_single', array(
'show_in_rest' => true,
'single' => true,
) );
register_post_meta( 'cpt', 'test_cpt_multi', array(
'show_in_rest' => true,
'single' => false,
) );
// Register 'test_single' on subtype to override for bad auth.
register_post_meta( 'cpt', 'test_single', array(
'show_in_rest' => true,
'single' => true,
'auth_callback' => '__return_false',
) );
/** @var WP_REST_Server $wp_rest_server */
global $wp_rest_server;
$wp_rest_server = new Spy_REST_Server;
@@ -1047,6 +1079,126 @@ class WP_Test_REST_Post_Meta_Fields extends WP_Test_REST_TestCase {
$this->assertArrayNotHasKey( 'test_no_type', $meta_schema );
}
/**
* @ticket 38323
* @dataProvider data_get_subtype_meta_value
*/
public function test_get_subtype_meta_value( $post_type, $meta_key, $single, $in_post_type ) {
$post_id = self::$post_id;
$endpoint = 'posts';
if ( 'cpt' === $post_type ) {
$post_id = self::$cpt_post_id;
$endpoint = 'cpt';
}
$meta_value = 'testvalue';
add_post_meta( $post_id, $meta_key, $meta_value );
$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/%s/%d', $endpoint, $post_id ) );
$response = rest_get_server()->dispatch( $request );
$this->assertEquals( 200, $response->get_status() );
$data = $response->get_data();
$this->assertArrayHasKey( 'meta', $data );
$this->assertInternalType( 'array', $data['meta'] );
if ( $in_post_type ) {
$expected_value = $meta_value;
if ( ! $single ) {
$expected_value = array( $expected_value );
}
$this->assertArrayHasKey( $meta_key, $data['meta'] );
$this->assertEquals( $expected_value, $data['meta'][ $meta_key ] );
} else {
$this->assertArrayNotHasKey( $meta_key, $data['meta'] );
}
}
public function data_get_subtype_meta_value() {
return array(
array( 'cpt', 'test_cpt_single', true, true ),
array( 'cpt', 'test_cpt_multi', false, true ),
array( 'cpt', 'test_single', true, true ),
array( 'cpt', 'test_multi', false, true ),
array( 'post', 'test_cpt_single', true, false ),
array( 'post', 'test_cpt_multi', false, false ),
array( 'post', 'test_single', true, true ),
array( 'post', 'test_multi', false, true ),
);
}
/**
* @ticket 38323
* @dataProvider data_set_subtype_meta_value
*/
public function test_set_subtype_meta_value( $post_type, $meta_key, $single, $in_post_type, $can_write ) {
$post_id = self::$post_id;
$endpoint = 'posts';
if ( 'cpt' === $post_type ) {
$post_id = self::$cpt_post_id;
$endpoint = 'cpt';
}
$meta_value = 'value_to_set';
$this->grant_write_permission();
$request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/%s/%d', $endpoint, $post_id ) );
$request->set_body_params( array(
'meta' => array(
$meta_key => $meta_value,
),
) );
$response = rest_get_server()->dispatch( $request );
if ( ! $can_write ) {
$this->assertEquals( 403, $response->get_status() );
$this->assertEmpty( get_post_meta( $post_id, $meta_key, $single ) );
return;
}
$this->assertEquals( 200, $response->get_status() );
$data = $response->get_data();
$this->assertArrayHasKey( 'meta', $data );
$this->assertInternalType( 'array', $data['meta'] );
if ( $in_post_type ) {
$expected_value = $meta_value;
if ( ! $single ) {
$expected_value = array( $expected_value );
}
$this->assertEquals( $expected_value, get_post_meta( $post_id, $meta_key, $single ) );
$this->assertArrayHasKey( $meta_key, $data['meta'] );
$this->assertEquals( $expected_value, $data['meta'][ $meta_key ] );
} else {
$this->assertEmpty( get_post_meta( $post_id, $meta_key, $single ) );
$this->assertArrayNotHasKey( $meta_key, $data['meta'] );
}
}
public function data_set_subtype_meta_value() {
$data = $this->data_get_subtype_meta_value();
foreach ( $data as $index => $dataset ) {
$can_write = true;
// This combination is not writable because of an auth callback of '__return_false'.
if ( 'cpt' === $dataset[0] && 'test_single' === $dataset[1] ) {
$can_write = false;
}
$data[ $index ][] = $can_write;
}
return $data;
}
/**
* Internal function used to disable an insert query which
* will trigger a wpdb error for testing purposes.

View File

@@ -12,15 +12,24 @@
class WP_Test_REST_Term_Meta_Fields extends WP_Test_REST_TestCase {
protected static $wp_meta_keys_saved;
protected static $category_id;
protected static $customtax_term_id;
public static function wpSetUpBeforeClass( $factory ) {
register_taxonomy( 'customtax', 'post', array(
'show_in_rest' => true,
) );
self::$wp_meta_keys_saved = isset( $GLOBALS['wp_meta_keys'] ) ? $GLOBALS['wp_meta_keys'] : array();
self::$category_id = $factory->category->create();
self::$customtax_term_id = $factory->term->create( array( 'taxonomy' => 'customtax' ) );
}
public static function wpTearDownAfterClass() {
$GLOBALS['wp_meta_keys'] = self::$wp_meta_keys_saved;
wp_delete_term( self::$category_id, 'category' );
wp_delete_term( self::$customtax_term_id, 'customtax' );
unregister_taxonomy( 'customtax' );
}
public function setUp() {
@@ -120,6 +129,27 @@ class WP_Test_REST_Term_Meta_Fields extends WP_Test_REST_TestCase {
)
);
register_taxonomy( 'customtax', 'post', array(
'show_in_rest' => true,
) );
register_term_meta( 'customtax', 'test_customtax_single', array(
'show_in_rest' => true,
'single' => true,
) );
register_term_meta( 'customtax', 'test_customtax_multi', array(
'show_in_rest' => true,
'single' => false,
) );
// Register 'test_single' on subtype to override for bad auth.
register_term_meta( 'customtax', 'test_single', array(
'show_in_rest' => true,
'single' => true,
'auth_callback' => '__return_false',
) );
/** @var WP_REST_Server $wp_rest_server */
global $wp_rest_server;
$wp_rest_server = new Spy_REST_Server;
@@ -1047,6 +1077,126 @@ class WP_Test_REST_Term_Meta_Fields extends WP_Test_REST_TestCase {
$this->assertArrayNotHasKey( 'test_no_type', $meta_schema );
}
/**
* @ticket 38323
* @dataProvider data_get_subtype_meta_value
*/
public function test_get_subtype_meta_value( $taxonomy, $meta_key, $single, $in_taxonomy ) {
$term_id = self::$category_id;
$endpoint = 'categories';
if ( 'customtax' === $taxonomy ) {
$term_id = self::$customtax_term_id;
$endpoint = 'customtax';
}
$meta_value = 'testvalue';
add_term_meta( $term_id, $meta_key, $meta_value );
$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/%s/%d', $endpoint, $term_id ) );
$response = rest_get_server()->dispatch( $request );
$this->assertEquals( 200, $response->get_status() );
$data = $response->get_data();
$this->assertArrayHasKey( 'meta', $data );
$this->assertInternalType( 'array', $data['meta'] );
if ( $in_taxonomy ) {
$expected_value = $meta_value;
if ( ! $single ) {
$expected_value = array( $expected_value );
}
$this->assertArrayHasKey( $meta_key, $data['meta'] );
$this->assertEquals( $expected_value, $data['meta'][ $meta_key ] );
} else {
$this->assertArrayNotHasKey( $meta_key, $data['meta'] );
}
}
public function data_get_subtype_meta_value() {
return array(
array( 'customtax', 'test_customtax_single', true, true ),
array( 'customtax', 'test_customtax_multi', false, true ),
array( 'customtax', 'test_single', true, true ),
array( 'customtax', 'test_multi', false, true ),
array( 'category', 'test_customtax_single', true, false ),
array( 'category', 'test_customtax_multi', false, false ),
array( 'category', 'test_single', true, true ),
array( 'category', 'test_multi', false, true ),
);
}
/**
* @ticket 38323
* @dataProvider data_set_subtype_meta_value
*/
public function test_set_subtype_meta_value( $taxonomy, $meta_key, $single, $in_taxonomy, $can_write ) {
$term_id = self::$category_id;
$endpoint = 'categories';
if ( 'customtax' === $taxonomy ) {
$term_id = self::$customtax_term_id;
$endpoint = 'customtax';
}
$meta_value = 'value_to_set';
$this->grant_write_permission();
$request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/%s/%d', $endpoint, $term_id ) );
$request->set_body_params( array(
'meta' => array(
$meta_key => $meta_value,
),
) );
$response = rest_get_server()->dispatch( $request );
if ( ! $can_write ) {
$this->assertEquals( 403, $response->get_status() );
$this->assertEmpty( get_term_meta( $term_id, $meta_key, $single ) );
return;
}
$this->assertEquals( 200, $response->get_status() );
$data = $response->get_data();
$this->assertArrayHasKey( 'meta', $data );
$this->assertInternalType( 'array', $data['meta'] );
if ( $in_taxonomy ) {
$expected_value = $meta_value;
if ( ! $single ) {
$expected_value = array( $expected_value );
}
$this->assertEquals( $expected_value, get_term_meta( $term_id, $meta_key, $single ) );
$this->assertArrayHasKey( $meta_key, $data['meta'] );
$this->assertEquals( $expected_value, $data['meta'][ $meta_key ] );
} else {
$this->assertEmpty( get_term_meta( $term_id, $meta_key, $single ) );
$this->assertArrayNotHasKey( $meta_key, $data['meta'] );
}
}
public function data_set_subtype_meta_value() {
$data = $this->data_get_subtype_meta_value();
foreach ( $data as $index => $dataset ) {
$can_write = true;
// This combination is not writable because of an auth callback of '__return_false'.
if ( 'customtax' === $dataset[0] && 'test_single' === $dataset[1] ) {
$can_write = false;
}
$data[ $index ][] = $can_write;
}
return $data;
}
/**
* Internal function used to disable an insert query which
* will trigger a wpdb error for testing purposes.