[wp-trac] [WordPress Trac] #21170: JavaScript actions and filters
WordPress Trac
noreply at wordpress.org
Fri Sep 15 00:17:05 UTC 2017
#21170: JavaScript actions and filters
-----------------------------+-------------------------
Reporter: koopersmith | Owner:
Type: feature request | Status: assigned
Priority: normal | Milestone: 4.9
Component: General | Version: 3.4
Severity: normal | Resolution:
Keywords: | Focuses: javascript
-----------------------------+-------------------------
Comment (by westonruter):
Replying to [comment:148 pento]:
> - If we haven't already, have a better way of importing modules into
Core. Committing the webpack-ed version of the module to the SVN repo is
unsustainable.
This is a need for the newly-committed CodeMirror bundle as well. See
#41870 (Code Editor: Add grunt task for building new CodeMirror bundles
from external dependencies)
Replying to [comment:151 adamsilverstein]:
> Also, @westonruter have you looked at wp.hooks, is it something you
think would be useful in making the //Customizer more extensible?//
The Customizer has it's own events interface which has served it well. I
suppose I'm so accustomed to to the way that JS classes in the Customizer
have been extended with subclasses and function wrapping that I haven't
felt the need for hooks. The main problem with the current system for
extending Customizer JS (and in Media JS) is that it is not particularly
elegant to be interfacing with function prototypes all over the place,
IMHO. I'd have to do an analysis of all of the Customizer feature plugins
to see all of the ways that it is being extended. The normal way that I've
implemented filter-like functionality in the Customizer is to wrap a
`wp.customize.Value`'s `validate` method to override its set value to
always be as desired. For example, in [https://github.com/xwp/wp-
customizer-responsive-device-preview Customizer Responsive Server-Side
Components Device Preview] it will force the URL in the
`wp.customize.previewer.previewUrl` to always include the current
`previewedDevice` value in a `customize_previewed_device` query parameter
([https://github.com/xwp/wp-customizer-responsive-device-
preview/blob/master/customizer-responsive-device-preview.js#L27-L35
link]):
{{{#!js
var originalPreviewUrlValidate;
originalPreviewUrlValidate = component.api.previewer.previewUrl.validate;
component.api.previewer.previewUrl.validate = function validatePreviewUrl(
newUrl ) {
var url = newUrl;
if ( null !== url ) {
url = component.amendUrlWithPreviewedDevice( url );
}
return originalPreviewUrlValidate.call( this, url );
};
}}}
It works very well, but it's not particularly elegant. It would be cleaner
if there was some 'previewUrl' filter that could be used instead of having
to wrap the `validate` function.
I'll note that I've tried to take a similar approach for filtering values
being set on Backbone models, but there is no equivalent `validate` method
in Backbone. The `validate` method on `wp.customize.Value` in the
Customizer is really more similar to a `sanitize` method, whereas in
Backbone it's used only as a strict a pass/fail kind of thing (like
`validate` in the REST API). So in the media widgets, in order to
implement the same kind of sanitization logic it is currently
[https://github.com/WordPress/wordpress-
develop/blob/95a263212177a4944f96c927eae7f80bdd020105/src/wp-
admin/js/widgets/media-widgets.js#L971-L1015 overridding] the entire
`Model#set` method itself.
One point of concern I have with `wp.hooks` as to me it would seem to
encourage a break in the encapsulation of logic inside of individual
components. In other words, JS components that would be running the hooks
would all have to reach out to this one object in global scope where all
of the hooks are registered. Namespaces would have to be added to the
hooks to prevent them from conflicting due to the fact that they are all
global.
This just came to mind now (and maybe this has already been considered in
the design of `wp.hooks`, so excuse my ignorance): ¿would it not be a
better architectural pattern to instead introduce hooks as something that
can be instantiated onto a specific object? For example, Backbone has its
`Events` mixin and Customizer similarly has its `wp.customize.Events`
interface. You can augment any object with this mixin to get the interface
to trigger and listen for events, and when the events are triggered you
don't need a namespace because they're naturally scoped to that object.
There is also less overhead then by not having to manage a massive object
of hook/handler mappings with the risk then of leaking memory (I recall
PHP actions and filters being identified as a performance bottleneck in
WordPress).
In contrast, what if you have a `wp.Hooks` interface that you add to some
`Thing` (like `Object.assign( Thing.prototype, wp.Hooks )` and then you do
`obj = new Thing()` and attach a filter to it like `obj.addFilter( 'foo',
function() {…} )` then when `obj` is destroyed then that anonymous
function handler could also be garbage collected. In contrast, if you do
`wp.hooks.addFilter( 'someNamespace.thing.foo', function() {} )` the you'd
potentially need to remember to `removeFilter` later or else that
anonymous function will stick around forever.
Replying to [comment:173 adamsilverstein]:
> The goal of getting `wp.hooks` into trunk is to start trying to use is
internally - I'm going to work on a demonstration of that next.
>
> If we find the `wp.hooks` library is not useful or feel its API is not
stable before the 4.9 release, I would support reverting or possubly
authoring a dev note as well as liberal inline comments explaining that
this is a new API that may have breaking changes and if developers use it
they should watch development closely.
We're planning to be working on a Customizer v2 feature plugin after the
4.9 release, and at that point we'll definitely taking a look at the
current JS API and anywhere that its extensibility is lacking. I'd want to
incorporate `wp.hooks` wherever possible in that project.
In conclusion, I would be open to keeping `wp.hooks` in `trunk` for the
remainder of `4.9-alpha` with an expectation that it will be reverted
before beta, if that helps with testing patches that prototype making use
of `wp.hooks`. (While an exception was made for the REST API, I think we
shouldn't ship something that isn't used in core.) In that way, it would
be treated like “temp hooks” for feature plugins (which aren't used very
often). But if having `wp.hooks` in core is only to facilitate writing
patches for implementing hooks for parts of core, then I'd suggest instead
creating a new “wp-js-hooks” '''feature plugin''' that simply bundles the
JS and registers it so that other feature plugins can enqueue it and
utilize it. (Plugin dependencies, anyone?)
--
Ticket URL: <https://core.trac.wordpress.org/ticket/21170#comment:175>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list