Opened 20 months ago
Last modified 14 months ago
#54958 reopened defect (bug)
Inconsistent behaviour for wp_add_inline_script between block-based and standard themes
Reported by: |
|
Owned by: | |
---|---|---|---|
Milestone: | Awaiting Review | Priority: | normal |
Severity: | normal | Version: | |
Component: | Script Loader | Keywords: | |
Focuses: | Cc: |
Description
When using a non-block based theme, data can be passed from PHP to JS inside of a shortcode using wp_add_inline_script:
Main plugin file
add_action( 'wp_enqueue_scripts', 'plugin_register_assets' ); function plugin_register_assets() { wp_register_script( 'plugin-js-handle', PLUGIN_URL . '/assets/js/file.js', array( 'jquery' ), PLUGIN_VERSION, true ); }
Shortcode
class shortcodeClass { public function render() { $this->enqueue_assets(); // Output shortcode content } public function enqueue_assets() { $args = array( // array data here ); wp_enqueue_script( 'plugin-js-handle' ); wp_add_inline_script( 'plugin-js-handle', 'const plugin_php_data = ' . json_encode( $args ), 'before' ); } }
When using a block theme, the following JS error is generated:
Uncaught ReferenceError: plugin_php_data is not defined
Specifically, the JS file handle isn’t being evaluated as registered on line 288 of class.wp-dependencies.php, and so wp_add_inline_script is failing, but only when a block-base theme is in use (I tested with the Twenty Twenty-Two and Tove block themes, works with all of the default, etc. non-block-based themes).
Is this an intended change in behaviour?
Change History (8)
#2
@
20 months ago
Thanks for the reply.
Is the suggestion then to enqueue plugin scripts on every page load in that case, or is there a way to check whether a shortcode is included in the HTML that is being loaded more generally? I know that you can check for a shortcode using has_shortcode:
if ( has_shortcode( $post->post_content, 'shortcode' ) ) { //enqueue }
But my understanding was that this would miss certain contexts (if the shortcode was used in a widget, archives, etc.), and loading on every page would slow page load times.
#3
@
20 months ago
It looks like it's safe to use wp_enqueue_script() within the short code callback to load script only on pages with shortcode. Instead of wp_add_inline_script(), you can pass JS directly to page script with <script> tag and return it along with shortcode content.
#4
@
20 months ago
- Resolution set to invalid
- Status changed from new to closed
Great, thanks for clarifying!
#5
@
17 months ago
- Component changed from General to Script Loader
- Milestone Awaiting Review deleted
#6
@
16 months ago
- Resolution invalid deleted
- Status changed from closed to reopened
The solution "Instead of wp_add_inline_script(), you can pass JS directly to page script with <script> tag and return it along with shortcode content." doesnot solve the issue of adding inline script 'before' the registered script.
Has anyone analysed why FSE themes break the existing behaviour?
From my testing the issue only occurs when you enqueue a script that has been previously registered.
It has been common practice for a long time to register a script outside the shortcode and enqueue it when needed. This now breaks wp_add_inline_script and is more troublesome when it is meant to be 'before'.
Fortunately there is a solution, to actually wp_register_script inside the shortcode function.
This is clearly a 'hack' but an explanation of why FSE breaks existing functiosn would be nice.
#8
@
14 months ago
Replying to alanfuller:
Has anyone analysed why FSE themes break the existing behaviour?
We extensively analyzed the situation and it appears that block themes (or at least Twenty Twenty-Two) fire the wp_enqueue_scripts
action only after the the_post
action and, in turn, after the_content
.
So, while plugins registering a script during wp_enqueue_scripts
will find it already registered when any shortcode callback is executed in regular themes, the same is not true for block themes. For them, a shortcode callback will be executed before wp_enqueue_scripts
, thus before a plugin had a chance to register the script.
In general, using wp_localize_script
and wp_add_inline_script
should always be done at the same time with the registration. Therefore, if you are registering the script inside wp_enqueue_scripts
and, at the same time, adding the inline script you need, then you are free to enqueue the script during the shortcode callback by using wp_enqueue_script
with the handle only. In fact, WordPress has a mechanism to automatically re-enqueue a script that was prematurely enqueued before the registration whenever the script gets finally registered. So, from that point of view, the change in block themes doesn't create any harm. But wp_localize_script
and wp_add_inline_script
must always be executed after the script is registered.
In those situations where a block theme is used and the javascript parameters are based on values calculated inside the shortcode callback, there is no solution other than registering (not just enqueuing) the script and add the inline script inside the shortcode callback itself, even if that happens before wp_enqueue_scripts
. Since WordPress cannot really register a script twice, this second approach is perfectly viable and effective for both regular and block themes.
Of course, this is not desirable as it creates an inconsistency that will force developers to register scripts in a different way, based on which type of theme is being used.
The wp_enqueue_script() and wp_add_inline_script() should not used from within the shortcode content.
The function should be called using the wp_enqueue_scripts action hook if you want to call it on the front-end of the site. Calling it outside of an action hook can lead to problems like #11526.