-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Fix: the trash post action doesn't take into account user capabilities. #62589
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ | |
*/ | ||
import { external, trash, backup } from '@wordpress/icons'; | ||
import { addQueryArgs } from '@wordpress/url'; | ||
import { useDispatch, useSelect } from '@wordpress/data'; | ||
import { useDispatch, useSelect, useRegistry } from '@wordpress/data'; | ||
import { decodeEntities } from '@wordpress/html-entities'; | ||
import { store as coreStore } from '@wordpress/core-data'; | ||
import { __, _n, sprintf, _x } from '@wordpress/i18n'; | ||
|
@@ -307,6 +307,37 @@ const trashPostAction = { | |
}, | ||
}; | ||
|
||
function useTrashPostAction( postType ) { | ||
const registry = useRegistry(); | ||
const { resource, cachedCanUserResolvers } = useSelect( | ||
( select ) => { | ||
const { getPostType, getCachedResolvers } = select( coreStore ); | ||
return { | ||
resource: getPostType( postType )?.rest_base || '', | ||
cachedCanUserResolvers: getCachedResolvers().canUser, | ||
}; | ||
}, | ||
[ postType ] | ||
); | ||
return useMemo( | ||
() => ( { | ||
...trashPostAction, | ||
isEligible( item ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem is that the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, maybe we need something like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Related discussion #62505 (comment) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It will because we make the memo depend on canUserResolvers (details in #62589 (comment)) so when the resolver finishes a rerender happens and isEligible will be recalled. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤨 seems fine for now but not ideal There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's very hard to follow. I'm not sure I understand what There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. canUserResolvers is the result getCachedResolvers().canUser. So basically when there is a change in the caching of canUser resolvers we will rerender making isEligible recalled. I will add some inline comments, explaining what we discussed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also why keeping the action as object just to be used inside the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ntsekouras I did that to minimise the diff, it was huge and unclear what changed + less likely to have cherry pick conflicts, and if it does, easier to resolve manually (I don't know what has changed in these files recently) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And it's useful for reusability #62754 (comment) |
||
return ( | ||
trashPostAction.isEligible( item ) && | ||
registry | ||
.select( coreStore ) | ||
.canUser( 'delete', resource, item.id ) | ||
); | ||
}, | ||
} ), | ||
// We are making this use memo depend on cachedCanUserResolvers as a way to make the component using this hook re-render | ||
// when user capabilities are resolved. This makes sure the isEligible function is re-evaluated. | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
[ registry, resource, cachedCanUserResolvers ] | ||
); | ||
} | ||
|
||
const permanentlyDeletePostAction = { | ||
id: 'permanently-delete', | ||
label: __( 'Permanently delete' ), | ||
|
@@ -1020,6 +1051,7 @@ export function usePostActions( { postType, onActionPerformed, context } ) { | |
); | ||
|
||
const duplicatePostAction = useDuplicatePostAction( postType ); | ||
const trashPostActionForPostType = useTrashPostAction( postType ); | ||
const isTemplateOrTemplatePart = [ | ||
TEMPLATE_POST_TYPE, | ||
TEMPLATE_PART_POST_TYPE, | ||
|
@@ -1048,7 +1080,7 @@ export function usePostActions( { postType, onActionPerformed, context } ) { | |
isTemplateOrTemplatePart ? resetTemplateAction : restorePostAction, | ||
isTemplateOrTemplatePart || isPattern | ||
? deletePostAction | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't we need the same for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, we need the same for some other actions, my plan was to define the fix here and after we agree on a fix I will replicate it to the other cases where it makes sense. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tested with the testing instructions, and it seems to be the same capability: I can also not delete it permanently in trunk. |
||
: trashPostAction, | ||
: trashPostActionForPostType, | ||
! isTemplateOrTemplatePart && permanentlyDeletePostAction, | ||
...defaultActions, | ||
].filter( Boolean ); | ||
|
@@ -1113,6 +1145,7 @@ export function usePostActions( { postType, onActionPerformed, context } ) { | |
isPattern, | ||
postTypeObject?.viewable, | ||
duplicatePostAction, | ||
trashPostActionForPostType, | ||
onActionPerformed, | ||
isLoaded, | ||
supportsRevisions, | ||
|
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.
I don't like where this is going. I understand why this was done but I like to think actions should be global objects that don't require a hook to define them. This is going in the opposite direction of all my extensibility PRs.
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.
Hi @youknowriad, this seems important to address on WP 6.6, we will be showing the trash button on the post editor on posts a user has no permission to trash, which is a considerable regression. As of right now there is no reliable way to fix the issue without using a hook, as soon as our APIs allow it and we can fix the issue without using a hook I'm happy to iterate and remove the hook here.
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.
Indeed 6.6 is close, so I'm totally fine with this fix for 6.6 but we should definitely look at better APIs for actions after that.