From 60370f5d3cff560eb420410b958b826b18068307 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 7eb87cf7993933..4f349f77dcd814 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 aaef8c77c4f578..fee9c71b86c070 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 c5e2927198da0c..d43894cdc27732 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 d1aaf0b447cfed..78417790fdb3f9 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 93dd4dbe1eda49..7e8e7fe556538d 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 ];