PluginProbe
Gutenberg / 19.6.1
Gutenberg v19.6.1
24.0.0 23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 12.6.0 All 403 releases
gutenberg / lib / compat / wordpress-6.7 / script-modules.php

script-modules.php in Gutenberg 19.6.1, at lib/compat/wordpress-6.7/script-modules.php

148 lines 6.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Print data associated with Script Modules in Script tags.
5 *
6 * This embeds data in the page HTML so that it is available on page load.
7 *
8 * Data can be associated with a given Script Module by using the
9 * `script_module_data_{$module_id}` filter.
10 *
11 * The data for a given Script Module will be JSON serialized in a script tag with an ID
12 * like `wp-script-module-data-{$module_id}`.
13 */
14 function gutenberg_print_script_module_data(): void {
15 $get_marked_for_enqueue = new ReflectionMethod( 'WP_Script_Modules', 'get_marked_for_enqueue' );
16 $get_marked_for_enqueue->setAccessible( true );
17 $get_import_map = new ReflectionMethod( 'WP_Script_Modules', 'get_import_map' );
18 $get_import_map->setAccessible( true );
19
20 $modules = array();
21 foreach ( array_keys( $get_marked_for_enqueue->invoke( wp_script_modules() ) ) as $id ) {
22 $modules[ $id ] = true;
23 }
24 foreach ( array_keys( $get_import_map->invoke( wp_script_modules() )['imports'] ) as $id ) {
25 $modules[ $id ] = true;
26 }
27
28 foreach ( array_keys( $modules ) as $module_id ) {
29 /**
30 * Filters data associated with a given Script Module.
31 *
32 * Script Modules may require data that is required for initialization or is essential to
33 * have immediately available on page load. These are suitable use cases for this data.
34 *
35 * This is best suited to a minimal set of data and is not intended to replace the REST API.
36 *
37 * If the filter returns no data (an empty array), nothing will be embedded in the page.
38 *
39 * The data for a given Script Module, if provided, will be JSON serialized in a script tag
40 * with an ID like `wp-script-module-data-{$module_id}`.
41 *
42 * The dynamic portion of the hook name, `$module_id`, refers to the Script Module ID that
43 * the data is associated with.
44 *
45 * @param array $data The data that should be associated with the array.
46 */
47 $data = apply_filters( "script_module_data_{$module_id}", array() );
48
49 if ( is_array( $data ) && ! empty( $data ) ) {
50 /*
51 * This data will be printed as JSON inside a script tag like this:
52 * <script type="application/json"></script>
53 *
54 * A script tag must be closed by a sequence beginning with `</`. It's impossible to
55 * close a script tag without using `<`. We ensure that `<` is escaped and `/` can
56 * remain unescaped, so `</script>` will be printed as `\u003C/script\u00E3`.
57 *
58 * - JSON_HEX_TAG: All < and > are converted to \u003C and \u003E.
59 * - JSON_UNESCAPED_SLASHES: Don't escape /.
60 *
61 * If the page will use UTF-8 encoding, it's safe to print unescaped unicode:
62 *
63 * - JSON_UNESCAPED_UNICODE: Encode multibyte Unicode characters literally (instead of as `\uXXXX`).
64 * - JSON_UNESCAPED_LINE_TERMINATORS: The line terminators are kept unescaped when
65 * JSON_UNESCAPED_UNICODE is supplied. It uses the same behaviour as it was
66 * before PHP 7.1 without this constant. Available as of PHP 7.1.0.
67 *
68 * The JSON specification requires encoding in UTF-8, so if the generated HTML page
69 * is not encoded in UTF-8 then it's not safe to include those literals. They must
70 * be escaped to avoid encoding issues.
71 *
72 * @see https://www.rfc-editor.org/rfc/rfc8259.html for details on encoding requirements.
73 * @see https://www.php.net/manual/en/json.constants.php for details on these constants.
74 * @see https://html.spec.whatwg.org/#script-data-state for details on script tag parsing.
75 */
76 $json_encode_flags = JSON_HEX_TAG | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_LINE_TERMINATORS;
77 if ( 'UTF-8' !== get_option( 'blog_charset' ) ) {
78 $json_encode_flags = JSON_HEX_TAG | JSON_UNESCAPED_SLASHES;
79 }
80
81 wp_print_inline_script_tag(
82 wp_json_encode( $data, $json_encode_flags ),
83 array(
84 'type' => 'application/json',
85 'id' => "wp-script-module-data-{$module_id}",
86 )
87 );
88 }
89 }
90 }
91
92 add_action(
93 'after_setup_theme',
94 function () {
95 if ( ! has_action( 'wp_footer', array( wp_script_modules(), 'print_script_module_data' ) ) ) {
96 add_action( 'wp_footer', 'gutenberg_print_script_module_data' );
97 }
98
99 if ( ! has_action( 'admin_print_footer_scripts', array( wp_script_modules(), 'print_script_module_data' ) ) ) {
100 add_action( 'admin_print_footer_scripts', 'gutenberg_print_script_module_data' );
101 }
102 },
103 20
104 );
105
106 /**
107 * Prints HTML for the a11y Script Module.
108 *
109 * a11y relies on some DOM elements to use as ARIA live regions.
110 * Ideally, these elements are part of the initial HTML of the page
111 * so that accessibility tools can find them and observe updates.
112 */
113 function gutenberg_a11y_script_module_html() {
114 $a11y_module_available = false;
115
116 $get_marked_for_enqueue = new ReflectionMethod( 'WP_Script_Modules', 'get_marked_for_enqueue' );
117 $get_marked_for_enqueue->setAccessible( true );
118 $get_import_map = new ReflectionMethod( 'WP_Script_Modules', 'get_import_map' );
119 $get_import_map->setAccessible( true );
120
121 foreach ( array_keys( $get_marked_for_enqueue->invoke( wp_script_modules() ) ) as $id ) {
122 if ( '@wordpress/a11y' === $id ) {
123 $a11y_module_available = true;
124 break;
125 }
126 }
127 if ( ! $a11y_module_available ) {
128 foreach ( array_keys( $get_import_map->invoke( wp_script_modules() )['imports'] ) as $id ) {
129 if ( '@wordpress/a11y' === $id ) {
130 $a11y_module_available = true;
131 break;
132 }
133 }
134 }
135 if ( ! $a11y_module_available ) {
136 return;
137 }
138 echo '<div style="position:absolute;margin:-1px;padding:0;height:1px;width:1px;overflow:hidden;clip-path:inset(50%);border:0;word-wrap:normal !important;">'
139 . '<p id="a11y-speak-intro-text" class="a11y-speak-intro-text" hidden>' . esc_html__( 'Notifications', 'default' ) . '</p>'
140 . '<div id="a11y-speak-assertive" class="a11y-speak-region" aria-live="assertive" aria-relevant="additions text" aria-atomic="true"></div>'
141 . '<div id="a11y-speak-polite" class="a11y-speak-region" aria-live="polite" aria-relevant="additions text" aria-atomic="true"></div>'
142 . '</div>';
143 }
144 if ( ! method_exists( 'WP_Script_Modules', 'print_a11y_script_module_html' ) ) {
145 add_action( 'wp_footer', 'gutenberg_a11y_script_module_html' );
146 add_action( 'admin_footer', 'gutenberg_a11y_script_module_html' );
147 }
148