Script Modules: Add new API to embed server data in HTML.
Add a new filter `script_module_data_{$module_id}` to associate data with a Script Module. For example: {{{#!php add_filter( 'script_module_data_MyScriptModuleID', function ( array $data ): array { $data['script-needs-this-data'] = 'ok'; return $data; } ); }}} If the Script Module is included in the page, enqueued or as a dependency, the associated data will be JSON-encoded and embedded in the HTML in a `<script type="application/json">` tag with an ID of the form `wp-script-module-data-{$module_id}` allowing the Script Module to access the data on the client. See the original proposal: https://make.wordpress.org/core/2024/05/06/proposal-server-to-client-data-sharing-for-script-modules/ Developed in https://github.com/WordPress/wordpress-develop/pull/6682. Props jonsurrell, cbravobernal, westonruter, gziolo, bernhard-reiter, youknowriad, sergiomdgomes, czapla. Fixes #61510. See #60647. Built from https://develop.svn.wordpress.org/trunk@58579 git-svn-id: http://core.svn.wordpress.org/trunk@58026 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
3f2b674b36
commit
3c520f16dd
|
@ -182,6 +182,9 @@ class WP_Script_Modules {
|
|||
add_action( 'admin_print_footer_scripts', array( $this, 'print_import_map' ) );
|
||||
add_action( 'admin_print_footer_scripts', array( $this, 'print_enqueued_script_modules' ) );
|
||||
add_action( 'admin_print_footer_scripts', array( $this, 'print_script_module_preloads' ) );
|
||||
|
||||
add_action( 'wp_footer', array( $this, 'print_script_module_data' ) );
|
||||
add_action( 'admin_print_footer_scripts', array( $this, 'print_script_module_data' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -363,4 +366,119 @@ class WP_Script_Modules {
|
|||
|
||||
return $src;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print data associated with Script Modules.
|
||||
*
|
||||
* The data will be embedded in the page HTML and can be read by Script Modules on page load.
|
||||
*
|
||||
* @since 6.7.0
|
||||
*
|
||||
* Data can be associated with a Script Module via the
|
||||
* {@see "script_module_data_{$module_id}"} filter.
|
||||
*
|
||||
* The data for a Script Module will be serialized as JSON in a script tag with an ID of the
|
||||
* form `wp-script-module-data-{$module_id}`.
|
||||
*/
|
||||
public function print_script_module_data(): void {
|
||||
$modules = array();
|
||||
foreach ( array_keys( $this->get_marked_for_enqueue() ) as $id ) {
|
||||
$modules[ $id ] = true;
|
||||
}
|
||||
foreach ( array_keys( $this->get_import_map()['imports'] ) as $id ) {
|
||||
$modules[ $id ] = true;
|
||||
}
|
||||
|
||||
foreach ( array_keys( $modules ) as $module_id ) {
|
||||
/**
|
||||
* Filters data associated with a given Script Module.
|
||||
*
|
||||
* Script Modules may require data that is required for initialization or is essential
|
||||
* to have immediately available on page load. These are suitable use cases for
|
||||
* this data.
|
||||
*
|
||||
* The dynamic portion of the hook name, `$module_id`, refers to the Script Module ID
|
||||
* that the data is associated with.
|
||||
*
|
||||
* This is best suited to pass essential data that must be available to the module for
|
||||
* initialization or immediately on page load. It does not replace the REST API or
|
||||
* fetching data from the client.
|
||||
*
|
||||
* @example
|
||||
* add_filter(
|
||||
* 'script_module_data_MyScriptModuleID',
|
||||
* function ( array $data ): array {
|
||||
* $data['script-needs-this-data'] = 'ok';
|
||||
* return $data;
|
||||
* }
|
||||
* );
|
||||
*
|
||||
* If the filter returns no data (an empty array), nothing will be embedded in the page.
|
||||
*
|
||||
* The data for a given Script Module, if provided, will be JSON serialized in a script
|
||||
* tag with an ID of the form `wp-script-module-data-{$module_id}`.
|
||||
*
|
||||
* The data can be read on the client with a pattern like this:
|
||||
*
|
||||
* @example
|
||||
* const dataContainer = document.getElementById( 'wp-script-module-data-MyScriptModuleID' );
|
||||
* let data = {};
|
||||
* if ( dataContainer ) {
|
||||
* try {
|
||||
* data = JSON.parse( dataContainer.textContent );
|
||||
* } catch {}
|
||||
* }
|
||||
* initMyScriptModuleWithData( data );
|
||||
*
|
||||
* @since 6.7.0
|
||||
*
|
||||
* @param array $data The data associated with the Script Module.
|
||||
*/
|
||||
$data = apply_filters( "script_module_data_{$module_id}", array() );
|
||||
|
||||
if ( is_array( $data ) && array() !== $data ) {
|
||||
/*
|
||||
* This data will be printed as JSON inside a script tag like this:
|
||||
* <script type="application/json"></script>
|
||||
*
|
||||
* A script tag must be closed by a sequence beginning with `</`. It's impossible to
|
||||
* close a script tag without using `<`. We ensure that `<` is escaped and `/` can
|
||||
* remain unescaped, so `</script>` will be printed as `\u003C/script\u00E3`.
|
||||
*
|
||||
* - JSON_HEX_TAG: All < and > are converted to \u003C and \u003E.
|
||||
* - JSON_UNESCAPED_SLASHES: Don't escape /.
|
||||
*
|
||||
* If the page will use UTF-8 encoding, it's safe to print unescaped unicode:
|
||||
*
|
||||
* - JSON_UNESCAPED_UNICODE: Encode multibyte Unicode characters literally (instead of as `\uXXXX`).
|
||||
* - JSON_UNESCAPED_LINE_TERMINATORS: The line terminators are kept unescaped when
|
||||
* JSON_UNESCAPED_UNICODE is supplied. It uses the same behaviour as it was
|
||||
* before PHP 7.1 without this constant. Available as of PHP 7.1.0.
|
||||
*
|
||||
* The JSON specification requires encoding in UTF-8, so if the generated HTML page
|
||||
* is not encoded in UTF-8 then it's not safe to include those literals. They must
|
||||
* be escaped to avoid encoding issues.
|
||||
*
|
||||
* @see https://www.rfc-editor.org/rfc/rfc8259.html for details on encoding requirements.
|
||||
* @see https://www.php.net/manual/en/json.constants.php for details on these constants.
|
||||
* @see https://html.spec.whatwg.org/#script-data-state for details on script tag parsing.
|
||||
*/
|
||||
$json_encode_flags = JSON_HEX_TAG | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_LINE_TERMINATORS;
|
||||
if ( ! is_utf8_charset() ) {
|
||||
$json_encode_flags = JSON_HEX_TAG | JSON_UNESCAPED_SLASHES;
|
||||
}
|
||||
|
||||
wp_print_inline_script_tag(
|
||||
wp_json_encode(
|
||||
$data,
|
||||
$json_encode_flags
|
||||
),
|
||||
array(
|
||||
'type' => 'application/json',
|
||||
'id' => "wp-script-module-data-{$module_id}",
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
*
|
||||
* @global string $wp_version
|
||||
*/
|
||||
$wp_version = '6.7-alpha-58578';
|
||||
$wp_version = '6.7-alpha-58579';
|
||||
|
||||
/**
|
||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||
|
|
Loading…
Reference in New Issue