Thursday, 27 April 2023

Injecting JavaScript variables to custom Wordpress block editor

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('myBlock-editor-script-js', 'window.myBlockConfig = ' . json_encode(array(
        'themeDir' => THEME_DIR,
        'themeUrl' => THEME_URL,
        'themeName' => THEME_NAME,
        'themeVersion' => THEME_VERSION,
    )), '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(
     'themeDir' => THEME_DIR,
     'themeUrl' => THEME_URL,
     'themeName' => THEME_NAME,
     'themeVersion' => THEME_VERSION,
    )) . '</script>';
});

Inline script loaded after scripts that do need the data

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

UPDATE:

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

function myBlockRestApiGetConfig($request)
{
    $response = array(
      'themeDir' => THEME_DIR,
      'themeURL' => THEME_URL,
      'themeName' => THEME_NAME,
      'themeVersion' => THEME_VERSION
    );

    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 :-)



from Injecting JavaScript variables to custom Wordpress block editor

No comments:

Post a Comment