[wp-trac] [WordPress Trac] #32474: Facilitate widgets to be stored in posts instead of options

WordPress Trac noreply at wordpress.org
Sat May 30 07:07:39 UTC 2015


#32474: Facilitate widgets to be stored in posts instead of options
------------------------------+--------------------------
 Reporter:  westonruter       |       Owner:  westonruter
     Type:  enhancement       |      Status:  reopened
 Priority:  normal            |   Milestone:  4.3
Component:  Widgets           |     Version:  2.8
 Severity:  normal            |  Resolution:
 Keywords:  has-patch commit  |     Focuses:
------------------------------+--------------------------

Comment (by westonruter):

 @[comment:19 azaozz]: Thanks for raising these concerns. Let me try to
 address them and explain.

 > Don't see what is fixed by adding that conditional.

 What is fixed is that plugins now have the ''option'' of filtering the
 `widget_{$id_base}` options to return `ArrayIterator` objects instead of
 intrinsic arrays, and `WP_Widget` will handle them successfully. The
 `array_*` functions that had been used in `WP_Widget`'s methods (e.g.
 `is_array()`, `array_key_exists()`, `array_keys()`) were not all
 compatible with the new Array objects in PHP 5. Now with the Core patch,
 `WP_Widget` is more agnostic to what kind of iterable is being passed
 around.

 > If a plugin or a theme wants to use the (hacky) way of intercepting
 options get and set, why should this be in core and not in the plugin?

 The patch is making it possible for plugins to do just this. The patch
 isn't intercepting the options get/set in Core. It's just gracefully
 handling the scenario where `get_option()` is filtered to return an
 `ArrayIterator` (or `ArrayObject`) as opposed to an intrinsic `array`. For
 an example of what a plugin can then do with this accommodation in Core,
 see the Customize Widgets Plus plugin's [https://github.com/xwp/wp-
 customize-widgets-plus/blob/master/php/class-widget-posts.php Widget
 Posts] module (yes, shameless plug).

 The bit of the patch you quote here is unfortunate because PHP (strangely)
 provides no `getKeys()` method for its Array objects. So that's why it is
 using the `getArrayCopy()` method to obtain an array of the keys. But note
 that this method bypasses the accessor methods like
 `ArrayIterator::offsetGet()` and `ArrayIterator::current()`, so if those
 methods are indeed lazy-loading widget instance data from posts, this will
 not be involved when `getArrayCopy()` is called.

 When developing the Widget Customizer plugin, I had to directly manipulate
 widget options extensively in order for them to be previewed and saved as
 expected. Even now, the Customizer in Core is creating
 `WP_Customize_Setting`s of type  `option` to represent widget instances.
 Based on this, my assumption has thus been that advanced plugins working
 with widgets may also interact with the underlying widget instance data
 via `get_option()` and `update_option()`, meaning that the filters need to
 be applied at this level. WP-CLI, for instance, [https://github.com/wp-cli
 /wp-
 cli/blob/6e626cc73e0463fe9564df3b98c9f08f9466b430/php/commands/widget.php#L394-L402
 gets the underlying option data] as opposed to accessing
 `WP_Widget::get_settings()`. I did a quick search on WordPress.org, and I
 see the Display Widgets plugin also interacts with widget options
 directly.

 > Also if we ever change the way widgets data is saved (using CPTs sounds
 like a good idea), this will have no backwards compatibility.

 Nevertheless, the `WP_Widget::get_settings()` and
 `WP_Widget::save_settings()` methods already work with arrays, and these
 arrays are ''mappings of widget instance numbers to their corresponding
 widget instance arrays''. Even if we do have Core switch to storing
 widgets in posts as opposed to options, we can't get around the fact that
 these methods have been implemented in this way. So we need to provide a
 way for these methods to efficiently pass around arrays of widget
 instances no matter the data backend. This is what `ArrayIterator` makes
 possible, and it is fully backwards compatible.

 > If we need to let plugins change the way widgets data is stored, a much
 better way would be to use actual filters, like we do in so many other
 places. Then we can maintain backwards compatibility.

 So yes, we could introduce filters in `WP_Widget::get_settings()` and
 `WP_Widget::save_settings()` to be able to short-circuit the normal logic
 and return `ArrayIterator` objects instead of intrinsic arrays. But other
 methods in `WP_Widget` (`_register`, `display_callback`, and
 `form_callback`) also then would have to be patched, as in this ticket's
 patch, to be compatible. And as above, this wouldn't help plugins that
 actually operate at the lower option-level.

 Instead, without introducing new filters, we can leverage the existing
 `pre_option_widget_{$id_base}` and `pre_update_option_widget_{$id_base}`
 ones.

 The patch is all backwards-compatible because without any plugins
 filtering `pre_option_widget_{$id_base}`, it will continue to work with
 intrinsic arrays as it always has. But then if a plugin does return
 `ArrayIterator` objects here instead, it is still backwards-compatible
 because these objects have the same interface as intrinsic arrays, as they
 are both iterables.

 Sorry for the long(-winded) reply.

--
Ticket URL: <https://core.trac.wordpress.org/ticket/32474#comment:20>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list