Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First stab at sidebars_widgets-based widget management #24290

Merged
merged 41 commits into from
Aug 13, 2020
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
649d666
First stab at sidebars_widgets based widget management
adamziel Jul 30, 2020
b1ca015
Render widgets screen based on sidebars endpoint
adamziel Jul 31, 2020
feedcbd
Fully functional blocks rendering
adamziel Jul 31, 2020
46dc634
Add a scaffold of store-based saving
adamziel Jul 31, 2020
560b6db
Sidebars API -based widget management
adamziel Aug 4, 2020
32e025a
Entity-based save operation
adamziel Aug 4, 2020
638dadf
Enable REST-based widgets save operation
adamziel Aug 4, 2020
997a7f5
Display success/error notice after saving
adamziel Aug 5, 2020
c234c19
Add the experimental sidebars controller
adamziel Aug 5, 2020
1267acc
Clean up unused apis
adamziel Aug 5, 2020
2d1d2d8
Restore the widget-forms endpoint
adamziel Aug 5, 2020
823d50d
Refactor widget-forms to widget-utils controller
adamziel Aug 5, 2020
2857bc7
Make widget form and preview work
adamziel Aug 5, 2020
c38a77f
Remove $core_widgets = [] override
adamziel Aug 5, 2020
362bc6e
Make the new widgets screen fully functional
adamziel Aug 5, 2020
0c9ee1c
Remove obsolete changes
adamziel Aug 5, 2020
84002c7
Remove unused code
adamziel Aug 5, 2020
479b842
Restore the experimental customizer UI
adamziel Aug 6, 2020
5329406
Lint PHP code
adamziel Aug 6, 2020
9900983
Lint
adamziel Aug 6, 2020
14cd40b
Add permissions_check
adamziel Aug 6, 2020
e1a145a
Define read / edit routes using a single declaration
adamziel Aug 6, 2020
6234176
replace get_param with array syntax
adamziel Aug 6, 2020
9fdc8ce
Add wp_slash to input widget settings
adamziel Aug 6, 2020
102e09c
Use schema
adamziel Aug 6, 2020
01b9d0d
lint
adamziel Aug 6, 2020
e788ff1
Use single, global editor instead of separate editors
adamziel Aug 6, 2020
1ca58bb
Update lib/class-wp-rest-sidebars-controller.php
adamziel Aug 7, 2020
89b7994
Update lib/class-wp-rest-widget-utils-controller.php
adamziel Aug 7, 2020
fa1c050
Update packages/edit-widgets/src/components/widget-areas-block-editor…
adamziel Aug 7, 2020
9fc82ec
Remove lib/class-experimental-wp-widget-blocks-manager.php
adamziel Aug 7, 2020
30b5b75
Clean up the endpoints
adamziel Aug 7, 2020
cd15be0
Invoke getWidgetAreas at the top level
adamziel Aug 7, 2020
176cc3c
rename widgetArea entity to sidebars
adamziel Aug 7, 2020
3f4fd5a
Enable the experiment code conditionally
adamziel Aug 7, 2020
97c2b7a
Load Gutenberg styles on widgets.php
adamziel Aug 7, 2020
f3cf1ab
Make the API compatible with old-style widgets
adamziel Aug 7, 2020
07db7d1
Clean up WP_REST_Widget_Utils_Controller
adamziel Aug 7, 2020
13c3db0
revert code data layer change
adamziel Aug 7, 2020
48c7c35
Add unit tests for the endpoints
adamziel Aug 7, 2020
4dc08e0
Fix indexing bug
adamziel Aug 7, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,12 @@ function register_site_icon_url( $response ) {
}

add_filter( 'rest_index', 'register_site_icon_url' );

/**
* Registers the WP_Widget_Block widget
*/
function gutenberg_register_widgets() {
register_widget( 'WP_Widget_Block' );
}

add_action( 'widgets_init', 'gutenberg_register_widgets' );
268 changes: 1 addition & 267 deletions lib/class-experimental-wp-widget-blocks-manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,107 +58,6 @@ public static function get_wp_registered_sidebars_sidebar( $sidebar_id ) {
return $wp_registered_sidebars[ $sidebar_id ];
}

/**
* Returns the result of wp_get_sidebars_widgets without swap_out_sidebars_blocks_for_block_widgets filter being applied.
*
* @since 5.7.0
*/
private static function get_raw_sidebar_widgets() {
return self::$unfiltered_sidebar_widgets;
}

/**
* Returns a post id being referenced in a sidebar area.
*
* @since 5.7.0
*
* @param string $sidebar_id Identifier of the sidebar.
* @return integer Post id.
*/
public static function get_post_id_referenced_in_sidebar( $sidebar_id ) {
$sidebars = self::get_raw_sidebar_widgets();
$sidebar = $sidebars[ $sidebar_id ];
return is_numeric( $sidebar ) ? $sidebar : 0;
}

/**
* Updates a sidebar structure to reference a $post_id, and makes the widgets being referenced inactive.
*
* @since 5.7.0
*
* @param string $sidebar_id Identifier of the sidebar.
* @param integer $post_id Post id.
*/
public static function reference_post_id_in_sidebar( $sidebar_id, $post_id ) {
$sidebars = self::get_raw_sidebar_widgets();
$sidebar = $sidebars[ $sidebar_id ];
wp_set_sidebars_widgets(
array_merge(
$sidebars,
array(
$sidebar_id => $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 Identifier of the sidebar.
* @return array $post_id Post id.
*/
public static function get_sidebar_as_blocks( $sidebar_id ) {
$blocks = array();

$sidebars_items = self::get_raw_sidebar_widgets();
$wp_registered_sidebars = self::get_wp_registered_sidebars();

foreach ( $sidebars_items[ $sidebar_id ] as $item ) {
$widget_class = self::get_widget_class( $item );
list( $object, $number ) = self::get_widget_info( $item );
$new_block = array(
'blockName' => 'core/legacy-widget',
'attrs' => array(
'id' => $item,
'instance' => self::get_sidebar_widget_instance( $wp_registered_sidebars[ $sidebar_id ], $item ),
),
'innerHTML' => '',
);
if ( null !== $widget_class ) {
$new_block['attrs']['widgetClass'] = $widget_class;
}
if ( isset( $object->id_base ) ) {
$new_block['attrs']['idBase'] = $object->id_base;
}
if ( is_int( $number ) ) {
$new_block['attrs']['number'] = $number;
}
$blocks[] = $new_block;
}
return $blocks;
}

/**
* Verifies if a sidebar id is valid or not.
*
* @since 5.7.0
*
* @param string $sidebar_id Identifier of the sidebar.
* @return boolean True if the $sidebar_id value is valid and false otherwise.
*/
public static function is_valid_sidebar_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.
*
Expand Down Expand Up @@ -187,7 +86,7 @@ private static function get_widget_class( $widget_id ) {
* @param string $id Identifier of the widget instance.
* @return array Array containing the widget instance.
*/
private static function get_sidebar_widget_instance( $sidebar, $id ) {
public static function get_sidebar_widget_instance( $sidebar, $id ) {
list( $object, $number, $name ) = self::get_widget_info( $id );
if ( ! $object ) {
return array();
Expand Down Expand Up @@ -252,169 +151,4 @@ private static function get_widget_info( $widget_id ) {
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 ) {
if ( ! isset( $block['blockName'] ) ) {
return false;
}
$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(
'<!-- wp:%s%s /-->',
$name,
$opening_tag_suffix
);
} else {
return sprintf(
'<!-- wp:%1$s%2$s -->%3$s<!-- /wp:%1$s -->',
$name,
$opening_tag_suffix,
$block['innerHTML']
);
}
}

/**
* Outputs a block widget on the website frontend.
*
* @param array $options Widget options.
* @param array $arguments Arguments array.
*/
public static function output_blocks_widget( $options, $arguments ) {
echo $options['before_widget'];
foreach ( $arguments['blocks'] as $block ) {
echo render_block( $block );
}
echo $options['after_widget'];
}

/**
* Noop block widget control output function for the necessary call to `wp_register_widget_control`.
*/
public static function output_blocks_widget_control() {}

/**
* Registers a widget that should represent a set of blocks and returns its ID.
*
* @param array $blocks Array of blocks.
*/
public static function convert_blocks_to_widget( $blocks ) {
$widget_id = 'blocks-widget-' . md5( self::serialize_blocks( $blocks ) );
global $wp_registered_widgets;
if ( isset( $wp_registered_widgets[ $widget_id ] ) ) {
return $widget_id;
}
wp_register_sidebar_widget(
$widget_id,
__( 'Blocks Area', 'gutenberg' ),
'Experimental_WP_Widget_Blocks_Manager::output_blocks_widget',
array(
'classname' => 'widget-area',
'description' => __( 'Displays a set of blocks', 'gutenberg' ),
),
array(
'blocks' => $blocks,
)
);
wp_register_widget_control(
$widget_id,
__( 'Blocks Area', 'gutenberg' ),
'Experimental_WP_Widget_Blocks_Manager::output_blocks_widget_control',
array( 'id_base' => 'blocks-widget' )
);
return $widget_id;
}

/**
* Filters the $sidebars_widgets to exchange wp_area post id with a widget that renders that block area.
*
* @param array $sidebars_widgets_input An associative array of sidebars and their widgets.
*/
public static function swap_out_sidebars_blocks_for_block_widgets( $sidebars_widgets_input ) {
global $sidebars_widgets;
global $wp_customize;
if ( null === self::$unfiltered_sidebar_widgets ) {
self::$unfiltered_sidebar_widgets = $sidebars_widgets;
}
$changeset_data = null;
if ( function_exists( 'is_customize_preview' ) && is_customize_preview() ) {
$changeset_data = $wp_customize->changeset_data();
if ( isset( $changeset_data['gutenberg_widget_blocks']['value'] ) ) {
$changeset_data = json_decode( $changeset_data['gutenberg_widget_blocks']['value'] );
}
}

$filtered_sidebar_widgets = array();
foreach ( $sidebars_widgets_input as $sidebar_id => $item ) {
$changeset_value = $changeset_data && isset( $changeset_data->$sidebar_id )
? $changeset_data->$sidebar_id
: null;

if ( ! is_numeric( $item ) && ! $changeset_value ) {
$filtered_sidebar_widgets[ $sidebar_id ] = $item;
continue;
}

$filtered_widgets = array();
$last_set_of_blocks = array();
$blocks = parse_blocks(
$changeset_value ? $changeset_value : get_post( $item )->post_content
);

foreach ( $blocks as $block ) {
if ( ! isset( $block['blockName'] ) ) {
continue;
}
if (
'core/legacy-widget' === $block['blockName'] &&
isset( $block['attrs']['identifier'] )
) {
if ( ! empty( $last_set_of_blocks ) ) {
$filtered_widgets[] = self::convert_blocks_to_widget( $last_set_of_blocks );
$last_set_of_blocks = array();
}
$filtered_widgets[] = $block['attrs']['identifier'];
} else {
$last_set_of_blocks[] = $block;
}
}
if ( ! empty( $last_set_of_blocks ) ) {
$filtered_widgets[] = self::convert_blocks_to_widget( $last_set_of_blocks );
}

$filtered_sidebar_widgets[ $sidebar_id ] = $filtered_widgets;
}
$sidebars_widgets = $filtered_sidebar_widgets;

return $filtered_sidebar_widgets;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't look like there is much functionality left in lib/class-experimental-wp-widget-blocks-manager.php. It's also not clear how the changes in this file would look when they're added to Core. Having a _Manager class in Core is unprecedented.

I'd suggest deleting lib/class-experimental-wp-widget-blocks-manager.php and moving the remaining functions into private functions in the REST API classes that use them.

If we do want to add new widget functions to Core, they should exist in compat.php with a clear description of where they should land when merged downstream.

}
Loading