-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Makes sure a SuperAdministrator can publish on any sites of the network. #3895
Conversation
You're welcome @youknowriad I'm going to improve this PR because, now i've read #2702 i don't think it's the right way to do it. First i've hesitated about the fact it might be related to the REST API. Now my ideas are clearer, i'm pretty sure it's not. I think Gutenberg shouldn't rely on the values that are stored into the database for capabilities. The reason is you can have plugins containing capability mapping. And you won't have this information into the wp_{blog_id}_capabilities meta field. The REST API basically returns the value of this meta field. A better way to handle this imho is to get the post type object capabilities for the post type being edited and to loop in it for the current user checking If you look at the I'll update the PR in this direction. |
Wouldn't this mean that, more broadly than just Gutenberg, the |
Enumerated at #2702 (comment), there are quite a few places we test for capabilities to determine whether something should be rendered. |
Update branch to upstream master
To be sure a user can do a specific cap, you need to use Saving a cap for a specific user is not always done, so yes there's a good chance (and it's more likely to be the case when dealing with custom post types as they can set custom caps / caps mapping) the meta field does not reflect precisely what a user can do. About the User controller of the REST API, i'm not sure its goal is to get what a user can do with a specific post type, but more to get/create/update/delete a user. If it was the case, the post type name would have been one of the available query arguments i think. |
I've updated the PR the way i've explained in this comment. It's fixing the issue i've first met with a SuperAdmin with no role on a child site, it should also fix possible issues for Custom Post Types having custom capabilities. I think it shouldn't need any changes on the JavaScript part, as i kind of map back custom capabilities to post capabilities. |
lib/client-assets.php
Outdated
|
||
$response->set_data( | ||
array( | ||
'capabilities' => $post_type_caps, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really awesome work here Thanks.
As far as I understand, these capabilities are "post type" specific capabilities only. Do you think it makes more sense to use a more descriptive key post_type_capabilties => array( $post_type => $post_type_caps )
to avoid confusion on the client-side?
Granted this means we need to update some client code as well.
Also this raises the question of whether this should be a separate endpoint /users/me/post_type_caps?postType=post
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're very welcome @youknowriad
I agree it makes a lot of sense. As I lack some knowledge of React, I took no risk adventuring myself into this part of Gutenberg's code 😃
As you said, it would require some updates into the client code so that thepost_type_capabilties
are used if available.
About the new endpoint, yes it's a possibility. You can alternatively use a specific query parameter /users/me/?context=edit&post_type=post
and temporarly use the rest_prepare_user
filter to include the post_type_capabilties
into the response before editing the WP_REST_Users_Controller::prepare_item_for_response()
method once Gutenberg is merged into core.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
About the new endpoint, yes it's a possibility. You can alternatively use a specific query parameter /users/me/?context=edit&post_type=post and temporarly use the rest_prepare_user filter to include the post_type_capabilties into the response before editing the WP_REST_Users_Controller::prepare_item_for_response() method once Gutenberg is merged into core.
That sounds like a good solution for now. We'll probably have to bring this issue to the REST API team later. Might be good to have @aduth's insights
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, the client changes should be small enough, I can help with those if necessary ;)
Update branch to latest upstream edits.
…of user. Edit the query parameters used for the users/me endpoint on the server and client side. Merge capabilities with post type capabilities into the client side before checking the user capabilities
Add spaces into inline comments. Add missing "gutenberg" textdomain. Remove quotes in JS object keys.
const userCaps = user.data ? | ||
{ ...user.data.capabilities, ...user.data.post_type_capabilities } : | ||
{ publish_posts: false }; | ||
const isContributor = ! userCaps.publish_posts; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to self: the test is probably failing because i don't test user.data anymore when setting isContributor.
if ( ! user.data || ! user.data.capabilities.publish_posts || authors.length < 2 ) { | ||
const userCaps = user.data ? | ||
{ ...user.data.capabilities, ...user.data.post_type_capabilities } : | ||
{ 'publish_posts': false }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need if this will be always a "post type capability" or not? In which case we coud avoid using user.data.capabilities
entirely?
Minor: maybe we could avoid creating a separate object, by leveraging lodash get
const canPublishPosts = get( user, 'data.post_type_capabilities.publish_posts', false )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, i think we don't need it, i'll update the PR in this direction + thanks for the tip about lodash 👍
return null; | ||
} | ||
|
||
return children; | ||
} | ||
|
||
const applyWithAPIData = withAPIData( () => { | ||
const postTypeSlug = window._wpGutenbergPost.type; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should avoid using the global here, and rely on the getCurrentPostType
selector. Example here
https://github.com/WordPress/gutenberg/blob/master/editor/components/page-attributes/check.js#L32-L51
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your feedback. I've tried to use getCurrentPostType
but unfortunately the Post Type was not defined yet at the time the request was sent. I'll give it another look asap.
I improved the PR the way you advised (use lodash/ stop using the global to get the post type / only use post type capabilities). I still need to update the tests so that they also use the |
I confirm. I just updated tests so that they use |
As 3 days passed and this issue hasn't been updated, I guess i can't do anything more on my side. So I'm leaving you deal with it, hoping the Gutenberg UI will soon be consistent with the Post Type capabilities of a user. Thanks for your consideration and advices. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Speaking to the REST API changes specifically, the post_type_capabilities
property appears at first glance redundant with the existing capabilities
property. It's a bit strange to specify a post type parameter on a user endpoint, though more understandable with the endpoint returning capabilities information.
Curious though, would another option here have been to add an is_super_admin
property to the endpoint to allow all actions?
https://developer.wordpress.org/reference/functions/is_super_admin/
export function PostAuthorCheck( { user, users, children } ) { | ||
const authors = filter( users.data, ( { capabilities } ) => capabilities.level_1 ); | ||
if ( ! user.data || ! user.data.capabilities.publish_posts || authors.length < 2 ) { | ||
const userCanPublishPosts = get( user, 'data.post_type_capabilities.publish_posts', false ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: At one point I'd benchmarked the two different ways to call get
(with .
and as an array) and found the array signature to perform much better, and arguably be more readable:
Also, we could assume that withAPIData
will guarantee that user
will at least be passed as an object, meaning we don't need to guard against access on user
(see also the line prior).
get( user.data, [ 'post_type_capabilities', 'publish_posts' ], false )
lib/client-assets.php
Outdated
// Preload common data. | ||
$preload_paths = array( | ||
'/wp/v2/users/me?context=edit', | ||
sprintf( '/wp/v2/users/me?post_type=%s&context=edit', sanitize_key( $post_type ) ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How did you land on using sanitize_key
? Can custom post type slugs have non-alphanumeric characters?
https://developer.wordpress.org/reference/functions/sanitize_key/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, it's probably my habit to always sanitize when i use sprintf. I'll remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, it's probably my habit to always sanitize when i use sprintf. I'll remove it.
I think sanitization is sensible, just making sure that it aligns with what's permitted when registering a custom post type.
Or, alternatively, should we be running the |
I should probably edit the Title of the PR. It does concerned any user having caps to edit a post type not only the Super Administrator. You can have specific roles in WordPress to edit/publish etc.. a specific custom post type.
Sorry i am not sure to understand. Could you explain in a more detailed way ? |
I mean instead of naively returning ...that we'd iterate through known capabilities and call † Might be a non-negligible performance impact to this. |
Also, the capabilities may change per CPT if I understand properly. So we'll have to loop over the CPTs and enforce a per CPT structure in this case. |
…nberg into try/improved-mobile-tools
…ription Improve paragraph block description.
Try improving mobile controls
Since @aduth is AFK, I don't want to let this PR stale. In opinion, this is good enough to ship. It's certainly not idea to add this A separate endpoint I'd appreciate another review, maybe @mcsf @pento @gziolo before merging. Also, this needs a rebase :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a nice fix; thank you, @imath. As mentioned, this should be rebased.
There's room to smooth the edges (e.g. refactor the common patterns), but we can address that later.
lib/register.php
Outdated
* @param WP_REST_Request $request Full details about the REST API request. | ||
* @return object The Post Type capabilities. | ||
*/ | ||
function gutenberg_get_post_type_capabities( $user, $name, $request ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo at capabities
lib/register.php
Outdated
/** | ||
* Includes the value for the custom field `post_type_capabities` inside the REST API response of user. | ||
* | ||
* TODO: This is a temporary solution. Next step would be to edit theWP_REST_Users_Controller, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing space at theWP_REST_Users_Controller
.
Wondering if we should be grouping these things that are expected to be fixed directly in core. Until then, does this function, as well as the next, make more sense in lib/compat.php
? It might make them more visible.
Rename "Classic Text" to "Classic". Props @jasmussen
3 column inserter
…of user. Edit the query parameters used for the users/me endpoint on the server and client side. Merge capabilities with post type capabilities into the client side before checking the user capabilities
Add spaces into inline comments. Add missing "gutenberg" textdomain. Remove quotes in JS object keys.
Call get using an array to improve performance. Sanitizing the post type slug is not necessary
Fix a missing space in two docblocks Fix a typo in a function name Move temporary functions to lib/compat.php to improve their visibility
These functions are now in lib/compat.php to follow @mcsf recommandations.
@mcsf Hi, yw & thanks a lot for your recommandations, i've applied them and "rebased". As it was the first time i was using this command, i hope i didn't put a mess 😰 |
Mmmm! the rebase look broken :( Might be simpler to copy the code and push another PR? You can probably try cherry-picking the right commits as well? Do you think you can open another PR to fix this? |
@youknowriad i was fearing it, so i saved a diff before 😉 it will be easier for me to create another PR, i think i still need to train to be a good rebaser! I’ll do it tonight (office hours for me!) and i’ll add it to this PR. Sorry for the « contretemps » 😊 |
No worries, Git can be scary sometimes :) |
#3895 showed there was an issue with SuperAdmins not having a role on a site of a multisite network. After some discussions, we think it is best to check the post type capabilities for the connected user and the current post type being edited. A new parameter is added to the users/me REST API route containing the post type name. This parameter is used to get the corresponding post type capabilities. Capability checks have been updated accordingly into Gutenberg editor components
superseded by #4122 |
Description
After preloading the current user from the
/wp/v2/users/me
REST request, a Super Administrator on a site he's not a user of has no caps/roles on it, as a result the major action button is set toSubmit for review
. The changes are making sure a Super Administrator with no caps/roles on the site can publish a post from the Gutenberg editor just like it's the case within the Classic Editor.Steps to reproduce the bug on a multisite configuration
How Has This Been Tested?
I've tested this on a Multisite configuration of WordPress version 5.0-alpha-42125-src
My testing environment: regular macOS HighSierra AMP - PHP 7.1.7
I've checked changes had no effects on the contributor role of the site.
Screenshots (jpeg or gifs if applicable):
Without the patch
With the patch
Types of changes
Bug fix
Checklist: