diff --git a/lib/compat/load.php b/lib/compat/load.php new file mode 100644 index 00000000000000..df05c5fad7aa7c --- /dev/null +++ b/lib/compat/load.php @@ -0,0 +1,170 @@ +namespace = 'wp/v2'; + /* + * The rest base is different from the name of the post type, + * since it uses wp_get_custom_css(). + */ + $this->rest_base = 'customcss'; + } + + /** + * Registers the routes for the objects of the controller. + * + * @see register_rest_route() + * + * @since 6.1.0 + */ + public function register_routes() { + register_rest_route( + $this->namespace, + '/' . $this->rest_base, + array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_items' ), + 'permission_callback' => array( $this, 'items_permissions_check' ), + ), + array( + 'methods' => WP_REST_Server::EDITABLE, + 'callback' => array( $this, 'update_item' ), + 'permission_callback' => array( $this, 'items_permissions_check' ), + ), + 'schema' => array( $this, 'get_public_item_schema' ), + ) + ); + } + + /** + * Retrieves the custom CSS + * + * @param WP_REST_Request $request Full details about the request. + * + * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure. + */ + public function get_items( $request ) { + $data = wp_get_custom_css(); + + return rest_ensure_response( $data ); + } + + /** + * Update custom CSS + * @see https://developer.wordpress.org/reference/functions/wp_update_custom_css_post + * @param WP_REST_Request $request Full details about the request. + * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. + */ + public function update_item( $request ) { + $data = wp_update_custom_css_post( $request ); + + return rest_ensure_response( $data ); + } + + /** + * Checks whether a given request has permission to read the custom CSS + * + * @param WP_REST_Request $request Full details about the request. + * + * @return WP_Error|bool True if the request has read access, WP_Error object otherwise. + */ + public function items_permissions_check( $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable + if ( ! current_user_can( 'edit_css' ) ) { + return new WP_Error( 'rest_cannot_view', __( 'Sorry, you are not allowed to view custom CSS.', 'gutenberg' ), array( 'status' => rest_authorization_required_code() ) ); + } + + return true; + } + + /** + * Custom CSS schema + * + * @return array Item schema data. + */ + public function get_item_schema() { + $schema = array( + '$schema' => 'http://json-schema.org/draft-04/schema#', + 'title' => 'custom_css', + 'type' => 'object', + 'properties' => array( + 'id' => array( + 'description' => __( 'ID of the custom CSS.', 'gutenberg' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'theme' => array( + 'description' => __( 'The theme slug.', 'gutenberg' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'content' => array( + 'description' => __( 'The custom CSS provided by the user.', 'gutenberg' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + ), + ); + + return $this->add_additional_fields_schema( $schema ); + } +} diff --git a/lib/compat/wordpress-6.1/rest-api.php b/lib/compat/wordpress-6.1/rest-api.php index f3391389d9e38a..a17412b300f321 100644 --- a/lib/compat/wordpress-6.1/rest-api.php +++ b/lib/compat/wordpress-6.1/rest-api.php @@ -93,3 +93,26 @@ function gutenberg_register_has_archive_on_post_types_endpoint() { ); } add_action( 'rest_api_init', 'gutenberg_register_has_archive_on_post_types_endpoint' ); + +/** + * Update `custom_css` post type to show in rest + * + * @param array $args Array of arguments for registering a post type. + * @param string $post_type Post type key. + */ +function gutenberg_update_custom_css_rest( $args, $post_type ) { + if ( in_array( $post_type, array( 'custom_css' ), true ) ) { + $args['show_in_rest'] = true; + } + return $args; +} +add_filter( 'register_post_type_args', 'gutenberg_update_custom_css_rest', 10, 2 ); + +/** + * Registers the custom CSS REST API routes. + */ +function gutenberg_register_gutenberg_rest_custom_css() { + $custom_css = new WP_REST_Custom_CSS_Controller(); + $custom_css->register_routes(); +} +add_action( 'rest_api_init', 'gutenberg_register_gutenberg_rest_custom_css', 100 ); diff --git a/packages/edit-site/src/components/global-styles/custom-css.js b/packages/edit-site/src/components/global-styles/custom-css.js new file mode 100644 index 00000000000000..f27429484ad143 --- /dev/null +++ b/packages/edit-site/src/components/global-styles/custom-css.js @@ -0,0 +1,97 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + +/** + * WordPress dependencies + */ +import apiFetch from '@wordpress/api-fetch'; +import { useEffect, useState, useContext, createPortal } from '@wordpress/element'; +import { TextareaControl } from '@wordpress/components'; +import { createHigherOrderComponent } from '@wordpress/compose'; +import { addFilter } from '@wordpress/hooks'; +import { BlockList } from '@wordpress/block-editor'; +import { __ } from '@wordpress/i18n'; + +/* +function CustomCSSValue() { + const [ customCSS, getCustomCSS ] = useState(); + + useEffect( () => { + apiFetch( { + path: '/wp/v2/customcss', + } ).then( ( res ) => { + getCustomCSS( res ); + } ); + }, [] ); + + return customCSS; +} +*/ +function CustomCSSControl() { + const [ newCSS, updateCustomCSS ] = useState(); + const [ customCSS, getCustomCSS ] = useState(); + + useEffect( () => { + apiFetch( { + path: '/wp/v2/customcss', + } ).then( ( res ) => { + getCustomCSS( res ); + } ); + }, [] ); + /* + useEffect( () => { + apiFetch( { + path: '/wp/v2/customcss', + method: 'PUT', //PUT should be used for updating resources. + data: { post_cotent: newCSS }, + } ).then( ( res ) => { + console.log( res ); + } ); + }, [] ); + */ + + return ( + updateCustomCSS( value ) } + /> + ); +} + +export default CustomCSSControl; + +/** + * Override the default block element to include custom CSS. + * + * @param {Function} BlockListBlock Original component. + * + * @return {Function} Wrapped component. + */ +const withCustomCSS = createHigherOrderComponent( + ( BlockListBlock ) => ( props ) => { + /* + if ( ! customCSS ) { + return ; + } + */ + const id = `wp-custom-css-test`; + const className = classnames( props?.className, id ); + const element = useContext( BlockList.__unstableElementContext ); + + return ( + <> + { element && createPortal( , element ) } + + + ); + }, + 'withCustomCSS' +); + +addFilter( + 'editor.BlockListBlock', + 'core/editor/custom-css/with-customcss', + withCustomCSS +); diff --git a/packages/edit-site/src/components/global-styles/screen-css.js b/packages/edit-site/src/components/global-styles/screen-css.js index 7fc1755a632c6b..464d367d6d1ee7 100644 --- a/packages/edit-site/src/components/global-styles/screen-css.js +++ b/packages/edit-site/src/components/global-styles/screen-css.js @@ -2,56 +2,16 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { - TextareaControl, - __experimentalVStack as VStack, -} from '@wordpress/components'; -import { useSelect } from '@wordpress/data'; -import { store as coreStore } from '@wordpress/core-data'; +import { __experimentalVStack as VStack } from '@wordpress/components'; /** * Internal dependencies */ import ScreenHeader from './header'; import Subtitle from './subtitle'; +import CustomCSSControl from './custom-css'; function ScreenCSS() { - /** - * Original plan: - * 1: Get the slug of the current theme - * 2: Get the custom_css post type content for the current theme - * 3: Display the content inside the text area - * 4: Fun part? Get changes to save. - * - * X. Is the TextareaControl too primitive? Is there a better choice? - * X. Add the code icon before the button text. - * X. Validate the CSS! - * - * What we learnt: - * getEntityRecords for the custom_css post type does not include the content. - * - * Plan B: Create a new global styles setting for the custom css. - * Use this new setting to display the CSS on the global styles screen. - * Add the custom_css post type to the global styles rest API endpoint, - * and use the existing PHP filters to make sure that the CSS in the - * global styles option and the Customier option matches. - * - * - * X. Use the existing methods for printing the actual CSS on the front and editors? - */ - const currentTheme = useSelect( ( select ) => { - return select( coreStore ).getEntityRecords( 'root', 'theme', { - status: 'active', - } )[ 0 ].stylesheet; - }, [] ); - - const customCssPost = useSelect( ( select ) => { - return select( coreStore ).getEntityRecords( 'postType', 'custom_css', { - per_page: 1, - slug: currentTheme, - } ); - }, [] ); - return ( <> { __( 'ADDITIONAL CSS' ) } - +