Injecting JavaScript variables to custom Wordpress block editor
Asked Answered
T

1

6

I am creating a few custom blocks in a theme, and I have a problem. Sometimes I have a need to pass some custom data to my blocks in the blocks editor.

In other words, I need data to be available in the blocks/myBlock/index.js (the editor script).

I register my blocks, with the recommended new way, register_block_type(__DIR__ . '/build/blocks/myBlock');, that basically loads the block.json file that then registers all the editor, frontend and render scripts defined there.

In my case it is composed of:

"editorScript": "file:./index.js",
  "style": [
    "file:./style.css"
  ],
  "render": "file:./render.php"

One would think I could use the function wp_add_inline_script in the hook admin_enqueue_scripts, but it does not seem to work. Hook is triggered, but no inline scripts are added. My best guess after some investigation is that block-scripts are loaded too early, and the wp_add_inline_script is triggered after script already has been loaded or something, according to comments in official documentation; https://developer.wordpress.org/reference/functions/wp_add_inline_script/#comment-5828

Example:

add_action('admin_enqueue_scripts', function () {
    wp_add_inline_script('my-namespace-my-block-editor-script-js', 'window.myBlockConfig = ' . json_encode(array(
        'foo' => 'bar',
    )), 'before');
});

And even brute-forcing in the scripts using admin_head-hook, as comment suggested even though it used wp_footer as example, does not seem to work either. I can then see my inline script loaded, but it is loaded after block-editor-script and by then none of the data made accessible via inlien script is reachable.

Example:

add_action('admin_head', function () {
    echo '<script>window.myBlockConfig = ' . json_encode(array(
     'foo' => 'bar'
    )) . '</script>';
});

Inline script loaded after scripts that do need the data

So what would be the "correct" way to do this?

UPDATE 1:

Only way I've found to solve this is using Wordpress REST API, eg.

function myBlockRestApiGetConfig($request)
{
    $response = array(
      'foo' => 'bar',
    );

    return rest_ensure_response($response);
}

add_action('rest_api_init', function () {
    register_rest_route('myBlock/v1', '/config', array(
      'methods' => 'GET',
      'callback' => 'myBlockRestApiGetConfig',
    ));
});

And then in my blocks editor script I can fetch it;

const config = await apiFetch({
   path: `/myBlock/v1/config`,
});

But still question is; what would be the "correct" way to do this? Maybe it is better to use the API? React backend is very API centric so it makes sense, but "preloading config" makes it faster. So it is pro/con I guess.

I still find it strange that it seems impossible to any hooks to load any script-tags before blocks.

Thank you for your time :-)

UPDATE 2:

Turns out I am an idiot as usual. The handle name used in wp_add_inline_script. I used the full script id as seen in source code; my-namespace-my-block-script-js, but -js is added by Wordpress on scripts and is not part of handle name. So it should be simply my-namespace-my-block-editor-script. And then it just works...

add_action('admin_enqueue_scripts', function () {
    // Add pre-loaded data for my-namespace/my-block
    wp_add_inline_script('my-namespace-my-block-editor-script', 'window.myBlockConfig = ' . json_encode(array(
        'foo' => 'bar',
    )), 'before');
});

Answer by @Ruvee helped me realise this, and is marked as "correct" answer.

Theis answered 17/4, 2023 at 15:14 Comment(2)
Turns out my issue was, stupidly enough, the handle name used in wp_add_inline_script. I used the full script id as seen in source code; myBlock-editor-script-js, but -js is added by Wordpress on scripts and is not part of handle name. So it should be simply myBlock-editor-script. And then it just works...Theis
I have extra info. If your block.json file has {..., "name": "ifolders/image-gallery", ...}, so the wp_localize_script will be like this wp_localize_script ('ifolders-image-gallery-editor-script', ..., ...). As you can see the "ifolders/image-gallery" converted to "ifolders-image-gallery-editor-script". Hope it will help to someone.Neoclassic
G
3

Not enough room in the comments section, so I'll write my response here!

I've been tinkering around with "Gutenberg blocks" for quite sometime now, I think I might be able to help you out!

Short answer:

Yes, there is a better, or as you put it, "correct" way of doing this and no need for an extra api call, although it could be an option in certain situations! But what you're looking for, is wp_localize_scriptDocs


More detailed answer:

Since you haven't provided any specific code and just asked some general questions I'll give you general steps I would take when I'm trying to access javascript variables in the global scope!

Registering your block with initDocs action hook, like this:

add_action('init', 'your_block_admin_assets');

function your_block_admin_assets()
{
  // This is a javascript file you would need as a "handle" when you use wp_localize_script function
  wp_register_script('your-new-blocktype', 'path/to/js/file.js', array('wp-blocks', 'wp-element', 'wp-editor'));

  // Inside this function you would need to use above js file name you just registered
  register_block_type('name_of_your_block', array(
    'editor_script' => 'your-new-blocktype',
    'render_callback' => ('your_HTML_callback')
  ));

  // Use the name of the script you registered above as first argument and second argument would be a name you pick and choose to access your data in the global scope (i.e ruveeTestData.root_url)
  wp_localize_script('your-new-blocktype', 'ruveeTestData', array(
    'root_url' => get_site_url(),
    'dummy_data' => 'dummy_stuff'
  ));
}

When you load posts that contain those block on the admin side, you would be able to access those global variables. I just tested and here's a screenshot from my end

enter image description here

Note:

  • First, you have to register a javascript file, using wp_register_script function, in order to use its name as a reference in wp_localize_script function.
  • You could also use some conditional checks like is_adminDocs to narrow down the loading of your global variables.

I could have been more specifics and given you more details if you had provided more details on your question, but I think the references I just gave you, would be sufficient to get you going in the right direction!

Gravitative answered 27/4, 2023 at 14:56 Comment(2)
Thank you! Your answer did help! Turned out wp_add_inline_script works as well as wp_localize_script. Turns out, my problem was the handler name. I used myBlock-editor-script-js but -js is added automatically by Wordpress. So correct handler is myBlock-editor-script. And it even works when using the blocks.json way to register your block. register_block_type('path/to/build/blocks/myBlock'); Theis
I think editor_script is deprecated in favor of editor_script_handles: github.com/WordPress/gutenberg/issues/44687Carbaugh

© 2022 - 2024 — McMap. All rights reserved.