[wp-trac] [WordPress Trac] #33507: Revamp widgets to be JS-driven

WordPress Trac noreply at wordpress.org
Sat Aug 22 05:30:03 UTC 2015


#33507: Revamp widgets to be JS-driven
-------------------------------------+-----------------
 Reporter:  westonruter              |      Owner:
     Type:  enhancement              |     Status:  new
 Priority:  normal                   |  Milestone:  4.4
Component:  Widgets                  |    Version:  3.9
 Severity:  normal                   |   Keywords:
  Focuses:  javascript, performance  |
-------------------------------------+-----------------
 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 implementing JS-driven widget controls, the user experience of managing
 widgets would be vastly improved and the server load would be greatly
 reduced.

--
Ticket URL: <https://core.trac.wordpress.org/ticket/33507>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list