WordPress.org

Make WordPress Core

Opened 3 weeks ago

Last modified 4 days ago

#44287 assigned enhancement

REST API: Declare user capability to perform actions using JSON Hyper Schema `targetSchema`

Reported by: danielbachhuber Owned by: pento
Milestone: 4.9.7 Priority: normal
Severity: normal Version:
Component: Role/Capability Keywords: has-patch has-unit-tests commit
Focuses: rest-api Cc:

Description

There are a variety of operations a WordPress user can only perform if they have the correct capabilities. For instance, a WordPress who can create posts can only change authors on the post if they have the edit_others_posts capability.

A REST API client should only display UI for one of these operations if the WordPress user can perform the action. Only editors should see the author dropdown, not authors.

However, user capabilities are evaluated at runtime. The result of current_user_can() can be modified by the map_meta_cap and user_can filters. This means we can't expose capabilities directly, but instead need to expose their computed value.

Fortunately, JSON Hyper Schema targetSchema provides a language for us to communicate this information. To resolve this issue, we'll need to commit a patch prepared from the following pull requests:

From Avoid direct use of user capabilities in client-side code

Attachments (2)

44287.patch (20.0 KB) - added by TimothyBlynJacobs 11 days ago.
44287.1.patch (20.1 KB) - added by TimothyBlynJacobs 6 days ago.

Download all attachments as: .zip

Change History (12)

This ticket was mentioned in Slack in #core-restapi by danielbachhuber. View the logs.


3 weeks ago

#2 @TimothyBlynJacobs
3 weeks ago

So the simplest version of this is using add_link() directly in the controllers and adding all the information inline. For example.

$response->add_link( 'https://api.w.org/action-sticky', $self, array(
        'title'        => __( 'The current user can sticky this post.' ),
        'targetSchema' => array(
                'type'       => 'object',
                'properties' => array(
                        'sticky' => array(
                                'type' => 'boolean',
                        ),
                ),
        ),
) );

A concern here is that we would be duplicating information for every item in collection responses. We can alleviate this by adding the bulk of the link details to the schema document for the resource. For example.

// In ::get_item_schema()
$schema['links'][] = array(
        'rel'          => 'https://api.w.org/action-sticky',
        'title'        => __( 'The current user can sticky this post.' ),
        'href'         => rest_url( '/wp/v2/posts/{id}' ),
        'targetSchema' => array(
                'type'       => 'object',
                'properties' => array(
                        'sticky' => array(
                                'type' => 'boolean',
                        ),
                ),
        ),
);

Then, the response size will be considerably smaller.

$response->add_link( 'https://api.w.org/action-sticky', $self );

#3 @danielbachhuber
3 weeks ago

@TimothyBlynJacobs I love the schema-based implementation. Want the honor of preparing a patch?

#4 @TimothyBlynJacobs
3 weeks ago

Cool! Sure, I'll work on a patch this week.

#5 @TimothyBlynJacobs
11 days ago

  • Keywords has-patch has-unit-tests added; needs-patch needs-unit-tests removed

First pass at a patch.

1) I did some adjusting to the attachments controller to resuse the links definition from the parent response. That way we don't have to repeat ourselves for adding the action links. As far as I can tell, the $post var isn't adjusted during that method to the links generated should always be the same.

2) I wasn't sure of the best way to structure the unit tests. For the most part they are all just in the posts controller tests with some small unit tests in the attachments controller since it has a separate prepare_item_for_response.

3) I made some minor changes to the text from the Gutenberg version, adding the taxonomy name in the description strings. This matches the description for the main schema document.

#6 @danielbachhuber
6 days ago

  • Milestone changed from 4.9.8 to 4.9.7

@TimothyBlynJacobs Looks good! I see a couple small nits to be addressed:

  1. To make get_available_actions() more useful for subclassing, let's pass $request into it too and then perform the 'edit' === $request['context'] check within get_available_actions(). This ensures get_available_actions() always executes, regardless of context context.
  2. We should avoid variable assignment within conditionals.

This:

if ( $schema_links = $this->get_schema_links() )

Should become:

$schema_links = $this->get_schema_links();
if ( $schema_links )

#7 @danielbachhuber
6 days ago

Also, we probably shouldn't include action-publish for attachments, as explicitly changing attachment status isn't really a UI feature we support.

#8 @TimothyBlynJacobs
6 days ago

  1. Makes sense. I'd originally done it to force the links to only be included in the edit context but I can see how it'd be helpful for subclassing to make it more open.
  2. Will do.
  3. Interesting, I'll try blocking the action for attachments in its controller.

Will upload an updated patch shortly.

#9 @TimothyBlynJacobs
6 days ago

@danielbachhuber Updated.

#10 @danielbachhuber
4 days ago

  • Keywords commit added
  • Owner set to pento
  • Status changed from new to assigned

@TimothyBlynJacobs Thanks for updating.

I've tested this patch by:

  1. Applying the patch locally:
grunt patch:https://core.trac.wordpress.org/attachment/ticket/44287/44287.1.patch
grunt build
  1. Disabling Gutenberg's existing shim:
-       add_filter( "rest_prepare_{$post_type}", 'gutenberg_add_target_schema_to_links', 10, 3 );
+       // add_filter( "rest_prepare_{$post_type}", 'gutenberg_add_target_schema_to_links', 10, 3 );
  1. Verifying that the following UI is present when creating a Post as an Administrator:
  • Author
  • Categories
  • Visibility
  • Sticky
  1. Verifying that aforementioned UI isn't present when creating a Post as a Contributor.

I think this is good for commit.

Note: See TracTickets for help on using tickets.