-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Patterns: fix capabilities settings for pattern categories (#55379)
Co-authored-by: Daniel Richards <daniel.richards@automattic.com>
- Loading branch information
1 parent
687cb22
commit 6f83c92
Showing
13 changed files
with
482 additions
and
95 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
lib/compat/wordpress-6.4/class-gutenberg-rest-blocks-controller-6-4.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
<?php | ||
/** | ||
* Reusable blocks REST API: WP_REST_Blocks_Controller class | ||
* | ||
* @package WordPress | ||
* @subpackage REST_API | ||
* @since 5.0.0 | ||
*/ | ||
|
||
/** | ||
* Controller which provides a REST endpoint for the editor to read, create, | ||
* edit and delete reusable blocks. Blocks are stored as posts with the wp_block | ||
* post type. | ||
* | ||
* @since 5.0.0 | ||
* | ||
* @see WP_REST_Posts_Controller | ||
* @see WP_REST_Controller | ||
*/ | ||
class Gutenberg_REST_Blocks_Controller_6_4 extends Gutenberg_REST_Blocks_Controller { | ||
/** | ||
* Gets the link relations available for the post and current user. | ||
* | ||
* @since 6.4.0 Ensures that only users with `edit_terms` capability can add taxonomy terms. | ||
* | ||
* @param WP_Post $post Post object. | ||
* @param WP_REST_Request $request Request object. | ||
* @return array List of link relations. | ||
*/ | ||
protected function get_available_actions( $post, $request ) { | ||
if ( 'edit' !== $request['context'] ) { | ||
return array(); | ||
} | ||
|
||
$rels = array(); | ||
|
||
$post_type = get_post_type_object( $post->post_type ); | ||
|
||
if ( 'attachment' !== $this->post_type && current_user_can( $post_type->cap->publish_posts ) ) { | ||
$rels[] = 'https://api.w.org/action-publish'; | ||
} | ||
|
||
if ( current_user_can( 'unfiltered_html' ) ) { | ||
$rels[] = 'https://api.w.org/action-unfiltered-html'; | ||
} | ||
|
||
if ( 'post' === $post_type->name ) { | ||
if ( current_user_can( $post_type->cap->edit_others_posts ) && current_user_can( $post_type->cap->publish_posts ) ) { | ||
$rels[] = 'https://api.w.org/action-sticky'; | ||
} | ||
} | ||
|
||
if ( post_type_supports( $post_type->name, 'author' ) ) { | ||
if ( current_user_can( $post_type->cap->edit_others_posts ) ) { | ||
$rels[] = 'https://api.w.org/action-assign-author'; | ||
} | ||
} | ||
|
||
$taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) ); | ||
|
||
foreach ( $taxonomies as $tax ) { | ||
$tax_base = ! empty( $tax->rest_base ) ? $tax->rest_base : $tax->name; | ||
|
||
if ( current_user_can( $tax->cap->edit_terms ) ) { | ||
$rels[] = 'https://api.w.org/action-create-' . $tax_base; | ||
} | ||
|
||
if ( current_user_can( $tax->cap->assign_terms ) ) { | ||
$rels[] = 'https://api.w.org/action-assign-' . $tax_base; | ||
} | ||
} | ||
|
||
return $rels; | ||
} | ||
} |
45 changes: 45 additions & 0 deletions
45
lib/compat/wordpress-6.4/class-gutenberg-rest-pattern-categories-controller.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
<?php | ||
/** | ||
* Gutenberg_REST_Pattern_Categories_Controller class | ||
* | ||
* Extends the WP_REST_Terms_Controller to handle permissions of pattern categories. | ||
* | ||
* @package Gutenberg | ||
* @subpackage REST_API | ||
* @since 6.4.0 | ||
*/ | ||
|
||
/** | ||
* Extends the WP_REST_Terms_Controller to handle permissions of pattern categories. | ||
* | ||
* @access public | ||
*/ | ||
class Gutenberg_REST_Pattern_Categories_Controller extends WP_REST_Terms_Controller { | ||
/** | ||
* Make pattern categories behave more like a hierarchical taxonomy in terms of permissions. | ||
* Check the edit_terms cap to see whether term creation is possible. | ||
* | ||
* @since 6.4.0 | ||
* | ||
* @param WP_REST_Request $request Request object. | ||
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. | ||
*/ | ||
public function create_item_permissions_check( $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable | ||
if ( ! $this->check_is_taxonomy_allowed( $this->taxonomy ) ) { | ||
return false; | ||
} | ||
|
||
$taxonomy_obj = get_taxonomy( $this->taxonomy ); | ||
|
||
// Patterns categories are a flat hierarchy (like tags), but work more like post categories in terms of permissions. | ||
if ( ! current_user_can( $taxonomy_obj->cap->edit_terms ) ) { | ||
return new WP_Error( | ||
'rest_cannot_create', | ||
__( 'Sorry, you are not allowed to create terms in this taxonomy.' ), | ||
array( 'status' => rest_authorization_required_code() ) | ||
); | ||
} | ||
|
||
return true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
119 changes: 119 additions & 0 deletions
119
packages/editor/src/components/post-taxonomies/pattern-categories-selector.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { useSelect, useDispatch } from '@wordpress/data'; | ||
import { store as coreStore } from '@wordpress/core-data'; | ||
import { addFilter } from '@wordpress/hooks'; | ||
import { privateApis as patternsPrivateApis } from '@wordpress/patterns'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { unlock } from '../../lock-unlock'; | ||
import { store as editorStore } from '../../store'; | ||
|
||
const { CategorySelector } = unlock( patternsPrivateApis ); | ||
|
||
const EMPTY_ARRAY = []; | ||
|
||
const DEFAULT_QUERY = { | ||
per_page: -1, | ||
orderby: 'name', | ||
order: 'asc', | ||
_fields: 'id,name,parent', | ||
context: 'view', | ||
}; | ||
|
||
/* | ||
* Pattern categories are a flat taxonomy but do not allow Author users and below to create | ||
* new categories, so this selector overrides the default flat taxonomy selector for | ||
* wp_block post types and users without 'create' capability for wp_pattern_category. | ||
*/ | ||
export function PatternCategoriesSelector( { slug } ) { | ||
const { hasAssignAction, terms, availableTerms, taxonomy, loading } = | ||
useSelect( | ||
( select ) => { | ||
const { getCurrentPost, getEditedPostAttribute } = | ||
select( editorStore ); | ||
const { getTaxonomy, getEntityRecords, isResolving } = | ||
select( coreStore ); | ||
const _taxonomy = getTaxonomy( slug ); | ||
const post = getCurrentPost(); | ||
|
||
return { | ||
hasAssignAction: _taxonomy | ||
? post._links?.[ | ||
'wp:action-assign-' + _taxonomy.rest_base | ||
] ?? false | ||
: false, | ||
terms: _taxonomy | ||
? getEditedPostAttribute( _taxonomy.rest_base ) | ||
: EMPTY_ARRAY, | ||
loading: isResolving( 'getEntityRecords', [ | ||
'taxonomy', | ||
slug, | ||
DEFAULT_QUERY, | ||
] ), | ||
availableTerms: | ||
getEntityRecords( 'taxonomy', slug, DEFAULT_QUERY ) || | ||
EMPTY_ARRAY, | ||
taxonomy: _taxonomy, | ||
}; | ||
}, | ||
[ slug ] | ||
); | ||
|
||
const { editPost } = useDispatch( editorStore ); | ||
|
||
if ( ! hasAssignAction || loading || availableTerms.length === 0 ) { | ||
return null; | ||
} | ||
|
||
const onUpdateTerms = ( termIds ) => { | ||
editPost( { [ taxonomy.rest_base ]: termIds } ); | ||
}; | ||
|
||
const onChange = ( term ) => { | ||
const hasTerm = terms.includes( term.id ); | ||
const newTerms = hasTerm | ||
? terms.filter( ( id ) => id !== term.id ) | ||
: [ ...terms, term.id ]; | ||
onUpdateTerms( newTerms ); | ||
}; | ||
|
||
const isCategorySelected = ( term ) => terms.includes( term.id ); | ||
|
||
const categoryOptions = availableTerms.map( ( term ) => ( { | ||
...term, | ||
label: term.name, | ||
} ) ); | ||
|
||
return ( | ||
<CategorySelector | ||
onChange={ onChange } | ||
categoryOptions={ categoryOptions } | ||
isCategorySelected={ isCategorySelected } | ||
showLabel={ false } | ||
/> | ||
); | ||
} | ||
|
||
export default function patternCategorySelector( OriginalComponent ) { | ||
return function ( props ) { | ||
const canAddCategories = useSelect( ( select ) => { | ||
const { canUser } = select( coreStore ); | ||
return canUser( 'create', 'wp_pattern_category' ); | ||
} ); | ||
if ( props.slug === 'wp_pattern_category' && ! canAddCategories ) { | ||
return <PatternCategoriesSelector { ...props } />; | ||
} | ||
|
||
return <OriginalComponent { ...props } />; | ||
}; | ||
} | ||
|
||
addFilter( | ||
'editor.PostTaxonomyType', | ||
'core/pattern-category-selector', | ||
patternCategorySelector | ||
); |
Oops, something went wrong.