From 66f4e2d72dd4c1ab61aa23fbf27b22c2327bc45f Mon Sep 17 00:00:00 2001 From: Jorge Date: Wed, 17 Apr 2019 10:45:41 +0100 Subject: [PATCH] Add end point --- ...-experimental-wp-widget-blocks-manager.php | 274 ++++++++++++++++++ lib/class-wp-rest-widget-areas-controller.php | 219 ++++++++++++++ lib/load.php | 4 + lib/rest-api.php | 11 + 4 files changed, 508 insertions(+) create mode 100644 lib/class-experimental-wp-widget-blocks-manager.php create mode 100644 lib/class-wp-rest-widget-areas-controller.php diff --git a/lib/class-experimental-wp-widget-blocks-manager.php b/lib/class-experimental-wp-widget-blocks-manager.php new file mode 100644 index 00000000000000..bb1ac9fa089f76 --- /dev/null +++ b/lib/class-experimental-wp-widget-blocks-manager.php @@ -0,0 +1,274 @@ + $post_id, + 'wp_inactive_widgets' => array_merge( + $sidebars['wp_inactive_widgets'], + $sidebar + ), + ) + ) + ); + } + + /** + * Returns a sidebar as an array of legacy widget blocks. + * + * @since 5.7.0 + * + * @param string $sidebar_id Indentifier of the sidebar. + * @return array $post_id Post id. + */ + public static function get_sidebar_as_blocks( $sidebar_id ) { + $blocks = array(); + + $sidebars_items = wp_get_sidebars_widgets(); + + foreach ( $sidebars_items[ $sidebar_id ] as $item ) { + $widget_class = self::get_widget_class( $item ); + $blocks[] = array( + 'blockName' => 'core/legacy-widget', + 'attrs' => array( + 'class' => $widget_class, + 'identifier' => $item, + 'instance' => self::get_sidebar_widget_instance( $sidebar, $item ), + ), + 'innerHTML' => '', + ); + } + return $blocks; + } + + /** + * Verifies if a sidabar id is valid or not. + * + * @since 5.7.0 + * + * @param string $sidebar_id Indentifier of the sidebar. + * @return boolean True if the $sidebar_id value is valid and false otherwise. + */ + public static function is_valid_sidabar_id( $sidebar_id ) { + $wp_registered_sidebars = self::get_wp_registered_sidebars(); + return isset( $wp_registered_sidebars[ $sidebar_id ] ); + } + + + /** + * Given a widget id returns the name of the class the represents the widget. + * + * @since 5.7.0 + * + * @param string $widget_id Indentifier of the widget. + * @return string|null Name of the class that represents the widget or null if the widget is not represented by a class. + */ + private static function get_widget_class( $widget_id ) { + $wp_registered_widgets = self::get_wp_registered_widgets(); + if ( + isset( $wp_registered_widgets[ $widget_id ]['callback'][0] ) && + $wp_registered_widgets[ $widget_id ]['callback'][0] instanceof WP_Widget + ) { + return get_class( $wp_registered_widgets[ $widget_id ]['callback'][0] ); + } + return null; + } + + /** + * Retrieves a widget instance. + * + * @since 5.7.0 + * + * @param array $sidebar sidebar data available at $wp_registered_sidebars. + * @param string $id Idenfitier of the widget instance. + * @return array Array containing the widget instance. + */ + private static function get_sidebar_widget_instance( $sidebar, $id ) { + list( $object, $number, $name ) = self::get_widget_info( $id ); + if ( ! $object ) { + return array(); + } + + $object->_set( $number ); + + $instances = $object->get_settings(); + $instance = $instances[ $number ]; + + $args = array_merge( + $sidebar, + array( + 'widget_id' => $id, + 'widget_name' => $name, + ) + ); + + /** + * Filters the settings for a particular widget instance. + * + * Returning false will effectively short-circuit display of the widget. + * + * @since 2.8.0 + * + * @param array $instance The current widget instance's settings. + * @param WP_Widget $this The current widget instance. + * @param array $args An array of default widget arguments. + */ + $instance = apply_filters( 'widget_display_callback', $instance, $object, $args ); + + if ( false === $instance ) { + return array(); + } + + return $instance; + } + + /** + * Given a widget id returns an array containing information about the widget. + * + * @since 5.7.0 + * + * @param string $widget_id Indentifier of the widget. + * @return array Array containing the the wiget object, the number, and the name. + */ + private static function get_widget_info( $widget_id ) { + $wp_registered_widgets = self::get_wp_registered_widgets(); + + if ( + ! isset( $wp_registered_widgets[ $widget_id ]['callback'][0] ) || + ! isset( $wp_registered_widgets[ $widget_id ]['params'][0]['number'] ) || + ! isset( $wp_registered_widgets[ $widget_id ]['name'] ) || + ! ( $wp_registered_widgets[ $widget_id ]['callback'][0] instanceof WP_Widget ) + ) { + return array( null, null, null ); + } + + $object = $wp_registered_widgets[ $widget_id ]['callback'][0]; + $number = $wp_registered_widgets[ $widget_id ]['params'][0]['number']; + $name = $wp_registered_widgets[ $widget_id ]['name']; + return array( $object, $number, $name ); + } + + /** + * Serializes an array of blocks. + * + * @since 5.7.0 + * + * @param array $blocks Post Array of block objects. + * @return string String representing the blocks. + */ + public static function serialize_blocks( $blocks ) { + return implode( array_map( 'self::serialize_block', $blocks ) ); + } + + /** + * Serializes a block. + * + * @since 5.7.0 + * + * @param array $block Block object. + * @return string String representing the block. + */ + public static function serialize_block( $block ) { + $name = $block['blockName']; + if ( 0 === strpos( $name, 'core/' ) ) { + $name = substr( $name, strlen( 'core/' ) ); + } + + if ( empty( $block['attrs'] ) ) { + $opening_tag_suffix = ''; + } else { + $opening_tag_suffix = ' ' . json_encode( $block['attrs'] ); + } + + if ( empty( $block['innerHTML'] ) ) { + return sprintf( + '', + $name, + $opening_tag_suffix + ); + } else { + return sprintf( + '%3$s', + $name, + $opening_tag_suffix, + $block['innerHTML'] + ); + } + } +} diff --git a/lib/class-wp-rest-widget-areas-controller.php b/lib/class-wp-rest-widget-areas-controller.php new file mode 100644 index 00000000000000..6d333efa96c145 --- /dev/null +++ b/lib/class-wp-rest-widget-areas-controller.php @@ -0,0 +1,219 @@ +namespace = '__experimental'; + $this->rest_base = 'widget-areas'; + } + + /** + * Registers the necessary REST API routes. + * + * @access public + */ + 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, 'get_items_permissions_check' ), + ), + 'schema' => array( $this, 'get_public_item_schema' ), + ) + ); + + $id_argument = array( + 'description' => __( 'The sidebar’s ID.', 'gutenberg' ), + 'type' => 'string', + 'required' => true, + 'validate_callback' => array( $this, 'is_valid_sidabar_id' ), + ); + + $content_argument = array( + 'description' => __( 'Sidebar content.', 'gutenberg' ), + 'type' => 'string', + 'required' => true, + ); + + register_rest_route( + $this->namespace, + '/' . $this->rest_base . '/(?P.+)', + array( + 'args' => array( + 'id' => $id_argument, + ), + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_item' ), + 'permission_callback' => array( $this, 'get_items_permissions_check' ), + ), + array( + 'methods' => WP_REST_Server::EDITABLE, + 'callback' => array( $this, 'update_item' ), + 'permission_callback' => array( $this, 'update_item_permissions_check' ), + 'args' => array( + 'id' => $id_argument, + 'content' => $content_argument, + ), + ), + 'schema' => array( $this, 'get_public_item_schema' ), + ) + ); + } + + /** + * Checks whether a given request has permission to read widget areas. + * + * @since 5.7.0 + * + * @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 get_items_permissions_check( $request ) { + if ( ! current_user_can( 'edit_theme_options' ) ) { + return new WP_Error( + 'rest_user_cannot_view', + __( 'Sorry, you are not allowed to read sidebars.', 'gutenberg' ) + ); + } + + return true; + } + + /** + * Retrieves all widget areas. + * + * @since 5.7.0 + * + * @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 ) { + global $wp_registered_sidebars; + + $data = array(); + + foreach ( array_keys( $wp_registered_sidebars ) as $sidebar_id ) { + $data[ $sidebar_id ] = $this->get_sidebar_data( $sidebar_id ); + } + + return rest_ensure_response( $data ); + } + + /** + * Retrieves a specific widget area. + * + * @since 5.7.0 + * + * @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_item( $request ) { + return rest_ensure_response( $this->get_sidebar_data( $request['id'] ) ); + } + + /** + * Checks if a given REST request has access to update a widget area. + * + * @since 5.7.0 + * + * @param WP_REST_Request $request Full details about the request. + * @return WP_Error|bool True if the request has access to update the item, error object otherwise. + */ + public function update_item_permissions_check( $request ) { + if ( ! current_user_can( 'edit_theme_options' ) ) { + return new WP_Error( + 'rest_user_cannot_edit', + __( 'Sorry, you are not allowed to edit sidebars.', 'gutenberg' ) + ); + } + + return true; + } + + /** + * Updates a single widget area. + * + * @since 5.7.0 + * + * @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 ) { + $sidebar_id = $request->get_param( 'id' ); + $sidebar_content = $request->get_param( 'content' ); + + $id_referenced_in_sidebar = Experimental_WP_Widget_Blocks_Manager::get_post_id_referenced_in_sidebar( $sidebar_id ); + + $post_id = wp_insert_post( + array( + 'ID' => $id_referenced_in_sidebar, + 'post_content' => $sidebar_content, + 'post_type' => 'wp_area', + ) + ); + + if ( 0 === $id_referenced_in_sidebar ) { + Experimental_WP_Widget_Blocks_Manager::reference_post_id_in_sidebar( $sidebar_id, $post_id ); + } + + return rest_ensure_response( $this->get_sidebar_data( $request['id'] ) ); + } + + /** + * Returns the sidebar data together with a content array containing the blocks present in the sidebar. + * The bocks may be legacy widget blocks representing the widgets currently present in the sidebar, or the content of a wp_area post that the sidebar references. + * + * @since 5.7.0 + * + * @param string $sidebar_id Indentifier of the sidebar. + * @return object Sidebar data with a content array. + */ + protected function get_sidebar_data( $sidebar_id ) { + $content_string = ''; + + $post_id_referenced_in_sidebar = Experimental_WP_Widget_Blocks_Manager::get_post_id_referenced_in_sidebar( $sidebar_id ); + + if ( 0 !== $post_id_referenced_in_sidebar ) { + $post = get_post( $post_id_referenced_in_sidebar ); + $content_string = $post->post_content; + } else { + $blocks = Experimental_WP_Widget_Blocks_Manager::get_sidebar_as_blocks( $sidebar_id ); + $content_string = Experimental_WP_Widget_Blocks_Manager::serialize_blocks( $blocks ); + } + + return array_merge( + Experimental_WP_Widget_Blocks_Manager::get_wp_registered_sidebars_sidebar( $sidebar_id ), + array( + 'content' => array( + 'raw' => $content_string, + 'rendered' => apply_filters( 'the_content', $content_string ), + 'block_version' => block_version( $content_string ), + ), + ) + ); + } +} diff --git a/lib/load.php b/lib/load.php index 9f845d95a8bf9d..d93b9dc1f9f0ea 100644 --- a/lib/load.php +++ b/lib/load.php @@ -18,6 +18,10 @@ if ( ! class_exists( 'WP_REST_Widget_Updater_Controller' ) ) { require dirname( __FILE__ ) . '/class-wp-rest-widget-updater-controller.php'; } + if ( ! class_exists( 'WP_REST_Widget_Areas_Controller' ) ) { + require dirname( __FILE__ ) . '/class-experimental-wp-widget-blocks-manager.php'; + require dirname( __FILE__ ) . '/class-wp-rest-widget-areas-controller.php'; + } /** * End: Include for phase 2 */ diff --git a/lib/rest-api.php b/lib/rest-api.php index eaccc09c61978d..d9671557bfcb8b 100644 --- a/lib/rest-api.php +++ b/lib/rest-api.php @@ -67,6 +67,17 @@ function gutenberg_register_rest_widget_updater_routes() { $widgets_controller->register_routes(); } add_action( 'rest_api_init', 'gutenberg_register_rest_widget_updater_routes' ); + +/** + * Registers the widget area REST API routes. + * + * @since 5.7.0 + */ +function gutenberg_register_rest_widget_areas() { + $widget_areas_controller = new WP_REST_Widget_Areas_Controller(); + $widget_areas_controller->register_routes(); +} +add_action( 'rest_api_init', 'gutenberg_register_rest_widget_areas' ); /** * End: Include for phase 2 */