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
…6529)

* Use `targetSchema` of JSON Hyper Schema to communicate sticky action

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.

* Ensure links are properly formatted

* Avoid re-renders when the current post changes

* Technically more correct test

* Update tests for 3e591c5

* Only include `wp:action-sticky` for `context=edit`; move description

* Move the description text from the targetSchema to the link title. (#6613)
  • Loading branch information
danielbachhuber authored May 7, 2018
1 parent f95b2d5 commit 4dc4c7b
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 46 deletions.
17 changes: 4 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( { hasStickyAction, postType, children } ) {
if (
postType !== 'post' ||
! userCan.publish_posts ||
! userCan.edit_others_posts
! hasStickyAction
) {
return null;
}
Expand All @@ -26,15 +22,10 @@ export function PostStickyCheck( { postType, children, user } ) {

export default compose( [
withSelect( ( select ) => {
const post = select( 'core/editor' ).getCurrentPost();
return {
hasStickyAction: get( post, [ '_links', 'wp:action-sticky' ], false ),
postType: select( 'core/editor' ).getCurrentPostType(),
};
} ),
withAPIData( ( props ) => {
const { postType } = props;

return {
user: `/wp/v2/users/me?post_type=${ postType }&context=edit`,
};
} ),
] )( PostStickyCheck );
39 changes: 6 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,27 @@ 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" hasStickyAction={ true }>
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" hasStickyAction={ false }>
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" hasStickyAction={ true }>
Can Toggle Sticky
</PostStickyCheck>
);
Expand Down
38 changes: 38 additions & 0 deletions lib/rest-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,43 @@ 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 && 'edit' === $request['context'] ) {
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' => __( 'The current user can sticky this post.', 'gutenberg' ),
'href' => $orig_links['self'][0]['href'],
'targetSchema' => array(
'type' => 'object',
'properties' => array(
'sticky' => array(
'type' => 'boolean',
),
),
),
),
);
}
}

$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 +311,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
29 changes: 29 additions & 0 deletions phpunit/class-gutenberg-rest-api-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,35 @@ 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 );
$request->set_param( 'context', 'edit' );
$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 );
$request->set_param( 'context', 'edit' );
$response = rest_do_request( $request );
$links = $response->get_links();
$this->assertTrue( isset( $links[ $check_key ] ) );
// editors can sticky but not included for context != edit.
wp_set_current_user( $this->editor );
$request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . $post_id );
$request->set_param( 'context', 'view' );
$response = rest_do_request( $request );
$links = $response->get_links();
$this->assertFalse( isset( $links[ $check_key ] ) );
}

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

0 comments on commit 4dc4c7b

Please sign in to comment.