-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Customizer: Add widget blocks section. #16204
Changes from 14 commits
1c6a4ff
2ad8caf
9180ac2
8b6e94f
271a49f
0643ace
4092380
e41149b
d2c4f53
870d6af
5ad559f
4308984
b3211fb
a86e801
87f2c37
f1985b6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -308,9 +308,9 @@ public static function output_blocks_widget( $options, $arguments ) { | |
} | ||
|
||
/** | ||
* Registers of a widget that should represent a set of blocks and returns its id. | ||
* Registers a widget that should represent a set of blocks and returns its ID. | ||
* | ||
* @param array $blocks Array of blocks. | ||
* @param array $blocks Array of blocks. | ||
*/ | ||
public static function convert_blocks_to_widget( $blocks ) { | ||
$widget_id = 'blocks-widget-' . md5( self::serialize_blocks( $blocks ) ); | ||
|
@@ -320,7 +320,7 @@ public static function convert_blocks_to_widget( $blocks ) { | |
} | ||
wp_register_sidebar_widget( | ||
$widget_id, | ||
__( 'Blocks Area ', 'gutenberg' ), | ||
__( 'Blocks Area', 'gutenberg' ), | ||
'Experimental_WP_Widget_Blocks_Manager::output_blocks_widget', | ||
array( | ||
'classname' => 'widget-area', | ||
|
@@ -330,6 +330,12 @@ public static function convert_blocks_to_widget( $blocks ) { | |
'blocks' => $blocks, | ||
) | ||
); | ||
wp_register_widget_control( | ||
$widget_id, | ||
__( 'Blocks Area', 'gutenberg' ), | ||
'echo', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This still triggers an error:
It seems echo is not considered a callback function, but using a function that prints something would be dangerous anyway as printing something during REST request may make the requests invalid. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will do that 👍 |
||
array( 'id_base' => 'blocks-widget' ) | ||
); | ||
return $widget_id; | ||
} | ||
|
||
|
@@ -340,20 +346,34 @@ public static function convert_blocks_to_widget( $blocks ) { | |
*/ | ||
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 ) { | ||
if ( ! is_numeric( $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(); | ||
$post = get_post( $item ); | ||
$blocks = parse_blocks( $post->post_content ); | ||
$blocks = parse_blocks( | ||
$changeset_value ? $changeset_value : get_post( $item )->post_content | ||
); | ||
|
||
foreach ( $blocks as $block ) { | ||
if ( ! isset( $block['blockName'] ) ) { | ||
|
@@ -379,6 +399,7 @@ public static function swap_out_sidebars_blocks_for_block_widgets( $sidebars_wid | |
$filtered_sidebar_widgets[ $sidebar_id ] = $filtered_widgets; | ||
} | ||
$sidebars_widgets = $filtered_sidebar_widgets; | ||
|
||
return $filtered_sidebar_widgets; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
<?php | ||
/** | ||
* Customizer Widget Blocks Section: WP_Customize_Widget_Blocks_Control class. | ||
* | ||
* @package gutenberg | ||
* @since 6.0.0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since 6.0.0 was published today, we'll need to push these again. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll update it once we are ready to merge. |
||
*/ | ||
|
||
/** | ||
* Class that renders the Customizer control for editing widgets with Gutenberg. | ||
* | ||
* @since 6.0.0 | ||
*/ | ||
class WP_Customize_Widget_Blocks_Control extends WP_Customize_Control { | ||
/** | ||
* Enqueue control related scripts/styles. | ||
* | ||
* @since 6.0.0 | ||
*/ | ||
public function enqueue() { | ||
gutenberg_widgets_init( 'gutenberg_customizer' ); | ||
} | ||
|
||
/** | ||
* Render the control's content. | ||
* | ||
* @since 6.0.0 | ||
*/ | ||
public function render_content() { | ||
?> | ||
<input | ||
id="_customize-input-gutenberg_widget_blocks" | ||
type="hidden" | ||
value="<?php echo esc_attr( $this->value() ); ?>" | ||
<?php $this->link(); ?> | ||
/> | ||
<?php | ||
the_gutenberg_widgets( 'gutenberg_customizer' ); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
<?php | ||
/** | ||
* Bootstraping the Gutenberg Customizer widget blocks section. | ||
* | ||
* Widget area edits made in the Customizer are synced to Customizer | ||
* changesets as an object, encoded as a JSON string, where the keys | ||
* are widget area IDs and the values are serialized block content. | ||
* This file takes care of that syncing using the 2-way data binding | ||
* supported by `WP_Customize_Control`s. The process is as follows: | ||
* | ||
* - On load, the client checks if the current changeset has | ||
* widget areas that it can parse and use to hydrate the store. | ||
* It will load all widget areas for the current theme, but if | ||
* the changeset has content for a given area, it will replace | ||
* its actual published content with the changeset's. | ||
* | ||
* - On edit, the client updates the 2-way bound input with a new object that maps | ||
* widget area IDs and the values are serialized block content, encoded | ||
* as a JSON string. | ||
* | ||
* - On publish, a PHP action will parse the JSON string in the | ||
* changeset and update all the widget areas in it, to store the | ||
* new content. | ||
* | ||
* @package gutenberg | ||
*/ | ||
|
||
/** | ||
* The sanitization function for incoming values for the `gutenberg_widget_blocks` setting. | ||
* It's a JSON string, so it decodes it and encodes it again to make sure it's valid. | ||
* | ||
* @param string $value The incoming value. | ||
*/ | ||
function gutenberg_customize_sanitize( $value ) { | ||
return json_encode( json_decode( $value ) ); | ||
} | ||
|
||
/** | ||
* Gutenberg's Customize Register. | ||
* | ||
* Adds a section to the Customizer for editing widgets with Gutenberg. | ||
* | ||
* @param \WP_Customize_Manager $wp_customize An instance of the class that controls most of the Theme Customization API for WordPress 3.4 and newer. | ||
* @since 6.0.0 | ||
*/ | ||
function gutenberg_customize_register( $wp_customize ) { | ||
require dirname( __FILE__ ) . '/class-wp-customize-widget-blocks-control.php'; | ||
$wp_customize->add_setting( | ||
'gutenberg_widget_blocks', | ||
array( | ||
'default' => '{}', | ||
'type' => 'gutenberg_widget_blocks', | ||
'capability' => 'edit_theme_options', | ||
'transport' => 'postMessage', | ||
'sanitize_callback' => 'gutenberg_customize_sanitize', | ||
) | ||
); | ||
$wp_customize->add_section( | ||
'gutenberg_widget_blocks', | ||
array( 'title' => __( 'Widget Blocks (Experimental)', 'gutenberg' ) ) | ||
); | ||
$wp_customize->add_control( new WP_Customize_Widget_Blocks_Control( | ||
$wp_customize, | ||
'gutenberg_widget_blocks', | ||
array( | ||
'section' => 'gutenberg_widget_blocks', | ||
'settings' => 'gutenberg_widget_blocks', | ||
) | ||
) ); | ||
} | ||
add_action( 'customize_register', 'gutenberg_customize_register' ); | ||
|
||
/** | ||
* Specifies how to save the `gutenberg_widget_blocks` setting. It parses the JSON string and updates the | ||
* referenced widget areas with the new content. | ||
* | ||
* @param string $value The value that is being published. | ||
* @param \WP_Customize_Setting $setting The setting instance. | ||
*/ | ||
function gutenberg_customize_update( $value, $setting ) { | ||
foreach ( json_decode( $value ) as $sidebar_id => $sidebar_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 ); | ||
} | ||
} | ||
} | ||
add_action( 'customize_update_gutenberg_widget_blocks', 'gutenberg_customize_update', 10, 2 ); | ||
|
||
/** | ||
* Filters the Customizer widget settings arguments. | ||
* This is needed because the Customizer registers settings for the raw registered widgets, without going through the `sidebars_widgets` filter. | ||
* The `WP_Customize_Widgets` class expects sidebars to have an array of widgets registered, not a post ID. | ||
* This results in the value passed to `sanitize_js_callback` being `null` and throwing an error. | ||
* | ||
* TODO: Figure out why core is not running the `sidebars_widgets` filter for the relevant part of the code. | ||
* Then, either fix it or change this filter to parse the post IDs and then pass them to the original `sanitize_js_callback`. | ||
* | ||
* @param array $args Array of Customizer setting arguments. | ||
* @param string $id Widget setting ID. | ||
* @return array Maybe modified array of Customizer setting arguments. | ||
*/ | ||
function filter_widget_customizer_setting_args( $args, $id = null ) { | ||
// Posts won't have a settings ID like widgets. We can use that to remove the sanitization callback. | ||
if ( ! isset( $id ) ) { | ||
unset( $args['sanitize_js_callback'] ); | ||
} | ||
|
||
return $args; | ||
} | ||
add_filter( 'widget_customizer_setting_args', 'filter_widget_customizer_setting_args' ); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { | ||
SlotFillProvider, | ||
Popover, | ||
navigateRegions, | ||
} from '@wordpress/components'; | ||
import { __ } from '@wordpress/i18n'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import WidgetAreas from '../widget-areas'; | ||
|
||
import './sync-customizer'; | ||
|
||
function CustomizerEditWidgetsInitializer( { settings } ) { | ||
return ( | ||
<SlotFillProvider> | ||
<div | ||
className="edit-widgets-customizer-edit-widgets-initializer__content" | ||
role="region" | ||
aria-label={ __( 'Widgets screen content' ) } | ||
tabIndex="-1" | ||
> | ||
<WidgetAreas blockEditorSettings={ settings } /> | ||
</div> | ||
<Popover.Slot /> | ||
</SlotFillProvider> | ||
); | ||
} | ||
|
||
export default navigateRegions( CustomizerEditWidgetsInitializer ); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
.edit-widgets-customizer-edit-widgets-initializer__content { | ||
background: #f1f1f1; | ||
margin: 0; | ||
min-height: 100%; | ||
padding: 30px 0; | ||
|
||
.block-editor-block-list__layout { | ||
padding: 0 0 0 18px; | ||
} | ||
|
||
.block-editor-block-list__empty-block-inserter { | ||
left: -18px; | ||
} | ||
|
||
.block-editor-rich-text__editable[data-is-placeholder-visible="true"] + .block-editor-rich-text__editable.wp-block-paragraph { | ||
padding: 0; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the commit, it seems like this was added to avoid missing widget control errors. The control is the edition interface of a widget, and it looks like widget controls are not mandatory, e.g., I can have a print hello widget, without any UI to edit it.
It would be interesting to check if the warnings also happen on other widgets without a control associated as it may be an existing core bug or it may be another problem in our Blocks Area Widget.
For now, I guess if this solution fixes the problem it is something we can use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I found it strange too.