Allow widget controls to be JS-driven
|Reported by:||westonruter||Owned by:||westonruter|
Description (last modified by westonruter)
Widgets currently have an almost complete reliance on PHP for all aspects of their behavior:
- Generating the control form via WP_Widget::form()
- Validating the instance data via WP_Widget::update()
- Rendering the widget into the template via WP_Widget::widget()
The dependence on PHP can make managing widgets in WordPress relatively slow. In the Customizer, it can be excruciatingly slow since the widget form control is presented alongside the widget in the preview, and so the slow roundtrip time for sanitization and rendering is clear (especially with full-page refreshes of the Customizer, which is to be mitigated in #27355 via partial refreshes).
In the Customizer, making a change to a widget form field results in an update-widget Ajax call to pass the full form data to WordPress to pass it through the widget’s update callback for sanitization. The Ajax handler then passes this updated instance through the form callback, and the HTML output of the form callback then gets sent back in the Ajax response. (Look at the number of Ajax requests triggered when typing into a widget field.) The Customizer widget logic then tries to apply the sanitized instance data by aligning the input fields in the widget form shown in the Customizer with the input fields sent in the Ajax response. When the input fields are aligned (when the same inputs are present), then the inputs’ values will be updated to their sanitized values and a widget-synced jQuery event is triggered. But if the inputs cannot be aligned (which can happen easily if any of the fields are created dynamically), then it falls back to showing an Update button which will do a full replacement of the widget form, just as is done on the widgets admin page (and a widget-updated jQuery event is triggered). Then finally, once the widget instance is updated, then the Customizer preview can do its full page refresh with the widget instance previewed in the template.
Naturally these new JS-driven widgets would need to be backwards compatible with existing widgets. We can allow a widget to opt-in to indicate it is JS-driven by supplying a new flag to the seldom-used $control_options param to WP_Widget::__construct() (which is used to pass the infamous width/height for wide widget form controls), for example:
When this is present, the Customizer would disable the existing update mechanism and defer to the control’s own logic.
Note that these new JS-driven widget controls in the Customizer would be implemented in a very similar way to how nav menu item controls have been implemented in the Customizer in 4.3. The overall widget control would be associated with a single widget instance setting. The widget’s setting would be just the JSON-serializable instance array (object) as opposed to a scalar value, and each property in the setting value would then get mapped to a different wp.customize.Element in the widget control: the inputs’ values would then get synced back into property of the setting object value by means of wp.customize.Element instances.
Some widget controls would still depend on the server for UI validation, for instance the RSS widget. However, only specific fields would need to be validated as opposed to the entire form. Note again that full server-side validation of the widget instance data would still be required. Ideally the duplication of logic here could be reduced by having a schema that both the JS and PHP validation logic could read from.
While the above focuses specifically on making the WP_Widget::form() and WP_Widget::update() both JS-driven, there may also be an opportunity to allow widgets to opt-in to JS-driven rendering of a given widget (i.e. implementing WP_Widget::widget(), in JS). This would make a lot of sense if the widget defined its template in Mustache (or Twig) and then allowed the instance array to be applied to that template either server-side or client-side. The effect for client-side would be postMessage instant previews of changes to widgets in the Customizer. The PHP-driven performant alternative to this would be partial-refresh as outlined in #27355.
By using JS-driven widgets, we will be able to use control templates for the widget controls as opposed to having to include a separate copy of the widget form with each control's params. This can drastically reduce the page weight, since the control template only needs to be included once.
By implementing JS-driven widget controls, the user experience of managing widgets would be vastly improved and the server load would be greatly reduced.
Depends on #35574 (Add REST API JSON schema information to WP_Widget)
See feature plugin: https://github.com/xwp/wp-js-widgets
Change History (24)
21 months ago
- Summary changed from Revamp widgets to be JS-driven to Allow widget controls to be JS-driven