Skip to content

Commit

Permalink
Add legacy widget by id
Browse files Browse the repository at this point in the history
  • Loading branch information
jorgefilipecosta committed Sep 2, 2019
1 parent 79d2886 commit b525de5
Show file tree
Hide file tree
Showing 10 changed files with 355 additions and 133 deletions.
8 changes: 4 additions & 4 deletions lib/class-experimental-wp-widget-blocks-manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,9 @@ public static function get_sidebar_as_blocks( $sidebar_id ) {
$blocks[] = array(
'blockName' => 'core/legacy-widget',
'attrs' => array(
'class' => $widget_class,
'identifier' => $item,
'instance' => self::get_sidebar_widget_instance( $wp_registered_sidebars[ $sidebar_id ], $item ),
'widgetClass' => $widget_class,
'identifier' => $item,
'instance' => self::get_sidebar_widget_instance( $wp_registered_sidebars[ $sidebar_id ], $item ),
),
'innerHTML' => '',
);
Expand Down Expand Up @@ -177,7 +177,7 @@ private static function get_widget_class( $widget_id ) {
* @param string $id Idenfitier 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
180 changes: 148 additions & 32 deletions lib/class-wp-rest-widget-updater-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,30 @@ public function __construct() {
public function register_routes() {
register_rest_route(
$this->namespace,
// Regex representing a PHP class extracted from http://php.net/manual/en/language.oop5.basic.php.
'/' . $this->rest_base . '/(?P<identifier>[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)/',
'/' . $this->rest_base . '/',
array(
'args' => array(
'identifier' => array(
'widget_class' => array(
'description' => __( 'Class name of the widget.', 'gutenberg' ),
'type' => 'string',
'required' => false,
'default' => null,
),
'identifier' => array(
'description' => __( 'Identifier of the widget.', 'gutenberg' ),
'type' => 'string',
'required' => false,
'default' => null,
),
'instance' => array(
'description' => __( 'Current widget instance', 'gutenberg' ),
'type' => 'object',
'default' => array(),
),
'instance_changes' => array(
'description' => __( 'Array of instance changes', 'gutenberg' ),
'type' => 'object',
'default' => array(),
),
),
array(
Expand Down Expand Up @@ -76,53 +93,120 @@ public function compute_new_widget_permissions_check() {
}

/**
* Returns the new widget instance and the form that represents it.
* Checks if the widget being referenced is valid.
*
* @since 5.2.0
* @access public
* @param string $identifier Instance identifier of the widget.
* @param string $widget_class Name of the class the widget references.
*
* @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.
* @return boolean True if the widget being referenced exists and false otherwise.
*/
public function compute_new_widget( $request ) {
$url_params = $request->get_url_params();

$widget = $request->get_param( 'identifier' );
private function is_valid_widget( $identifier, $widget_class ) {
global $wp_widget_factory, $wp_registered_widgets;
if ( ! $identifier && ! $widget_class ) {
return false;
}
if ( $identifier ) {
return isset( $wp_registered_widgets[ $identifier ] );
}
return isset( $wp_widget_factory->widgets[ $widget_class ] ) &&
( $wp_widget_factory->widgets[ $widget_class ] instanceof WP_Widget );
}

global $wp_widget_factory;
/**
* Computes an array with instance changes cleaned of widget specific prefixes and sufixes.
*
* @since 5.7.0
* @param string $id_base Widget ID Base.
* @param string $id Widget instance identifier.
* @param array $instance_changes Array with the form values being being changed.
*
* @return array An array based on $instance_changes whose keys have the widget specific sufixes and prefixes removed.
*/
private function parse_instance_changes( $id_base, $id, $instance_changes ) {
$instance_changes_parsed = array();
$start_position = strlen( 'widget-' . $id_base . '[' . $id . '][' );
foreach ( $instance_changes as $key => $value ) {
$key_parsed = substr( $key, $start_position, -1 );
$instance_changes_parsed[ $key_parsed ] = $value;
}
return $instance_changes_parsed;
}

/**
* Returns the edit form of the widget being referenced.
*
* @since 5.7.0
* @param string $identifier Instance identifier of the widget.
*
* @return WP_REST_Response Response object.
*/
private function handle_reference_widgets( $identifier ) {
global $wp_registered_widget_controls;
$form = '';
$id_base = $identifier;
$id = $identifier;
$number = null;
if (
null === $widget ||
! isset( $wp_widget_factory->widgets[ $widget ] ) ||
! ( $wp_widget_factory->widgets[ $widget ] instanceof WP_Widget )
isset( $wp_registered_widget_controls[ $identifier ]['callback'] ) &&
is_callable( $wp_registered_widget_controls[ $identifier ]['callback'] )
) {
return new WP_Error(
'widget_invalid',
__( 'Invalid widget.', 'gutenberg' ),
array(
'status' => 404,
)
);
$control = $wp_registered_widget_controls[ $identifier ];
ob_start();
call_user_func_array( $control['callback'], $control['params'] );
$form = ob_get_clean();
if ( isset( $control['id_base'] ) ) {
$id_base = $control['id_base'];
}
if ( isset( $control['params'][0]['number'] ) ) {
$number = $control['params'][0]['number'];
}
}

$widget_obj = $wp_widget_factory->widgets[ $widget ];
return rest_ensure_response(
array(
'instance' => array(),
'form' => $form,
'id_base' => $id_base,
'id' => $id,
'number' => $number,
)
);
}

$instance = $request->get_param( 'instance' );
/**
* Returns the new class widget instance and the form that represents it.
*
* @since 5.7.0
* @access public
*
* @param string $widget_class Widget id for callback widgets or widget class name for class widgets.
* @param array $instance Previous widget instance.
* @param array $instance_changes Array with the form values being being changed.
* @param string $id_to_use Identifier of the specific widget instance.
* @return WP_REST_Response Response object on success, or WP_Error object on failure.
*/
private function handle_class_widgets( $widget_class, $instance, $instance_changes, $id_to_use ) {
if ( null === $instance ) {
$instance = array();
}
$id_to_use = $request->get_param( 'id_to_use' );
if ( null === $id_to_use ) {
$id_to_use = -1;
}

global $wp_widget_factory;
$widget_obj = $wp_widget_factory->widgets[ $widget_class ];

$widget_obj->_set( $id_to_use );
$id_base = $widget_obj->id_base;
$id = $widget_obj->id;
ob_start();

$instance_changes = $request->get_param( 'instance_changes' );
if ( null !== $instance_changes ) {
$old_instance = $instance;
$instance = $widget_obj->update( $instance_changes, $old_instance );
$instance_changes = $this->parse_instance_changes( $id_base, $id_to_use, $instance_changes );
$old_instance = $instance;
$instance = $widget_obj->update( $instance_changes, $old_instance );

/**
* Filters a widget's settings before saving.
*
Expand Down Expand Up @@ -166,20 +250,52 @@ public function compute_new_widget( $request ) {
*/
do_action_ref_array( 'in_widget_form', array( &$widget_obj, &$return, $instance ) );
}

$id_base = $widget_obj->id_base;
$id = $widget_obj->id;
$form = ob_get_clean();
$form = ob_get_clean();

return rest_ensure_response(
array(
'instance' => $instance,
'form' => $form,
'id_base' => $id_base,
'id' => $id,
'number' => $id_to_use,
)
);
}

/**
* Returns the new widget instance and the form that represents it.
*
* @since 5.7.0
* @access public
*
* @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 compute_new_widget( $request ) {
$identifier = $request->get_param( 'identifier' );
$widget_class = $request->get_param( 'widget_class' );

if ( ! $this->is_valid_widget( $identifier, $widget_class ) ) {
return new WP_Error(
'widget_invalid',
__( 'Invalid widget.', 'gutenberg' ),
array(
'status' => 404,
)
);
}

if ( $identifier ) {
return $this->handle_reference_widgets( $identifier );
}
return $this->handle_class_widgets(
$widget_class,
$request->get_param( 'instance' ),
$request->get_param( 'instance_changes' ),
$request->get_param( 'id_to_use' )
);
}
}
/**
* End: Include for phase 2
Expand Down
2 changes: 2 additions & 0 deletions lib/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
}
if ( ! class_exists( 'WP_REST_Widget_Areas_Controller' ) ) {
require dirname( __FILE__ ) . '/class-experimental-wp-widget-blocks-manager.php';
}
if ( ! class_exists( 'WP_REST_Widget_Areas_Controller' ) ) {
require dirname( __FILE__ ) . '/class-wp-rest-widget-areas-controller.php';
}
/**
Expand Down
1 change: 1 addition & 0 deletions lib/widgets-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ function gutenberg_widgets_init( $hook ) {
);

wp_enqueue_script( 'wp-edit-widgets' );
wp_enqueue_script( 'admin-widgets' );
wp_enqueue_script( 'wp-format-library' );
wp_enqueue_style( 'wp-edit-widgets' );
wp_enqueue_style( 'wp-format-library' );
Expand Down
25 changes: 22 additions & 3 deletions lib/widgets.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@ function gutenberg_block_editor_admin_print_footer_scripts() {
*/
function gutenberg_block_editor_admin_footer() {
if ( gutenberg_is_block_editor() ) {
echo implode(
"\n",
array(
'<form method="post">',
wp_nonce_field( 'save-sidebar-widgets', '_wpnonce_widgets', false ),
'</form>',
)
);
/** This action is documented in wp-admin/admin-footer.php */
// phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
do_action( 'admin_footer-widgets.php' );
Expand Down Expand Up @@ -124,10 +132,12 @@ function gutenberg_get_legacy_widget_settings() {
global $wp_registered_widgets;
if ( ! empty( $wp_registered_widgets ) ) {
foreach ( $wp_registered_widgets as $widget_id => $widget_obj ) {
$block_widget_start = 'blocks-widget-';
if (
is_array( $widget_obj['callback'] ) &&
( is_array( $widget_obj['callback'] ) &&
isset( $widget_obj['callback'][0] ) &&
( $widget_obj['callback'][0] instanceof WP_Widget )
( $widget_obj['callback'][0] instanceof WP_Widget ) ) ||
strncmp( $widget_id, $block_widget_start, strlen( $block_widget_start ) ) === 0
) {
continue;
}
Expand All @@ -142,7 +152,7 @@ function gutenberg_get_legacy_widget_settings() {
$settings['hasPermissionsToManageWidgets'] = $has_permissions_to_manage_widgets;
$settings['availableLegacyWidgets'] = $available_legacy_widgets;

return $settings;
return gutenberg_experiments_editor_settings( $settings );
}

/**
Expand Down Expand Up @@ -213,3 +223,12 @@ function gutenberg_create_wp_area_post_type() {
add_action( 'init', 'gutenberg_create_wp_area_post_type' );

add_filter( 'sidebars_widgets', 'Experimental_WP_Widget_Blocks_Manager::swap_out_sidebars_blocks_for_block_widgets' );

/**
* Function to enqueue admin-widgets as part of the block editor assets.
*/
function gutenberg_enqueue_widget_scripts() {
wp_enqueue_script( 'admin-widgets' );
}

add_action( 'enqueue_block_editor_assets', 'gutenberg_enqueue_widget_scripts' );
Loading

0 comments on commit b525de5

Please sign in to comment.