WordPress.org

Make WordPress Core

Opened 5 years ago

Closed 3 years ago

Last modified 2 years ago

#9346 closed enhancement (fixed)

wp_enqueue_script() doesn't work mid-page for footer scripts

Reported by: Viper007Bond Owned by: azaozz
Milestone: 3.3 Priority: lowest
Severity: minor Version: 2.8
Component: JavaScript Keywords: needs-docs needs-patch
Focuses: Cc:

Description

Create a footer script at init, plugins_loaded, or whatever. Doesn't matter, just early.

wp_register_script( 'myscript' '/some/path/script.js', array(), '1.2.3', true );

Now if we were to do wp_enqueue_script( 'myscript' ); directly after that, the script would be outputted in the footer as expected.

However if we were to do the enqueue farther down the page, say inside a the_content filter, it doesn't work. It should. I need to be able to dynamically enqueue scripts for example based on shortcodes.

Attachments (3)

9346.diff (523 bytes) - added by Denis-de-Bernardy 5 years ago.
print-scripts-footer.diff (867 bytes) - added by amattie 4 years ago.
Alternative solution for consideration purposes
9346-2.patch (5.2 KB) - added by azaozz 3 years ago.

Download all attachments as: .zip

Change History (39)

comment:1 Viper007Bond5 years ago

  • Summary changed from wp_enqueue_script() doesn't work mid-page to wp_enqueue_script() doesn't work mid-page for footer scripts

Missing comma inside that register:

wp_register_script( 'myscript', '/some/path/script.js', array(), '1.2.3', true );

And incase you didn't notice, the fifth parameter is set to true which makes it output in the footer.

comment:2 follow-up: Viper007Bond5 years ago

Debugged and found the problem.

When WP_Scripts::do_item() fires for outputting the header scripts and comes across a script that is meant for the footer, it tosses that that handle into the WP_Scripts::in_footer array and aborts outputting it.

Calling wp_enqueue_script() after that point doesn't add the script to the WP_Scripts::in_footer array, so it never gets properly registered.

I have a couple solutions in mind, but I'll let someone more at home with the class (azaozz perhaps?) come up with the solution to ensure it's the cleanest one.

comment:3 sivel5 years ago

  • Cc matt@… added

comment:4 follow-up: azaozz5 years ago

Yes the script loader requires all scripts to be queued before the page starts to load so it can do the dependencies properly. It also supports wp_print_script() in the middle of the page and would print all dependencies (if not already in the head) and remove any of them if queued for the footer.

I suppose we can add support for wp_enqueue_script() in the middle of the page that would queue scripts only for the footer. Would need to force all dependencies to print in the footer too even if queued for the head by default.

That may bring some issues with scripts that cannot run from the footer properly and are printed as dependency. Perhaps would be better to leave this as an "advanced" option only.

comment:5 Viper007Bond5 years ago

  • Priority changed from normal to lowest
  • Severity changed from normal to minor
  • Type changed from defect (bug) to enhancement

I didn't think of just using wp_print_scripts( 'myscript' ); inside a footer hook. That works nicely.

Dropping the priority on this and switching it to an enhancement as there's an alternate solution.

comment:6 in reply to: ↑ 2 ; follow-up: hakre5 years ago

Replying to Viper007Bond:

Debugged and found the problem.

When WP_Scripts::do_item() fires for outputting the header scripts and comes across a script that is meant for the footer, it tosses that that handle into the WP_Scripts::in_footer array and aborts outputting it.

Calling wp_enqueue_script() after that point doesn't add the script to the WP_Scripts::in_footer array, so it never gets properly registered.

I have a couple solutions in mind, but I'll let someone more at home with the class (azaozz perhaps?) come up with the solution to ensure it's the cleanest one.

thanks for getting into it. a propper dev feedback would be nice, because as you I think this should be easily solveable.

comment:7 in reply to: ↑ 6 Denis-de-Bernardy5 years ago

+1 for this one

Denis-de-Bernardy5 years ago

comment:8 Denis-de-Bernardy5 years ago

  • Keywords has-patch tested added; needs-patch removed
  • Milestone changed from Future Release to 2.8

Attached patch does the trick. tested with a footer script that required recursive depends including a few that should go in the header.

Before the patch: nothing gets added at all.

After the patch:

  • all depends (including recursively needed depends) get added in the footer if none is previously added
  • already included depends do not get added as expected

Potential issues I can think of:

  • localized scripts (should work fine)
  • scripts that really should be in the header, but I think it is the plugin author's job to make sure his scripts work.

comment:9 Denis-de-Bernardy5 years ago

  • Keywords commit added

comment:10 azaozz5 years ago

  • Milestone 2.8 deleted
  • Resolution set to wontfix
  • Status changed from new to closed

Still think it's better to use wp_print_scripts() in the middle of the page or in the footer. The patch may behave unexpectedly when wp_print_scripts() is used after it but before the footer action.

comment:11 aaroncampbell5 years ago

  • Cc aaroncampbell added

I just thought I'd add in my two cents. First, this would be really handy to have for the exact reason that Viper mentioned, shortcodes. Shortcodes have become an extremely useful tool, but the ability to easily enqueue scripts would really put them over the top. Right now I'm using the suggested method of a wp_footer action that calls wp_print_scripts, but it's not as elegant as using wp_scripts.

Hopefully we can take a look at this again some day soon.

comment:12 archon8104 years ago

  • Cc admin@… added

+1 for a proper solution - the use case that Viper described (shortcodes) makes this look like a bug - the feature of printing scripts in the footer does not work as expected.

comment:13 in reply to: ↑ 4 scribu4 years ago

Can't wait for jQuery's require() method.

comment:14 scribu4 years ago

Related: #15126

comment:15 rspindel4 years ago

  • Cc rspindel added

comment:16 amattie4 years ago

  • Cc amattie@… added

I just ran into this issue when trying to add a script to the footer within a shortcode. I considered this to be bug and created a patch before looking for and finding this ticket. I'll be attaching that patch for debate and consideration purposes.

In order to address my needs for now, I will manually add my scripts to in_footer[] immediately after the enqueue.

amattie4 years ago

Alternative solution for consideration purposes

comment:17 scribu4 years ago

  • Keywords tested commit removed
  • Milestone set to Future Release
  • Resolution wontfix deleted
  • Status changed from closed to reopened

Re-opening for reconsideration, given amattie's patch.

comment:18 azaozz4 years ago

The second patch forces a script in the footer without accounting for the dependencies. When that script depends on another script that prints in the head by default (and is not already printed) it would break.

I would rather go with the first patch (by Denis). It prints all scripts that haven't been printed yet in the footer regardless of the default location.

comment:19 scribu4 years ago

Related: #15843

comment:21 philipwalton3 years ago

For what it's worth, I ran into another situation other than shortcodes where I needed to make the decision whether or not to enqueue a script after the admin_enqueue_scripts hook was fired. In this case on the admin side.

I'm using an MVC plugin framework that loads a view file for the settings form. In the view file the user of the framework creates a form object, e.g:

$form = new MVC_Active_Form;
$form->ajax_validation = true;

So the framework has no idea whether or not the settings form will require ajax validation until after WordPress loads it, which doesn't happen until well after the admin_enqueue_scripts hook is fired.

Anyway, I just thought I'd offer another example to support a better implementation of wp_enqueue_script() in core. In the meantime the proposed work-around is doing the trick.

comment:22 mitchoyoshitaka3 years ago

  • Cc mitcho@… added

Working on #17704 now and realized I can't do it neatly because of this bug. Just another reason why getting this fixed properly would be appreciated.

comment:23 billerickson3 years ago

  • Cc bill.erickson@… added

comment:24 azaozz3 years ago

  • Milestone changed from Future Release to 3.3

comment:25 travisnorthcutt3 years ago

  • Cc travis@… added

azaozz3 years ago

comment:26 azaozz3 years ago

9346-2.patch adds support for late enqueueing of both scripts and styles which are printed in the footer.

comment:27 azaozz3 years ago

  • Resolution set to fixed
  • Status changed from reopened to closed

In [18446]:

Support for using wp_enqueue_script() and wp_enqueue_style() in the HTML body. All scripts and styles are added in the footer, fixes #9346

comment:28 follow-up: nacin3 years ago

  • Resolution fixed deleted
  • Status changed from closed to reopened

Lots of new functions, should docs would be nice.

Would be good to get westi to look at this as well, as he's generally watched the dependencies closely. Some of the stuff in [18446] looks a bit cryptic.

comment:29 in reply to: ↑ 28 azaozz3 years ago

Replying to nacin:

The only "real" change is making in_array() in class.wp-dependencies.php do a strict comparison. The rest is copy/paste between the wp-scripts and wp-styles functions. It would be better to open new tickets for any further problems.

Last edited 3 years ago by azaozz (previous) (diff)

comment:30 WraithKenny3 years ago

  • Cc Ken@… added

comment:31 ocean903 years ago

  • Keywords needs-docs needs-patch added; has-patch removed

comment:32 azizur3 years ago

  • Cc azizur added

comment:33 ryan3 years ago

  • Resolution set to fixed
  • Status changed from reopened to closed

comment:34 follow-up: michalsrodek2 years ago

  • Cc michalsrodek added
  • Type changed from enhancement to defect (bug)

Unfortunately it's not the best idea to add styles in the footer. In some cases websites are loading very long and some parts are unstyled until whole page is loaded. I think that it would be better to buffer everything after head section using ob functions(http://www.php.net/manual/en/ref.outcontrol.php).

comment:35 ocean902 years ago

  • Type changed from defect (bug) to enhancement

If you have problems you should open a new ticket.

comment:36 in reply to: ↑ 34 aaroncampbell2 years ago

Replying to michalsrodek:

Unfortunately it's not the best idea to add styles in the footer

This thicket was for scripts not styles.

Note: See TracTickets for help on using tickets.