From 724ab4ca49dad39fa59136a8b1c543ee5b164c75 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Tue, 25 May 2021 15:04:46 +1000 Subject: [PATCH] Fix errors caused by adding widgets to WordPress core --- lib/class-wp-rest-widget-types-controller.php | 2 +- lib/class-wp-rest-widgets-controller.php | 24 +- lib/load.php | 4 +- lib/widgets-api.php | 375 +++++++++--------- lib/widgets-customize.php | 12 +- .../block-library/src/legacy-widget/index.php | 32 +- 6 files changed, 236 insertions(+), 213 deletions(-) diff --git a/lib/class-wp-rest-widget-types-controller.php b/lib/class-wp-rest-widget-types-controller.php index bd6c0a42ee6587..866f8d606d36f8 100644 --- a/lib/class-wp-rest-widget-types-controller.php +++ b/lib/class-wp-rest-widget-types-controller.php @@ -207,7 +207,7 @@ protected function get_widgets() { $widgets = array(); foreach ( $wp_registered_widgets as $widget ) { - $parsed_id = gutenberg_parse_widget_id( $widget['id'] ); + $parsed_id = wp_parse_widget_id( $widget['id'] ); $widget_object = gutenberg_get_widget_object( $parsed_id['id_base'] ); $widget['id'] = $parsed_id['id_base']; diff --git a/lib/class-wp-rest-widgets-controller.php b/lib/class-wp-rest-widgets-controller.php index b851b5b1d95a2c..03e16a7a6a75de 100644 --- a/lib/class-wp-rest-widgets-controller.php +++ b/lib/class-wp-rest-widgets-controller.php @@ -150,7 +150,7 @@ public function get_item_permissions_check( $request ) { // phpcs:ignore Variabl */ public function get_item( $request ) { $widget_id = $request['id']; - $sidebar_id = gutenberg_find_widgets_sidebar( $widget_id ); + $sidebar_id = wp_find_widgets_sidebar( $widget_id ); if ( is_null( $sidebar_id ) ) { return new WP_Error( @@ -192,7 +192,7 @@ public function create_item( $request ) { return $widget_id; } - gutenberg_assign_widget_to_sidebar( $widget_id, $sidebar_id ); + wp_assign_widget_to_sidebar( $widget_id, $sidebar_id ); $request['context'] = 'edit'; @@ -229,10 +229,10 @@ public function update_item_permissions_check( $request ) { // phpcs:ignore Vari */ public function update_item( $request ) { $widget_id = $request['id']; - $sidebar_id = gutenberg_find_widgets_sidebar( $widget_id ); + $sidebar_id = wp_find_widgets_sidebar( $widget_id ); // Allow sidebar to be unset or missing when widget is not a WP_Widget. - $parsed_id = gutenberg_parse_widget_id( $widget_id ); + $parsed_id = wp_parse_widget_id( $widget_id ); $widget_object = gutenberg_get_widget_object( $parsed_id['id_base'] ); if ( is_null( $sidebar_id ) && $widget_object ) { return new WP_Error( @@ -255,7 +255,7 @@ public function update_item( $request ) { if ( $request->has_param( 'sidebar' ) ) { if ( $sidebar_id !== $request['sidebar'] ) { $sidebar_id = $request['sidebar']; - gutenberg_assign_widget_to_sidebar( $widget_id, $sidebar_id ); + wp_assign_widget_to_sidebar( $widget_id, $sidebar_id ); } } @@ -286,7 +286,7 @@ public function delete_item_permissions_check( $request ) { // phpcs:ignore Vari */ public function delete_item( $request ) { $widget_id = $request['id']; - $sidebar_id = gutenberg_find_widgets_sidebar( $widget_id ); + $sidebar_id = wp_find_widgets_sidebar( $widget_id ); if ( is_null( $sidebar_id ) ) { return new WP_Error( @@ -300,7 +300,7 @@ public function delete_item( $request ) { if ( $request['force'] ) { $prepared = $this->prepare_item_for_response( compact( 'widget_id', 'sidebar_id' ), $request ); - gutenberg_assign_widget_to_sidebar( $widget_id, '' ); + wp_assign_widget_to_sidebar( $widget_id, '' ); $prepared->set_data( array( 'deleted' => true, @@ -308,7 +308,7 @@ public function delete_item( $request ) { ) ); } else { - gutenberg_assign_widget_to_sidebar( $widget_id, 'wp_inactive_widgets' ); + wp_assign_widget_to_sidebar( $widget_id, 'wp_inactive_widgets' ); $prepared = $this->prepare_item_for_response( array( 'sidebar_id' => 'wp_inactive_widgets', @@ -359,7 +359,7 @@ protected function save_widget( $request ) { if ( isset( $request['id'] ) ) { // Saving an existing widget. $id = $request['id']; - $parsed_id = gutenberg_parse_widget_id( $id ); + $parsed_id = wp_parse_widget_id( $id ); $id_base = $parsed_id['id_base']; $number = isset( $parsed_id['number'] ) ? $parsed_id['number'] : null; $widget_object = gutenberg_get_widget_object( $id_base ); @@ -495,7 +495,7 @@ public function prepare_item_for_response( $item, $request ) { } $widget = $wp_registered_widgets[ $widget_id ]; - $parsed_id = gutenberg_parse_widget_id( $widget_id ); + $parsed_id = wp_parse_widget_id( $widget_id ); $fields = $this->get_fields_for_response( $request ); $prepared = array( @@ -511,11 +511,11 @@ public function prepare_item_for_response( $item, $request ) { rest_is_field_included( 'rendered', $fields ) && 'wp_inactive_widgets' !== $sidebar_id ) { - $prepared['rendered'] = trim( gutenberg_render_widget( $widget_id, $sidebar_id ) ); + $prepared['rendered'] = trim( wp_render_widget( $widget_id, $sidebar_id ) ); } if ( rest_is_field_included( 'rendered_form', $fields ) ) { - $rendered_form = gutenberg_render_widget_control( $widget_id ); + $rendered_form = wp_render_widget_control( $widget_id ); if ( ! is_null( $rendered_form ) ) { $prepared['rendered_form'] = trim( $rendered_form ); } diff --git a/lib/load.php b/lib/load.php index 941f3d71b5835a..0f951eab2ae58c 100644 --- a/lib/load.php +++ b/lib/load.php @@ -9,6 +9,8 @@ die( 'Silence is golden.' ); } +global $wp_version; + require_once __DIR__ . '/init.php'; require_once __DIR__ . '/upgrade.php'; @@ -73,7 +75,7 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/rest-api.php'; } -if ( ! class_exists( 'WP_Widget_Block' ) ) { +if ( version_compare( $wp_version, '5.8-alpha', '<' ) ) { require_once __DIR__ . '/class-wp-widget-block.php'; } diff --git a/lib/widgets-api.php b/lib/widgets-api.php index 8fbacba8333c01..cf626da1618dd0 100644 --- a/lib/widgets-api.php +++ b/lib/widgets-api.php @@ -7,223 +7,238 @@ * @package gutenberg */ -/** - * Assigns a widget to the given sidebar. - * - * Belongs in wp-includes/widgets.php when merged to Core. - * - * @since 10.2.0 - * - * @param string $widget_id The widget id to assign. - * @param string $sidebar_id The sidebar id to assign to. If empty, the widget won't be added to any sidebar. - */ -function gutenberg_assign_widget_to_sidebar( $widget_id, $sidebar_id ) { - $sidebars = wp_get_sidebars_widgets(); - - foreach ( $sidebars as $maybe_sidebar_id => $widgets ) { - foreach ( $widgets as $i => $maybe_widget_id ) { - if ( $widget_id === $maybe_widget_id && $sidebar_id !== $maybe_sidebar_id ) { - unset( $sidebars[ $maybe_sidebar_id ][ $i ] ); - // We could technically break 2 here, but continue looping in case the id is duplicated. - continue 2; +if ( ! function_exists( 'wp_assign_widget_to_sidebar' ) ) { + /** + * Assigns a widget to the given sidebar. + * + * Can be removed when minimum WordPress version is 5.8. + * + * @since 10.2.0 + * + * @param string $widget_id The widget id to assign. + * @param string $sidebar_id The sidebar id to assign to. If empty, the widget won't be added to any sidebar. + */ + function wp_assign_widget_to_sidebar( $widget_id, $sidebar_id ) { + $sidebars = wp_get_sidebars_widgets(); + + foreach ( $sidebars as $maybe_sidebar_id => $widgets ) { + foreach ( $widgets as $i => $maybe_widget_id ) { + if ( $widget_id === $maybe_widget_id && $sidebar_id !== $maybe_sidebar_id ) { + unset( $sidebars[ $maybe_sidebar_id ][ $i ] ); + // We could technically break 2 here, but continue looping in case the id is duplicated. + continue 2; + } } } - } - if ( $sidebar_id ) { - $sidebars[ $sidebar_id ][] = $widget_id; - } + if ( $sidebar_id ) { + $sidebars[ $sidebar_id ][] = $widget_id; + } - wp_set_sidebars_widgets( $sidebars ); + wp_set_sidebars_widgets( $sidebars ); + } } -/** - * Finds the sidebar that a given widget belongs to. - * - * Belongs in wp-includes/widgets.php when merged to Core. - * - * @since 10.3.0 - * - * @param string $widget_id The widget id to look for. - * @return string|null The found sidebar's id, or null if it was not found. - */ -function gutenberg_find_widgets_sidebar( $widget_id ) { - foreach ( wp_get_sidebars_widgets() as $sidebar_id => $widget_ids ) { - foreach ( $widget_ids as $maybe_widget_id ) { - if ( $maybe_widget_id === $widget_id ) { - return (string) $sidebar_id; +if ( ! function_exists( 'wp_find_widgets_sidebar' ) ) { + /** + * Finds the sidebar that a given widget belongs to. + * + * Can be removed when minimum WordPress version is 5.8. + * + * @since 10.3.0 + * + * @param string $widget_id The widget id to look for. + * @return string|null The found sidebar's id, or null if it was not found. + */ + function wp_find_widgets_sidebar( $widget_id ) { + foreach ( wp_get_sidebars_widgets() as $sidebar_id => $widget_ids ) { + foreach ( $widget_ids as $maybe_widget_id ) { + if ( $maybe_widget_id === $widget_id ) { + return (string) $sidebar_id; + } } } - } - - return null; -} -/** - * Converts a widget ID into its id_base and number components. - * - * Belongs in wp-includes/widgets.php when merged to Core. - * WP_Customize_Widgets::parse_widget_id should then be deprecated. - * - * @since 10.2.0 - * - * @param string $id Widget ID. - * @return array Array containing a widget's id_base and number components. - */ -function gutenberg_parse_widget_id( $id ) { - $parsed = array(); - - if ( preg_match( '/^(.+)-(\d+)$/', $id, $matches ) ) { - $parsed['id_base'] = $matches[1]; - $parsed['number'] = (int) $matches[2]; - } else { - // Likely an old single widget. - $parsed['id_base'] = $id; + return null; } - - return $parsed; } -/** - * Calls the render callback of a widget and returns the output. - * - * Belongs in wp-includes/widgets.php when merged to Core. Some of the code in - * dynamic_sidebar() and WP_Customize_Widgets should then be DRYed up. - * - * @since 10.2.0 - * - * @param string $widget_id Widget ID. - * @param string $sidebar_id Sidebar ID. - * @return string - */ -function gutenberg_render_widget( $widget_id, $sidebar_id ) { - global $wp_registered_widgets, $wp_registered_sidebars; +if ( ! function_exists( 'wp_parse_widget_id' ) ) { + /** + * Converts a widget ID into its id_base and number components. + * + * Can be removed when minimum WordPress version is 5.8. + * + * @since 10.2.0 + * + * @param string $id Widget ID. + * @return array Array containing a widget's id_base and number components. + */ + function wp_parse_widget_id( $id ) { + $parsed = array(); + + if ( preg_match( '/^(.+)-(\d+)$/', $id, $matches ) ) { + $parsed['id_base'] = $matches[1]; + $parsed['number'] = (int) $matches[2]; + } else { + // Likely an old single widget. + $parsed['id_base'] = $id; + } - if ( ! isset( $wp_registered_widgets[ $widget_id ] ) ) { - return ''; + return $parsed; } +} - if ( isset( $wp_registered_sidebars[ $sidebar_id ] ) ) { - $sidebar = $wp_registered_sidebars[ $sidebar_id ]; - } elseif ( 'wp_inactive_widgets' === $sidebar_id ) { - $sidebar = array(); - } else { - return ''; - } +if ( ! function_exists( 'wp_render_widget' ) ) { + /** + * Calls the render callback of a widget and returns the output. + * + * Can be removed when minimum WordPress version is 5.8. + * + * @since 10.2.0 + * + * @param string $widget_id Widget ID. + * @param string $sidebar_id Sidebar ID. + * @return string + */ + function wp_render_widget( $widget_id, $sidebar_id ) { + global $wp_registered_widgets, $wp_registered_sidebars; + + if ( ! isset( $wp_registered_widgets[ $widget_id ] ) ) { + return ''; + } + + if ( isset( $wp_registered_sidebars[ $sidebar_id ] ) ) { + $sidebar = $wp_registered_sidebars[ $sidebar_id ]; + } elseif ( 'wp_inactive_widgets' === $sidebar_id ) { + $sidebar = array(); + } else { + return ''; + } - $params = array_merge( - array( - array_merge( - $sidebar, - array( - 'widget_id' => $widget_id, - 'widget_name' => $wp_registered_widgets[ $widget_id ]['name'], - ) + $params = array_merge( + array( + array_merge( + $sidebar, + array( + 'widget_id' => $widget_id, + 'widget_name' => $wp_registered_widgets[ $widget_id ]['name'], + ) + ), ), - ), - (array) $wp_registered_widgets[ $widget_id ]['params'] - ); - - // Substitute HTML `id` and `class` attributes into `before_widget`. - $classname_ = ''; - foreach ( (array) $wp_registered_widgets[ $widget_id ]['classname'] as $cn ) { - if ( is_string( $cn ) ) { - $classname_ .= '_' . $cn; - } elseif ( is_object( $cn ) ) { - $classname_ .= '_' . get_class( $cn ); + (array) $wp_registered_widgets[ $widget_id ]['params'] + ); + + // Substitute HTML `id` and `class` attributes into `before_widget`. + $classname_ = ''; + foreach ( (array) $wp_registered_widgets[ $widget_id ]['classname'] as $cn ) { + if ( is_string( $cn ) ) { + $classname_ .= '_' . $cn; + } elseif ( is_object( $cn ) ) { + $classname_ .= '_' . get_class( $cn ); + } } - } - $classname_ = ltrim( $classname_, '_' ); - $params[0]['before_widget'] = sprintf( $params[0]['before_widget'], $widget_id, $classname_ ); + $classname_ = ltrim( $classname_, '_' ); + $params[0]['before_widget'] = sprintf( $params[0]['before_widget'], $widget_id, $classname_ ); - /** This filter is documented in wp-includes/widgets.php */ - $params = apply_filters( 'dynamic_sidebar_params', $params ); + /** This filter is documented in wp-includes/widgets.php */ + $params = apply_filters( 'dynamic_sidebar_params', $params ); - $callback = $wp_registered_widgets[ $widget_id ]['callback']; + $callback = $wp_registered_widgets[ $widget_id ]['callback']; - ob_start(); + ob_start(); - /** This filter is documented in wp-includes/widgets.php */ - do_action( 'dynamic_sidebar', $wp_registered_widgets[ $widget_id ] ); + /** This filter is documented in wp-includes/widgets.php */ + do_action( 'dynamic_sidebar', $wp_registered_widgets[ $widget_id ] ); - if ( is_callable( $callback ) ) { - call_user_func_array( $callback, $params ); - } + if ( is_callable( $callback ) ) { + call_user_func_array( $callback, $params ); + } - return ob_get_clean(); + return ob_get_clean(); + } } -/** - * Calls the control callback of a widget and returns the output. - * - * Belongs in wp-admin/includes/widgets.php when merged to Core. Some of the - * code in wp_widget_control() should then be DRYed up. - * - * @since 10.2.0 - * - * @param string $id Widget ID. - * @return string|null - */ -function gutenberg_render_widget_control( $id ) { - global $wp_registered_widget_controls; +if ( ! function_exists( 'wp_render_widget_control' ) ) { + /** + * Calls the control callback of a widget and returns the output. + * + * Can be removed when minimum WordPress version is 5.8. + * + * @since 10.2.0 + * + * @param string $id Widget ID. + * @return string|null + */ + function wp_render_widget_control( $id ) { + global $wp_registered_widget_controls; + + if ( ! isset( $wp_registered_widget_controls[ $id ]['callback'] ) ) { + return null; + } - if ( ! isset( $wp_registered_widget_controls[ $id ]['callback'] ) ) { - return null; - } + $callback = $wp_registered_widget_controls[ $id ]['callback']; + $params = $wp_registered_widget_controls[ $id ]['params']; - $callback = $wp_registered_widget_controls[ $id ]['callback']; - $params = $wp_registered_widget_controls[ $id ]['params']; + ob_start(); - ob_start(); + if ( is_callable( $callback ) ) { + call_user_func_array( $callback, $params ); + } - if ( is_callable( $callback ) ) { - call_user_func_array( $callback, $params ); + return ob_get_clean(); } - - return ob_get_clean(); } -/** - * Returns the instance settings of the given widget. Must be a widget that - * is registered using WP_Widget. - * - * Belongs in WP_Widget when merged to Core. - * - * @since 10.2.0 - * - * @param string $id Widget ID. - * @return array|null - */ -function gutenberg_get_widget_instance( $id ) { - $parsed_id = gutenberg_parse_widget_id( $id ); - $widget_object = gutenberg_get_widget_object( $parsed_id['id_base'] ); +if ( ! function_exists( 'gutenberg_get_widget_instance' ) ) { + /** + * Returns the instance settings of the given widget. Must be a widget that + * is registered using WP_Widget. + * + * Belongs in WP_Widget when merged to Core. + * + * Can be removed when minimum WordPress version is 5.8. + * + * @since 10.2.0 + * + * @param string $id Widget ID. + * @return array|null + */ + function gutenberg_get_widget_instance( $id ) { + $parsed_id = wp_parse_widget_id( $id ); + $widget_object = gutenberg_get_widget_object( $parsed_id['id_base'] ); + + if ( ! isset( $parsed_id['number'] ) || ! $widget_object ) { + return null; + } - if ( ! isset( $parsed_id['number'] ) || ! $widget_object ) { - return null; + $all_instances = $widget_object->get_settings(); + return $all_instances[ $parsed_id['number'] ]; } - - $all_instances = $widget_object->get_settings(); - return $all_instances[ $parsed_id['number'] ]; } -/** - * Returns the registered WP_Widget object for the given widget type. - * - * Belongs in WP_Widget_Factory when merged to Core. - * - * @since 10.2.0 - * - * @param string $id_base Widget type ID. - * @return WP_Widget|null - */ -function gutenberg_get_widget_object( $id_base ) { - global $wp_widget_factory; - - foreach ( $wp_widget_factory->widgets as $widget_object ) { - if ( $widget_object->id_base === $id_base ) { - return $widget_object; +if ( ! function_exists( 'gutenberg_get_widget_object' ) ) { + /** + * Returns the registered WP_Widget object for the given widget type. + * + * Belongs in WP_Widget_Factory when merged to Core. + * + * Can be removed when minimum WordPress version is 5.8. + * + * @since 10.2.0 + * + * @param string $id_base Widget type ID. + * @return WP_Widget|null + */ + function gutenberg_get_widget_object( $id_base ) { + global $wp_widget_factory; + + foreach ( $wp_widget_factory->widgets as $widget_object ) { + if ( $widget_object->id_base === $id_base ) { + return $widget_object; + } } - } - return null; + return null; + } } diff --git a/lib/widgets-customize.php b/lib/widgets-customize.php index bb2013f8c65474..475a2c58d12520 100644 --- a/lib/widgets-customize.php +++ b/lib/widgets-customize.php @@ -5,6 +5,8 @@ * @package gutenberg */ +global $wp_version; + /** * Gutenberg's Customize Register. * @@ -167,7 +169,9 @@ function gutenberg_widgets_customize_load_block_editor_scripts_and_styles( $is_b return $is_block_editor_screen; } -add_action( 'customize_register', 'gutenberg_widgets_customize_register' ); -add_filter( 'widget_customizer_setting_args', 'gutenberg_widgets_customize_add_unstable_instance', 10, 2 ); -add_action( 'customize_controls_enqueue_scripts', 'gutenberg_customize_widgets_init' ); -add_filter( 'should_load_block_editor_scripts_and_styles', 'gutenberg_widgets_customize_load_block_editor_scripts_and_styles' ); +if ( version_compare( $wp_version, '5.8-alpha', '<' ) ) { + add_action( 'customize_register', 'gutenberg_widgets_customize_register' ); + add_filter( 'widget_customizer_setting_args', 'gutenberg_widgets_customize_add_unstable_instance', 10, 2 ); + add_action( 'customize_controls_enqueue_scripts', 'gutenberg_customize_widgets_init' ); + add_filter( 'should_load_block_editor_scripts_and_styles', 'gutenberg_widgets_customize_load_block_editor_scripts_and_styles' ); +} diff --git a/packages/block-library/src/legacy-widget/index.php b/packages/block-library/src/legacy-widget/index.php index e8ab4a0a2f2cb8..6a49111b8e6929 100644 --- a/packages/block-library/src/legacy-widget/index.php +++ b/packages/block-library/src/legacy-widget/index.php @@ -13,16 +13,22 @@ * @return string Rendered block. */ function render_block_core_legacy_widget( $attributes ) { + global $wp_widget_factory; + if ( isset( $attributes['id'] ) ) { - $sidebar_id = gutenberg_find_widgets_sidebar( $attributes['id'] ); - return gutenberg_render_widget( $attributes['id'], $sidebar_id ); + $sidebar_id = wp_find_widgets_sidebar( $attributes['id'] ); + return wp_render_widget( $attributes['id'], $sidebar_id ); } if ( ! isset( $attributes['idBase'] ) ) { return ''; } - $widget_object = gutenberg_get_widget_object( $attributes['idBase'] ); + if ( method_exists( $wp_widget_factory, 'get_widget_object' ) ) { + $widget_object = $wp_widget_factory->get_widget_object( $attributes['idBase'] ); + } else { + $widget_object = gutenberg_get_widget_object( $attributes['idBase'] ); + } if ( ! $widget_object ) { return ''; @@ -44,25 +50,21 @@ function render_block_core_legacy_widget( $attributes ) { } /** - * Registers the 'core/legacy-widget' block. + * On application init this does two things: + * + * - Registers the 'core/legacy-widget' block. + * - Intercepts any request with legacy-widget-preview in the query param and, + * if set, renders a page containing a preview of the requested Legacy Widget + * block. */ -function register_block_core_legacy_widget() { +function init_legacy_widget_block() { register_block_type_from_metadata( __DIR__ . '/legacy-widget', array( 'render_callback' => 'render_block_core_legacy_widget', ) ); -} - -add_action( 'init', 'register_block_core_legacy_widget', 20 ); -/** - * Intercepts any request with legacy-widget-preview in the query param and, if - * set, renders a page containing a preview of the requested Legacy Widget - * block. - */ -function handle_legacy_widget_preview_iframe() { if ( empty( $_GET['legacy-widget-preview'] ) ) { return; } @@ -108,4 +110,4 @@ function handle_legacy_widget_preview_iframe() { exit; } -add_action( 'init', 'handle_legacy_widget_preview_iframe', 21 ); +add_action( 'init', 'init_legacy_widget_block' );