[wp-trac] [WordPress Trac] #33507: Allow widget controls to be JS-driven
WordPress Trac
noreply at wordpress.org
Thu Jan 28 16:25:15 UTC 2016
#33507: Allow widget controls to be JS-driven
-------------------------+--------------------------------------
Reporter: westonruter | Owner: westonruter
Type: enhancement | Status: accepted
Priority: normal | Milestone: Future Release
Component: Widgets | Version: 3.9
Severity: normal | Resolution:
Keywords: | Focuses: javascript, performance
-------------------------+--------------------------------------
Old description:
> 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.
>
> Most of the above logic can be eliminated entirely if widget controls
> handled rendering of the controls and sanitization of the instance data
> purely with JavaScript, just like every other Customizer control normally
> behaves.
>
> Widgets would hugely benefit from a revamp following patterns laid down
> in Customizer controls. Customizer controls were designed to be JS-driven
> from the start. A Customizer control gets associated with a Customizer
> setting, the control then applies the setting data onto the control’s
> template and the inputs are automatically synced back to the setting—this
> is accomplished via two-way data bindings provided by
> `wp.customize.Element`. So controls in the Customizer handle UI
> validation purely with JavaScript. There is no need for an Ajax request
> because the logic is in the client. (True this means that the
> sanitization logic has to be duplicated in PHP and JS, but this can be
> minimized by adopting a common schema for the input types.)
>
> 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.
New description:
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.
Most of the above logic can be eliminated entirely if widget controls
handled rendering of the controls and sanitization of the instance data
purely with JavaScript, just like every other Customizer control normally
behaves.
Widgets would hugely benefit from a revamp following patterns laid down in
Customizer controls. Customizer controls were designed to be JS-driven
from the start. A Customizer control gets associated with a Customizer
setting, the control then applies the setting data onto the control’s
template and the inputs are automatically synced back to the setting—this
is accomplished via two-way data bindings provided by
`wp.customize.Element`. So controls in the Customizer handle UI validation
purely with JavaScript. There is no need for an Ajax request because the
logic is in the client. (True this means that the sanitization logic has
to be duplicated in PHP and JS, but this can be minimized by adopting a
common schema for the input types.)
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)
--
Comment (by westonruter):
Dependency: #35574 (Add REST API JSON schema information to WP_Widget)
--
Ticket URL: <https://core.trac.wordpress.org/ticket/33507#comment:12>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list