-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Blocks: Add new utility function to add script
/ viewScript
to an already registered block
#48382
Comments
script
/ viewScript
to an already registered blockscript
/ viewScript
to an already registered block
Thank you for opening this issue that is now tracked in #41236 with other planned tasks for Block API. Yes, that makes perfect sense to follow with more utility functions. I'm still unsure whether we need a single function instead that has a 3rd param that let's devs define other contexts: This is also good timing for this issue as I was about to file one anyway after seeing this tutorial by @justintadlock for Building a book review grid with a Query Loop block variation that surfaced exactly that challenge in the code example included: add_action( 'enqueue_block_editor_assets', 'myplugin_assets' );
function myplugin_assets() {
// Get plugin directory and URL paths.
$path = untrailingslashit( __DIR__ );
$url = untrailingslashit( plugins_url( '', __FILE__ ) );
// Get auto-generated asset file.
$asset_file = "{$path}/build/index.asset.php";
// If the asset file exists, get its data and load the script.
if ( file_exists( $asset_file ) ) {
$asset = include $asset_file;
wp_enqueue_script(
'book-reviews-variation',
"{$url}/build/index.js",
$asset['dependencies'],
$asset['version'],
true
);
}
} |
It would be really helpful to have this function(s)! (I don't really have a preference on the 1-vs-2 functions debate.) Last week, I was working on an enhancement to the core YouTube embed block that would have benefited from this. I discovered @skorasaurus was also doing the exact same thing and shared this need. During today's excellent developer meetup with @ndiego on extending blocks, the example plugin to flip the order of columns on mobile could have been further optimized with this functionality as well. cc: @ryanwelcher It's possible to enqueue the script on |
I had been wondering about this again today (and as another use case) as I was trying to make a block variation on a dynamic block (custom one that I'm making) and wanted to enqueue a separate javascript file only when that variation was used. |
Quick note: enqueuing a script on |
The biggest challenge with the proposed implementation is that a registered block gets modified directly, so the function call needs to happen after the block gets registered. The way wp_enqueue_block_style is implemented more nuanced, but therefore it doesn't have these limitations. However, I'm not entirely sure that using the Let's work on adding a helper function like this in Gutenberg or even WordPress core first. For simplicity we could fully mirror wp_enqueue_block_script( 'core/button', array(
'handle' => 'my-custom-view-script',
'type' => 'view',
) ); By the way, if you feel like we miss |
I like this terseness:
Alternatively, the place I immediately thought to add a
Which I suppose could also apply to the At this point I'd be happy with any alternative to using |
I'm curious how that functionality fits into the world of frontend powered by Interactivity API. In that case, developers no longer enqueue regular scripts but Script Modules instead. In effect, there is a new field in |
Maybe this will help someone: You can also do this by registering extra view (module) scripts during the 'register_block_type_args' hook and adding the ids/handles to the 'view_script_module_ids'/view_script_handles args properties. If a script needs to be enqueued dependent on an attribute value, you can use a 'render_callback' wrapper and do your enqueueing there. This makes it really easy to extend exiting blocks with scripts but also adjust rendering or add Interactivity API directives and even make them interactive by setting the arg ['supports']['interactivity'] = true; |
@gziolo from my perspective we should have utility functions for both cases :) |
This seems to be related in some ways to discussions around lazy hydration techniques: #52723 @poof86 related directly to your comment: #48382 (comment). |
I'm trying to understand the use case this seeks to support. Concrete examples would help. It's possible I'm missing the point of this discussion. I believe we're talking about a case like the gutenberg/packages/block-library/src/file/index.php Lines 20 to 33 in 0c0e605
I'll start by saying that with Script Modules, it should be easy to conditionally load some some Script Modules if some JavaScript is is unconditionally loaded ( In the case of function render_block_core_file( $attributes, $content ) {
// If it's interactive, enqueue the script module and add the directives.
if ( ! empty( $attributes['displayPreview'] ) ) {
wp_enqueue_script_module( '@wordpress/block-library/file' );
}
} The proposed |
My comment offered at least two examples and I think @skorasaurus had another.
|
Thanks for the details 👍
In the case of the Youtube embed, is this is the relevant snippet of code? function replace_youtube_embed_with_web_component( $content, $block ) {
$isValidYouTube = 'youtube' === $block['attrs']['providerNameSlug'] && isset( $block['attrs']['url'] );
if( ! $isValidYouTube || is_feed() ) {
return $content;
}
$video_id = extract_youtube_id_from_uri( $block['attrs']['url'] );
if ( ! $video_id ) {
return $content;
}
wp_enqueue_script_module( 'lite-youtube' );
// …
} If I'm understanding correctly, most of that snippet would remain the same (enqueue the module only if conditions are met). The change would be from enqueuing the module manually to calling the proposed function: function replace_youtube_embed_with_web_component( $content, $block ) {
$isValidYouTube = 'youtube' === $block['attrs']['providerNameSlug'] && isset( $block['attrs']['url'] );
if( ! $isValidYouTube || is_feed() ) {
return $content;
}
$video_id = extract_youtube_id_from_uri( $block['attrs']['url'] );
if ( ! $video_id ) {
return $content;
}
- wp_enqueue_script_module( 'lite-youtube' );
+ wp_enqueue_block_view_script( 'core/embed', /* … */ );
// …
} |
ahh, yep, great memory @mrwweb: Another example/context @sirreal: I made a custom dynamic block for my workplace at https://gitlab.com/cpl/cpl-libcal-block (visual example at https://gitlab.com/cpl/cpl-libcal-block/-/blob/main/example.png?ref_type=heads) that fetches some data from a 3rd party API in JSON format, and then displays it neatly on the frontend. I received a request to present the same data (and same attributes underneath the hood) in an accordion-like style. I was pressed for time so I made a separate block but that has created more technical debt (2x the maintenance and duplicate code). |
Yup. That's it. You're right that this specific case with the conditional check for YouTube complicates things and so might not be much of a change in that case. (Though that said, you've highlighted other cases where there is an additional condition for enqueueing, so maybe there's some kind of case for supporting an array of attributes that needs to match in order to enqueue the script!) Here's another example I've considered building in the past (it'll happen some day): I want some kind of interactive expandable caption for the Media & Text block that requires JS for the show/hide functionality. (Maybe with the interactivity API, maybe not.) In that case, I'd want to be able to use |
Would the conditional loading be solved by this ticket "Blocks: Introduce a way to enqueue view scripts only when needed for interactivity"? |
Here's that demo plugin: https://github.com/ndiego/enable-column-direction. The frontend js is just enqueued with |
Thanks @ndiego, is this also a case of needing a way to conditionally load the assets? snippet/**
* Render icons on the frontend.
*/
function enable_column_direction_render_block_columns( $block_content, $block ) {
$reverse_direction_on_mobile = isset( $block['attrs']['isReversedDirectionOnMobile'] ) ? $block['attrs']['isReversedDirectionOnMobile'] : false;
if ( ! $reverse_direction_on_mobile ) {
return $block_content;
}
// Since we will need the JavaScript for this block, now enqueue it.
// Note: Remove if not using front-end JavaScript to control column order.
wp_enqueue_script( 'enable-column-direction-frontend-scripts' );
// Append the custom class to the block.
$p = new WP_HTML_Tag_Processor( $block_content );
if ( $p->next_tag() ) {
$p->add_class( 'is-reversed-direction-on-mobile' );
}
$block_content = $p->get_updated_html();
return $block_content;
}
add_filter( 'render_block_core/columns', 'enable_column_direction_render_block_columns', 10, 2 ); |
Yeah, that was my somewhat hacky way of conditionally enqueuing the script if the block is present. 😅 |
Let me summarize what I understand is necessary:
That would work for all 3 cases, meaning that all of them get alwys enqueue on the frontend, and 2 always gets enqueued in the editor.
Replicating |
What problem does this address?
Part of #41236.
There are many use-cases why one may want to add additional frontend javascript to existing blocks. This is both for core and custom blocks.
What is your proposed solution?
We already have a really solid system in place for handling the enqueue logic for the scripts that get defined in the block registration. We also have a utility function in core that allows you to add additional styles to any block called
wp_enqueue_block_style
.My suggestion here would be to introduce two more similar functions:
wp_enqueue_block_script
→ adds the script to thescriptHandles
which ensures the file gets enqueued both in the editor and on the frontendwp_enqueue_block_view_script
→ adds the script to theviewScriptHandles
which ensures the file gets enqueued on the frontendHere is an example of how this function can get implemented:
The text was updated successfully, but these errors were encountered: