Skip to content

Commit

Permalink
Try Legacy widget block
Browse files Browse the repository at this point in the history
  • Loading branch information
jorgefilipecosta committed Jan 25, 2019
1 parent 1748145 commit 35e0180
Show file tree
Hide file tree
Showing 15 changed files with 607 additions and 4 deletions.
10 changes: 10 additions & 0 deletions gutenberg.php
Expand Up @@ -55,6 +55,13 @@ function the_gutenberg_project() {
<div id="metaboxes" style="display: none;">
<?php the_gutenberg_metaboxes(); ?>
</div>
<?php
/** This action is documented in wp-admin/admin-footer.php */
do_action( 'admin_print_footer_scripts-widgets.php' );

/** This action is documented in wp-admin/admin-footer.php */
do_action( 'admin_footer-widgets.php' );
?>
</div>
<?php
}
Expand Down Expand Up @@ -232,6 +239,9 @@ function gutenberg_init( $return, $post ) {
*/
remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );

do_action( 'admin_print_styles-widgets.php' );
do_action( 'admin_print_scripts-widgets.php' );

/*
* Ensure meta box functions are available to third-party code;
* includes/meta-boxes is typically loaded from edit-form-advanced.php.
Expand Down
106 changes: 106 additions & 0 deletions lib/class-wp-rest-widget-updater-controller.php
@@ -0,0 +1,106 @@
<?php
/**
* Widget Updater REST API: WP_REST_Widget_Updater_Controller class
*
* @package gutenberg
* @since 4.9.0
*/

/**
* Controller which provides REST endpoint for updating a widget.
*
* @since 2.8.0
*
* @see WP_REST_Controller
*/
class WP_REST_Widget_Updater_Controller extends WP_REST_Controller {

/**
* Constructs the controller.
*
* @access public
*/
public function __construct() {
$this->namespace = 'wp/v2';
$this->rest_base = 'widget-updater';
}

/**
* Registers the necessary REST API route.
*
* @access public
*/
public function register_routes() {
register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/',
array(
'args' => array(
'name' => array(
'description' => __( 'Unique registered name for the block.', 'gutenberg' ),
'type' => 'string',
),
),
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'compute_new_widget' ),
),
)
);
}

/**
* Returns the new widget instance and the form that represents it.
*
* @since 2.8.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 ) {
$json_request = $request->get_json_params();
if ( ! isset( $json_request['identifier'] ) ) {
return;
}
$widget = $json_request['identifier'];
global $wp_widget_factory;

if ( ! isset( $wp_widget_factory->widgets[ $widget ] ) ) {
return;
}

$widget_obj = $wp_widget_factory->widgets[ $widget ];
if ( ! ( $widget_obj instanceof WP_Widget ) ) {
return;
}

$instance = isset( $json_request['instance'] ) ? $json_request['instance'] : array();

$id_to_use = isset( $json_request['id_to_use'] ) ? $json_request['id_to_use'] : -1;

$widget_obj->_set( $id_to_use );
ob_start();

if ( isset( $json_request['instance_changes'] ) ) {
$instance = $widget_obj->update( $json_request['instance_changes'], $instance );
// TODO: apply required filters.
}

$widget_obj->form( $instance );
// TODO: apply required filters.

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

return rest_ensure_response(
array(
'instance' => $instance,
'form' => $form,
'id_base' => $id_base,
'id' => $id,
)
);
}
}
11 changes: 11 additions & 0 deletions lib/client-assets.php
Expand Up @@ -1216,9 +1216,20 @@ function gutenberg_editor_scripts_and_styles( $hook ) {
);
}

$available_legacy_widgets = array();
global $wp_widget_factory;

foreach ( $wp_widget_factory->widgets as $class => $widget_obj ) {
$available_legacy_widgets[ $class ] = array(
'name' => html_entity_decode( $widget_obj->name ),
'description' => html_entity_decode( $widget_obj->widget_options['description'] ),
);
}

$editor_settings = array(
'alignWide' => $align_wide || ! empty( $gutenberg_theme_support[0]['wide-images'] ), // Backcompat. Use `align-wide` outside of `gutenberg` array.
'availableTemplates' => $available_templates,
'availableLegacyWidgets' => $available_legacy_widgets,
'allowedBlockTypes' => $allowed_block_types,
'disableCustomColors' => get_theme_support( 'disable-custom-colors' ),
'disableCustomFontSizes' => get_theme_support( 'disable-custom-font-sizes' ),
Expand Down
9 changes: 9 additions & 0 deletions lib/load.php
Expand Up @@ -12,6 +12,9 @@
// These files only need to be loaded if within a rest server instance
// which this class will exist if that is the case.
if ( class_exists( 'WP_REST_Controller' ) ) {
if ( ! class_exists( 'WP_REST_Widget_Updater_Controller' ) ) {
require dirname( __FILE__ ) . '/class-wp-rest-widget-updater-controller.php';
}
require dirname( __FILE__ ) . '/rest-api.php';
}

Expand Down Expand Up @@ -43,9 +46,15 @@
if ( ! function_exists( 'render_block_core_latest_posts' ) ) {
require dirname( __FILE__ ) . '/../packages/block-library/src/latest-posts/index.php';
}

if ( ! function_exists( 'render_block_legacy_widget' ) ) {
require dirname( __FILE__ ) . '/../packages/block-library/src/legacy-widget/index.php';
}

if ( ! function_exists( 'render_block_core_rss' ) ) {
require dirname( __FILE__ ) . '/../packages/block-library/src/rss/index.php';
}
if ( ! function_exists( 'render_block_core_shortcode' ) ) {
require dirname( __FILE__ ) . '/../packages/block-library/src/shortcode/index.php';
}

11 changes: 11 additions & 0 deletions lib/rest-api.php
Expand Up @@ -20,6 +20,17 @@ function gutenberg_register_rest_routes() {
_deprecated_function( __FUNCTION__, '5.0.0' );
}

/**
* Registers the REST API routes needed by the legacy widget block.
*
* @since 5.0.0
*/
function gutenberg_register_rest_widget_updater_routes() {
$widgets_controller = new WP_REST_Widget_Updater_Controller();
$widgets_controller->register_routes();
}
add_action( 'rest_api_init', 'gutenberg_register_rest_widget_updater_routes' );

/**
* Make sure oEmbed REST Requests apply the WP Embed security mechanism for WordPress embeds.
*
Expand Down
1 change: 1 addition & 0 deletions packages/block-library/src/editor.scss
Expand Up @@ -14,6 +14,7 @@
@import "./image/editor.scss";
@import "./latest-comments/editor.scss";
@import "./latest-posts/editor.scss";
@import "./legacy-widget/editor.scss";
@import "./media-text/editor.scss";
@import "./list/editor.scss";
@import "./more/editor.scss";
Expand Down
2 changes: 2 additions & 0 deletions packages/block-library/src/index.js
Expand Up @@ -31,6 +31,7 @@ import * as html from './html';
import * as mediaText from './media-text';
import * as latestComments from './latest-comments';
import * as latestPosts from './latest-posts';
import * as legacyWidget from './legacy-widget';
import * as list from './list';
import * as missing from './missing';
import * as more from './more';
Expand Down Expand Up @@ -81,6 +82,7 @@ export const registerCoreBlocks = () => {
mediaText,
latestComments,
latestPosts,
legacyWidget,
missing,
more,
nextpage,
Expand Down
86 changes: 86 additions & 0 deletions packages/block-library/src/legacy-widget/WidgetEditDomManager.js
@@ -0,0 +1,86 @@
/**
* External dependencies
*/
import { includes } from 'lodash';

/**
* WordPress dependencies
*/
import { Component, createRef } from '@wordpress/element';

class WidgetEditDomManager extends Component {
constructor() {
super( ...arguments );

this.containerRef = createRef();
this.triggerWidgetEvent = this.triggerWidgetEvent.bind( this );
}

componentDidMount() {
this.triggerWidgetEvent( 'widget-added' );
}

shouldComponentUpdate( nextProps ) {
// We can not leverage react render otherwise we would destroy dom changes applied by the plugins.
// We manually update the required dom node replicating what the widget screen and the customizer do.
if ( nextProps.form !== this.props.form && this.containerRef.current ) {
const widgetContent = this.containerRef.current.querySelector( '.widget-content' );
widgetContent.innerHTML = nextProps.form;
this.triggerWidgetEvent( 'widget-updated' );
}
return false;
}

render() {
const { id, idBase, widgetNumber, form } = this.props;
return (
<div className="widget open" ref={ this.containerRef }>
<div className="widget-inside">
<form method="post">
<div className="widget-content" dangerouslySetInnerHTML={ { __html: form } }>
</div>
<input type="hidden" name="widget-id" className="widget-id" value={ id } />
<input type="hidden" name="id_base" className="id_base" value={ idBase } />
<input type="hidden" name="widget_number" className="widget_number" value={ widgetNumber } />
<input type="hidden" name="multi_number" className="multi_number" value="" />
<input type="hidden" name="add_new" className="add_new" value="" />
</form>
</div>
</div>
);
}

triggerWidgetEvent( event ) {
window.$( window.document ).trigger(
event,
[ window.$( this.containerRef.current ) ]
);
}

retrieveUpdatedInstance() {
if ( this.containerRef.current ) {
const { idBase, widgetNumber } = this.props;
const form = this.containerRef.current.querySelector( 'form' );
const formData = new window.FormData( form );
const updatedInstance = {};
const keyPrefixLength = `widget-${ idBase }[${ widgetNumber }][`.length;
const keySuffixLength = `]`.length;
for ( const [ rawKey, value ] of formData ) {
const keyParsed = rawKey.substring( keyPrefixLength, rawKey.length - keySuffixLength );
// This fields are added to the form because the widget JavaScript code may use this values.
// They are not relevant for the update mechanism.
if ( includes(
[ 'widget-id', 'id_base', 'widget_number', 'multi_number', 'add_new' ],
keyParsed,
) ) {
continue;
}
updatedInstance[ keyParsed ] = value;
}
return updatedInstance;
}
}
}

export default WidgetEditDomManager;

0 comments on commit 35e0180

Please sign in to comment.