Skip to content
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

Open
fabiankaegy opened this issue Feb 23, 2023 · 5 comments
Labels
[Feature] Block API API that allows to express the block paradigm. Needs Dev Ready for, and needs developer efforts [Type] Enhancement A suggestion for improvement.

Comments

@fabiankaegy
Copy link
Member

fabiankaegy commented Feb 23, 2023

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:

  1. wp_enqueue_block_script → adds the script to the scriptHandles which ensures the file gets enqueued both in the editor and on the frontend
  2. wp_enqueue_block_view_script → adds the script to the viewScriptHandles which ensures the file gets enqueued on the frontend

Here is an example of how this function can get implemented:

/**
  * Enqueue a view script for a block
  *
  * @param string $block_name Block name.
  * @param array  $args {
  *    Optional. Array of arguments for enqueuing a view script.
  *    @type string $handle Script handle.
  *    @type string $src Script URL.
  *    @type array $dep Script dependencies.
  *    @type string|bool $ver Script version.
  *    @type bool $in_footer Whether to enqueue the script before </body> instead of in the <head>.
  * }
  * @return void
  */
 function wp_enqueue_block_view_script( $block_name, $args = array() ) {
 	$default_args = array(
 		'handle'    => '',
 		'src'       => '',
 		'dep'       => array(),
 		'ver'       => false,
 		'in_footer' => [ 'strategy' => 'defer' ],
 	);

 	$args = wp_parse_args( $args, $default_args );

 	$block = \WP_Block_Type_Registry::get_instance()->get_registered( $block_name );

 	wp_register_script(
 		$args['handle'],
 		$args['src'],
 		$args['dep'],
 		$args['ver'],
 		$args['in_footer']
 	);

 	if ( ! empty( $block ) ) {
 		$block->view_script_handles[] = $args['handle'];
 	}
 }
@fabiankaegy fabiankaegy added [Type] Enhancement A suggestion for improvement. [Feature] Block API API that allows to express the block paradigm. labels Feb 23, 2023
@gziolo gziolo changed the title Add new utility function to add script / viewScript to an already registered block Blocks: Add new utility function to add script / viewScript to an already registered block Feb 26, 2023
@gziolo gziolo added the Needs Dev Ready for, and needs developer efforts label Feb 26, 2023
@gziolo
Copy link
Member

gziolo commented Feb 26, 2023

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: edit, view, or all. The same way we could update the existing function for styles. It's also worth pointing out that we still a way to define a style that loads only in the view context (frontend only). Finally, should we overload the first parameter in the utility function to allow defining multiple block names in case someone wants to load a shared script or style for multiple blocks (see related #41821)?

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
        );
    }
}

@mrwweb
Copy link

mrwweb commented Nov 29, 2023

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 the_content and probably render_block, but those definitely feel like hacks. The presence of wp_enqueue_block_style just really begs for a script equivalent!

@skorasaurus
Copy link
Member

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.

@mrwweb
Copy link

mrwweb commented Dec 5, 2023

Quick note: enqueuing a script on render_block / render_block_{block}works. However, that technique and all others I know of have the limitation of only allowing scripts inwp_footer`. That's a key reason for a first-class method to enqueue a specific script for a block.

@gziolo
Copy link
Member

gziolo commented Dec 6, 2023

wp_enqueue_block_view_script that @fabiankaegy included as an example implementation should allow enqueuing in both the header or footer. However, for blocks, we default now to the defer strategy:

https://github.com/WordPress/wordpress-develop/blob/ee461f010a87d806d31367d047a0d20804a80dde/src/wp-includes/blocks.php#L183-L186

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 render_callback filter for every registered style is the most efficient approach.

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_style and add wp_enqueue_block_script. If we want to have control over script type, we could do

wp_enqueue_block_script( 'core/button', array(
    'handle' => 'my-custom-view-script',
    'type'   => 'view',   
) );

By the way, if you feel like we miss viewStyle, there is an active proposal that awaits feedback:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Block API API that allows to express the block paradigm. Needs Dev Ready for, and needs developer efforts [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

No branches or pull requests

4 participants