Skip to content

Commit

Permalink
Use targetSchema of JSON Hyper Schema to communicate sticky action
Browse files Browse the repository at this point in the history
Because WordPress' capabilities system is filterable, we need to execute
the capabilities before we know whether the current user can perform the
action. Fortunately, `targetSchema` supports exactly this use-case.
  • Loading branch information
danielbachhuber committed May 1, 2018
1 parent 36233aa commit 18e815f
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 46 deletions.
16 changes: 3 additions & 13 deletions editor/components/post-sticky/check.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,13 @@ import { get } from 'lodash';
/**
* WordPress dependencies
*/
import { withAPIData } from '@wordpress/components';
import { compose } from '@wordpress/element';
import { withSelect } from '@wordpress/data';

export function PostStickyCheck( { postType, children, user } ) {
const userCan = get( user.data, [ 'post_type_capabilities' ], false );

export function PostStickyCheck( { post, postType, children } ) {
if (
postType !== 'post' ||
! userCan.publish_posts ||
! userCan.edit_others_posts
! get( post, [ '_links', 'wp:action-sticky' ], false )
) {
return null;
}
Expand All @@ -27,14 +23,8 @@ export function PostStickyCheck( { postType, children, user } ) {
export default compose( [
withSelect( ( select ) => {
return {
post: select( 'core/editor' ).getCurrentPost(),
postType: select( 'core/editor' ).getCurrentPostType(),
};
} ),
withAPIData( ( props ) => {
const { postType } = props;

return {
user: `/wp/v2/users/me?post_type=${ postType }&context=edit`,
};
} ),
] )( PostStickyCheck );
63 changes: 30 additions & 33 deletions editor/components/post-sticky/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,54 +9,51 @@ import { shallow } from 'enzyme';
import { PostStickyCheck } from '../check';

describe( 'PostSticky', () => {
const user = {
data: {
post_type_capabilities: {
edit_others_posts: true,
publish_posts: true,
},
},
};

it( 'should not render anything if the post type is not "post"', () => {
const wrapper = shallow(
<PostStickyCheck postType="page" user={ user }>
<PostStickyCheck postType="page" post={ {
_links: {
self: {
href: 'https://w.org/wp-json/wp/v2/posts/5',
},
},
title: 'Not a stickyable post',
} }>
Can Toggle Sticky
</PostStickyCheck>
);
expect( wrapper.type() ).toBe( null );
} );

it( 'should not render anything if the user doesn\'t have the right capabilities', () => {
let wrapper = shallow(
<PostStickyCheck postType="post" user={ {} }>
Can Toggle Sticky
</PostStickyCheck>
);
expect( wrapper.type() ).toBe( null );

wrapper = shallow(
<PostStickyCheck postType="post" user={
{ data: { post_type_capabilities: { edit_others_posts: false, publish_posts: true } } }
}>
Can Toggle Sticky
</PostStickyCheck>
);
expect( wrapper.type() ).toBe( null );

wrapper = shallow(
<PostStickyCheck postType="post" user={
{ data: { post_type_capabilities: { edit_others_posts: true, publish_posts: false } } }
}>
it( 'should not render anything if post doesn\'t support stickying', () => {
const wrapper = shallow(
<PostStickyCheck postType="post" post={ {
_links: {
self: {
href: 'https://w.org/wp-json/wp/v2/posts/5',
},
},
title: 'Not a stickyable post',
} }>
Can Toggle Sticky
</PostStickyCheck>
);
expect( wrapper.type() ).toBe( null );
} );

it( 'should render if the user has the correct capability', () => {
it( 'should render if the post supports stickying', () => {
const wrapper = shallow(
<PostStickyCheck postType="post" user={ user }>
<PostStickyCheck postType="post" post={ {
_links: {
self: {
href: 'https://w.org/wp-json/wp/v2/posts/5',
},
'wp:action-sticky': {
href: 'https://w.org/wp-json/wp/v2/posts/5',
},
},
title: 'A stickyable post',
} }>
Can Toggle Sticky
</PostStickyCheck>
);
Expand Down
39 changes: 39 additions & 0 deletions lib/rest-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,44 @@ function gutenberg_add_block_format_to_post_content( $response, $post, $request
return $response;
}

/**
* Include target schema attributes to links, based on whether the user can.
*
* @param WP_REST_Response $response WP REST API response of a post.
* @param WP_Post $post The post being returned.
* @param WP_REST_Request $request WP REST API request.
* @return WP_REST_Response Response containing the new links.
*/
function gutenberg_add_target_schema_to_links( $response, $post, $request ) {
$new_links = array();
$orig_links = $response->get_links();
$post_type = get_post_type_object( $post->post_type );
// Only Posts can be sticky.
if ( 'post' === $post->post_type ) {
if ( current_user_can( $post_type->cap->edit_others_posts )
&& current_user_can( $post_type->cap->publish_posts ) ) {
$new_links['https://api.w.org/action-sticky'] = array(
array(
'title' => __( 'Sticky Post', 'gutenberg' ),
'href' => $orig_links['self'][0]['href'],
'targetSchema' => array(
'type' => 'object',
'properties' => array(
'sticky' => array(
'type' => 'boolean',
'description' => __( 'Whether or not the object should be treated as sticky.', 'gutenberg' ),
),
),
),
),
);
}
}

$response->add_links( $new_links );
return $response;
}

/**
* Whenever a post type is registered, ensure we're hooked into it's WP REST API response.
*
Expand All @@ -274,6 +312,7 @@ function gutenberg_add_block_format_to_post_content( $response, $post, $request
function gutenberg_register_post_prepare_functions( $post_type ) {
add_filter( "rest_prepare_{$post_type}", 'gutenberg_add_permalink_template_to_posts', 10, 3 );
add_filter( "rest_prepare_{$post_type}", 'gutenberg_add_block_format_to_post_content', 10, 3 );
add_filter( "rest_prepare_{$post_type}", 'gutenberg_add_target_schema_to_links', 10, 3 );
return $post_type;
}
add_filter( 'registered_post_type', 'gutenberg_register_post_prepare_functions' );
Expand Down
20 changes: 20 additions & 0 deletions phpunit/class-gutenberg-rest-api-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,26 @@ function test_viewable_field_without_context() {
$this->assertFalse( isset( $result['viewable'] ) );
}

/**
* Only returns wp:action-sticky when current user can sticky.
*/
function test_link_sticky_only_appears_for_editor() {
$post_id = $this->factory->post->create();
$check_key = 'https://api.w.org/action-sticky';
// authors cannot sticky.
wp_set_current_user( $this->author );
$request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . $post_id );
$response = rest_do_request( $request );
$links = $response->get_links();
$this->assertFalse( isset( $links[ $check_key ] ) );
// editors can sticky.
wp_set_current_user( $this->editor );
$request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . $post_id );
$response = rest_do_request( $request );
$links = $response->get_links();
$this->assertTrue( isset( $links[ $check_key ] ) );
}

/**
* Should include relevant data in the 'theme_supports' key of index.
*/
Expand Down

0 comments on commit 18e815f

Please sign in to comment.