Opened 12 months ago
Last modified 12 months ago
#21134 new defect (bug)
Registering and enqueueing on the same action can cause enqueueing to happen before registering
| Reported by: |
|
Owned by: | |
|---|---|---|---|
| Priority: | normal | Milestone: | Awaiting Review |
| Component: | General | Version: | 3.4 |
| Severity: | normal | Keywords: | |
| Cc: |
Description
We have two plugins, plugin1 and plugin2. Plugin1 registers a script, Plugin2 wants to enqueue this script. Both of these routines are executed on the _enqueue_scripts action.
There is a chance that enqueueing in Plugin2 will happen before registering in Plugin1 and therefore fail.
Possible fixes:
- Every time we enqueue a script, registered in another plugin, we use a higher priority. I am not a fan of this approach, because it is opaque – we need to document each enqueue like this, because the next developer might not know why did we use higher priority.
- Every time we register a script, we use a lower priority. I am not a fan of this either, because we will have to do this for almost every register, because we can't know if another plugin won't try to enqueue our scripts.
- Violate core recommendation and register the script on an earlier hook. I am not a fan of approach for obvious reasons.
- Add _register_scripts hooks and recommend plugin authors to register their scripts at this time.
I would prefer if we added another set of hooks, because it both makes sense to register on a register hook (as opposed to enqueue hook) and it separates the two actions, so that we can execute them at different times.
When we agree on a solution, I would be happy to write the patch.
Attachments (1)
Change History (6)
comment:2
nbachiyski
— 12 months ago
To me, this is what priorities are for, so that documentation issue is not really valid. And basically, wouldn't this be nearly the same as a
Well, yes, but when you do this often, it is both annoying and, as I said – opaque.
When I read code with priorities I have hard time understanding why the priority was changed from the default, unless there's a comment or we pay special attention and make it obvious (extract it in a function, use a constant/variable for the priority). It's rarely obvious from the code itself.
And: Is this setup really to be found often? Most plugins ship with their own copy of a script anyway, don't they?
In our case, we're building a bigger product and we have tens of plugins, interacting with each other. So it is a common case for us. In the future, as more and more people start using WordPress as a framework to build larger projects, cases like this will be even more common.
comment:3
follow-up:
↓ 4
azaozz
— 12 months ago
An option is to defer checking for dependencies in WP_Scripts. This will also solve the problem with preliminary init but will make WP_Scripts a bit more complicated.
The idea is to skip checking for dependencies on "enqueue". So calling WP_Dependencies::enqueue() would not check if isset($this->registered[$handle[0]]). That would allow us to add the default scripts later (at init 20?) and to check whether all enqueued scripts have their dependencies available and enqueue these dependencies after that.
It would also be cleaner if we separate script-loader.php into two files: one that only lists the default scripts and another that has all the functions.
comment:4
in reply to:
↑ 3
azaozz
— 12 months ago
Replying to azaozz:
... add the default scripts later (at init 20?)
No, that has to be early on 'init', as it currently is. Otherwise deregistering default scripts will break for many plugins.
comment:5
azaozz
— 12 months ago
"Proof of concept" patch. If a file has been enqueued with a dependency that doesn't exist or is not registered prior to calling print_head_scripts() ('wp_head', 9 or 'admin_print_scripts', 20), it is removed from the queue when calling WP_Dependencies::all_deps() by WP_Dependencies::do_items().
So, if I understand correctly, the problem is that Plugin2 is enqueuing another plugin's script, without making sure that this other script has been registered.
(For scripts in WP core, this is not an issue, as those will always have been registered before.)
So, proper action would have to be taken in Plugin2, either by checking if the script has been registered, via wp_script_is(), or by making sure to enqueue after the register has happened, via a higher action hook priority.
To me, this is what priorities are for, so that documentation issue is not really valid. And basically, wouldn't this be nearly the same as another wp_register_scripts action that runs right before wp_enqueue_scripts?
And: Is this setup really to be found often? Most plugins ship with their own copy of a script anyway, don't they?