From 1177a58ee0f5d8d0dc661ac6aff7231296e07097 Mon Sep 17 00:00:00 2001 From: ramon Date: Thu, 5 Sep 2024 13:17:11 +1000 Subject: [PATCH] A test to allow view context for global styles GET request Preloads the global styles CPT without edit via filter Check canUser capabilities according to the capabilities set in the CPT wp_global_styles --- ...est-global-styles-controller-gutenberg.php | 19 +---- lib/compat/wordpress-6.6/rest-api.php | 1 - lib/compat/wordpress-6.7/rest-api.php | 37 ++++++++- packages/core-data/src/resolvers.js | 4 +- .../global-styles-provider/index.js | 80 +++++++++++++------ 5 files changed, 95 insertions(+), 46 deletions(-) diff --git a/lib/class-wp-rest-global-styles-controller-gutenberg.php b/lib/class-wp-rest-global-styles-controller-gutenberg.php index 7eb87cf799393..4f349f77dcd81 100644 --- a/lib/class-wp-rest-global-styles-controller-gutenberg.php +++ b/lib/class-wp-rest-global-styles-controller-gutenberg.php @@ -671,23 +671,8 @@ public function get_theme_item( $request ) { * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. */ - public function get_theme_items_permissions_check( $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable - - /* - * Verify if the current user has edit_theme_options capability. - * This capability is required to edit/view/delete templates. - */ - if ( ! current_user_can( 'edit_theme_options' ) ) { - return new WP_Error( - 'rest_cannot_manage_global_styles', - __( 'Sorry, you are not allowed to access the global styles on this site.', 'gutenberg' ), - array( - 'status' => rest_authorization_required_code(), - ) - ); - } - - return true; + public function get_theme_items_permissions_check( $request ) { + return $this->get_theme_item_permissions_check( $request ); } /** diff --git a/lib/compat/wordpress-6.6/rest-api.php b/lib/compat/wordpress-6.6/rest-api.php index aaef8c77c4f57..fee9c71b86c07 100644 --- a/lib/compat/wordpress-6.6/rest-api.php +++ b/lib/compat/wordpress-6.6/rest-api.php @@ -170,7 +170,6 @@ function gutenberg_block_editor_preload_paths_6_6( $paths, $context ) { $paths[] = '/wp/v2/global-styles/themes/' . get_stylesheet(); $paths[] = '/wp/v2/themes?context=edit&status=active'; $paths[] = '/wp/v2/global-styles/' . WP_Theme_JSON_Resolver_Gutenberg::get_user_global_styles_post_id() . '?context=edit'; - $paths[] = '/wp/v2/global-styles/' . WP_Theme_JSON_Resolver_Gutenberg::get_user_global_styles_post_id(); } return $paths; } diff --git a/lib/compat/wordpress-6.7/rest-api.php b/lib/compat/wordpress-6.7/rest-api.php index c5e2927198da0..d43894cdc2773 100644 --- a/lib/compat/wordpress-6.7/rest-api.php +++ b/lib/compat/wordpress-6.7/rest-api.php @@ -48,8 +48,22 @@ function gutenberg_block_editor_preload_paths_6_7( $paths, $context ) { if ( false !== $reusable_blocks_key ) { unset( $paths[ $reusable_blocks_key ] ); } - } + /* + * Removes the `context=edit` query parameter from the global styles preload path added in gutenberg_block_editor_preload_paths_6_6(). + * Uses array_filter because it may have been added again in WordPress Core 6.6 in src/wp-admin/edit-form-blocks.php + * Reason: because GET requests to global styles items are accessible to roles with the `edit_posts` capability. + */ + $global_styles_edit_path = '/wp/v2/global-styles/' . WP_Theme_JSON_Resolver_Gutenberg::get_user_global_styles_post_id() . '?context=edit'; + $paths = array_filter( + $paths, + function ( $value ) use ( $global_styles_edit_path ) { + return $value !== $global_styles_edit_path; + } + ); + + $paths[] = '/wp/v2/global-styles/' . WP_Theme_JSON_Resolver_Gutenberg::get_user_global_styles_post_id(); + } return $paths; } add_filter( 'block_editor_rest_api_preload_paths', 'gutenberg_block_editor_preload_paths_6_7', 10, 2 ); @@ -114,3 +128,24 @@ function gutenberg_override_default_rest_server() { return 'Gutenberg_REST_Server'; } add_filter( 'wp_rest_server_class', 'gutenberg_override_default_rest_server', 1 ); + + +/** + * Filters the arguments for registering a wp_global_styles post type. + * Note when syncing to Core: the capabilities should be updates for `wp_global_styles` in the wp-includes/post.php. + * + * @since 6.7.0 + * + * @param array $args Array of arguments for registering a post type. + * See the register_post_type() function for accepted arguments. + * @param string $post_type Post type key. + */ +function gutenberg_register_post_type_args_for_wp_global_styles( $args, $post_type ) { + if ( $post_type === 'wp_global_styles' ) { + $args['capabilities']['read'] = 'edit_posts'; + } + + return $args; +} + +add_filter( 'register_post_type_args', 'gutenberg_register_post_type_args_for_wp_global_styles', 10, 2 ); diff --git a/packages/core-data/src/resolvers.js b/packages/core-data/src/resolvers.js index 20270ef7f6cff..ca745107ec646 100644 --- a/packages/core-data/src/resolvers.js +++ b/packages/core-data/src/resolvers.js @@ -645,7 +645,7 @@ export const __experimentalGetCurrentThemeBaseGlobalStyles = async ( { resolveSelect, dispatch } ) => { const currentTheme = await resolveSelect.getCurrentTheme(); const themeGlobalStyles = await apiFetch( { - path: `/wp/v2/global-styles/themes/${ currentTheme.stylesheet }`, + path: `/wp/v2/global-styles/themes/${ currentTheme.stylesheet }?context=view`, } ); dispatch.__experimentalReceiveThemeBaseGlobalStyles( currentTheme.stylesheet, @@ -658,7 +658,7 @@ export const __experimentalGetCurrentThemeGlobalStylesVariations = async ( { resolveSelect, dispatch } ) => { const currentTheme = await resolveSelect.getCurrentTheme(); const variations = await apiFetch( { - path: `/wp/v2/global-styles/themes/${ currentTheme.stylesheet }/variations`, + path: `/wp/v2/global-styles/themes/${ currentTheme.stylesheet }/variations?context=view`, } ); dispatch.__experimentalReceiveThemeGlobalStyleVariations( currentTheme.stylesheet, diff --git a/packages/editor/src/components/global-styles-provider/index.js b/packages/editor/src/components/global-styles-provider/index.js index 93dd4dbe1eda4..7e8e7fe556538 100644 --- a/packages/editor/src/components/global-styles-provider/index.js +++ b/packages/editor/src/components/global-styles-provider/index.js @@ -16,6 +16,7 @@ import { useMemo, useCallback } from '@wordpress/element'; * Internal dependencies */ import { unlock } from '../../lock-unlock'; +import { store as editorStore } from '../../store'; const { GlobalStylesContext, cleanEmptyObject } = unlock( blockEditorPrivateApis @@ -46,24 +47,38 @@ export function mergeBaseAndUserConfigs( base, user ) { function useGlobalStylesUserConfig() { const { globalStylesId, isReady, settings, styles, _links } = useSelect( ( select ) => { - const { getEditedEntityRecord, hasFinishedResolution, canUser } = - select( coreStore ); + const { + getEntityRecord, + getEditedEntityRecord, + hasFinishedResolution, + canUser, + } = select( coreStore ); const _globalStylesId = select( coreStore ).__experimentalGetCurrentGlobalStylesId(); - const record = - _globalStylesId && - canUser( 'read', { - kind: 'root', - name: 'globalStyles', - id: _globalStylesId, - } ) - ? getEditedEntityRecord( - 'root', - 'globalStyles', - _globalStylesId - ) - : undefined; + let record; + const userCanEditGlobalStyles = canUser( 'edit', { + kind: 'root', + name: 'globalStyles', + id: _globalStylesId, + } ); + + if ( _globalStylesId ) { + if ( userCanEditGlobalStyles ) { + record = getEditedEntityRecord( + 'root', + 'globalStyles', + _globalStylesId + ); + } else { + record = getEntityRecord( + 'root', + 'globalStyles', + _globalStylesId, + { context: 'view' } + ); + } + } let hasResolved = false; if ( @@ -71,13 +86,22 @@ function useGlobalStylesUserConfig() { '__experimentalGetCurrentGlobalStylesId' ) ) { - hasResolved = _globalStylesId - ? hasFinishedResolution( 'getEditedEntityRecord', [ - 'root', - 'globalStyles', - _globalStylesId, - ] ) - : true; + if ( _globalStylesId ) { + hasResolved = userCanEditGlobalStyles + ? hasFinishedResolution( 'getEditedEntityRecord', [ + 'root', + 'globalStyles', + _globalStylesId, + ] ) + : hasFinishedResolution( 'getEntityRecord', [ + 'root', + 'globalStyles', + _globalStylesId, + { context: 'view' }, + ] ); + } else { + hasResolved = true; + } } return { @@ -146,10 +170,16 @@ function useGlobalStylesUserConfig() { function useGlobalStylesBaseConfig() { const baseConfig = useSelect( ( select ) => { - const { __experimentalGetCurrentThemeBaseGlobalStyles } = + const { __experimentalGetCurrentThemeBaseGlobalStyles, canUser } = select( coreStore ); - - return __experimentalGetCurrentThemeBaseGlobalStyles(); + const currentPost = select( editorStore ).getCurrentPost(); + return ( + canUser( 'read', { + kind: 'postType', + name: currentPost?.type, + id: currentPost?.id, + } ) && __experimentalGetCurrentThemeBaseGlobalStyles() + ); }, [] ); return [ !! baseConfig, baseConfig ];