Skip to content
This repository was archived by the owner on Sep 24, 2018. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions lib/endpoints/class-wp-rest-users-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public function register_routes() {
),
) ),
),
'schema' => $this->get_item_schema(),
) );
register_rest_route( 'wp/v2', '/users/(?P<id>[\d]+)', array(
array(
Expand Down Expand Up @@ -56,6 +57,7 @@ public function register_routes() {
'reassign' => array(),
),
),
'schema' => $this->get_item_schema(),
) );

register_rest_route( 'wp/v2', '/users/me', array(
Expand All @@ -64,12 +66,9 @@ public function register_routes() {
'args' => array(
'context' => array(),
),
'schema' => $this->get_item_schema(),
));

register_rest_route( 'wp/v2', '/users/schema', array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_item_schema' ),
) );
}

/**
Expand Down Expand Up @@ -326,7 +325,7 @@ public function delete_item( $request ) {
if ( ! $result ) {
return new WP_Error( 'rest_cannot_delete', __( 'The user cannot be deleted.' ), array( 'status' => 500 ) );
}

return $orig_user;
}

Expand Down
17 changes: 17 additions & 0 deletions lib/infrastructure/class-wp-rest-server.php
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,23 @@ public function get_namespaces() {
return array_keys( $this->namespaces );
}

/**
* Get options specified at the route-level.
*
* This is typically things like the schema, which relates to the resource
* rather than any endpoint callback in particular.
*
* @param string $route Route to fetch options for.
* @return array|null Options map if set, otherwise null.
*/
public function get_route_options( $route ) {
if ( isset( $this->route_options[ $route ] ) ) {
return $this->route_options[ $route ];
}

return null;
}

/**
* Match the request to a callback and call it
*
Expand Down
34 changes: 34 additions & 0 deletions plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,10 @@ function rest_handle_options_request( $response, $handler, $request ) {
$response = new WP_REST_Response();

$accept = array();
$body = array(
'args' => array(),
'schema' => null,
);

foreach ( $handler->get_routes() as $route => $endpoints ) {
$match = preg_match( '@^' . $route . '$@i', $request->get_route(), $args );
Expand All @@ -582,14 +586,44 @@ function rest_handle_options_request( $response, $handler, $request ) {
continue;
}

$opts = $handler->get_route_options( $route );
if ( isset( $opts['schema'] ) ) {
$body['schema'] = $opts['schema'];
}

foreach ( $endpoints as $endpoint ) {
$accept = array_merge( $accept, $endpoint['methods'] );

$methods = array_keys( $endpoint['methods'] );
$method = array_shift( $methods );
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are endpoints registered in this format?

'methods' =>
    array (
      'DELETE' => true,
    ),

When would a method be false, or an endpoint registered supporting two methods?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mainly this was so it's a constant-time lookup internally in dispatch. Endpoints often support more than one method as well, all EDITABLE supports POST, PUT, and PATCH.


$args = array();
if ( ! empty( $endpoint['args'] ) ) {
foreach ( $endpoint['args'] as $key => $arg_opts ) {
$args[ $key ] = (object) array();

if ( isset( $arg_opts['description'] ) ) {
$args[ $key ]->description = $arg_opts['description'];
}

if ( isset( $arg_opts['type'] ) ) {
$args[ $key ]->type = $arg_opts['type'];
}

if ( isset( $arg_opts['default'] ) ) {
$args[ $key ]->default = $arg_opts['default'];
}
}
}

$body['args'][ $method ] = $args;
}
break;
}
$accept = array_keys( $accept );

$response->header( 'Accept', implode( ', ', $accept ) );
$response->set_data( (object) $body );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this cast to an object? Pretty much everything else return an array / ArrayAccess

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because I want to make sure it's always an object, even when empty. Otherwise it will be an array when empty.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh. Derp. I guess it was empty at one point, and then I changed my code.


return $response;
}
Expand Down
25 changes: 17 additions & 8 deletions tests/test-rest-users-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -714,12 +714,17 @@ public function test_delete_user_invalid_reassign_id() {
$this->assertErrorResponse( 'rest_user_invalid_reassign', $response, 400 );
}

public function test_get_item_schema() {
$request = new WP_REST_Request( 'GET', '/wp/v2/users/schema' );
public function test_options_request() {

$request = new WP_REST_Request( 'OPTIONS', '/wp/v2/users' );
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you did OPTIONS /wp/v2/users/1, would you expect to get the same?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joehoyle thoughts on ^^

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird, thought I added a comment. Yes, though not quite the same, I'd expect to get the get / update / delete request arguments, as opposed to get / create.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I think I have enough to wrap this up now.

$response = $this->server->dispatch( $request );
$data = $response->get_data();
$properties = $data['properties'];

$this->assertArrayHasKey( 'GET', $data['request_args'] );
$this->assertArrayHasKey( 'POST', $data['request_args'] );
$this->assertArrayNotHasKey( 'DELETE', $data['request_args'] );

$properties = $data['schema']['properties'];
$this->assertEquals( 16, count( $properties ) );
$this->assertArrayHasKey( 'avatar_url', $properties );
$this->assertArrayHasKey( 'capabilities', $properties );
Expand All @@ -736,10 +741,14 @@ public function test_get_item_schema() {
$this->assertArrayHasKey( 'slug', $properties );
$this->assertArrayHasKey( 'url', $properties );
$this->assertArrayHasKey( 'username', $properties );

}

public function test_get_additional_field_registration() {
public function test_get_item_schema() {
/** Legacy while other controllers are converted over **/
}

public function test_get_additional_field_registration() {
$schema = array(
'type' => 'integer',
'description' => 'Some integer of mine',
Expand Down Expand Up @@ -816,10 +825,10 @@ protected function check_user_data( $user, $data, $context ) {
$this->assertEquals( get_author_posts_url( $user->ID ), $data['link'] );

if ( 'view' === $context || 'edit' === $context ) {
$this->assertEquals( $user->first_name, $data['first_name'] );
$this->assertEquals( $user->last_name, $data['last_name'] );
$this->assertEquals( $user->nickname, $data['nickname'] );
$this->assertEquals( $user->user_nicename, $data['slug'] );
$this->assertEquals( $user->first_name, $data['first_name'] );
$this->assertEquals( $user->last_name, $data['last_name'] );
$this->assertEquals( $user->nickname, $data['nickname'] );
$this->assertEquals( $user->user_nicename, $data['slug'] );
}

if ( 'view' !== $context && 'edit' !== $context ) {
Expand Down