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 ];