run:R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
23.8 KB
2026-03-11 16:18:51
R W Run
7.8 KB
2026-03-11 16:18:52
R W Run
36.1 KB
2026-03-11 16:18:51
R W Run
11.9 KB
2026-03-11 16:18:52
R W Run
18.94 KB
2026-03-11 16:18:52
R W Run
7.35 KB
2026-03-11 16:18:52
R W Run
28.6 KB
2026-03-11 16:18:51
R W Run
316 By
2026-03-11 16:18:51
R W Run
12.9 KB
2026-03-11 16:18:51
R W Run
61.02 KB
2026-03-11 16:18:52
R W Run
15 KB
2026-03-11 16:18:51
R W Run
112.05 KB
2026-03-11 16:18:51
R W Run
12.47 KB
2026-03-11 16:18:51
R W Run
15.07 KB
2026-03-11 16:18:52
R W Run
9.84 KB
2026-03-11 16:18:52
R W Run
13.17 KB
2026-03-11 16:18:52
R W Run
33.83 KB
2026-03-11 16:18:51
R W Run
42.63 KB
2026-03-11 16:18:51
R W Run
55.71 KB
2026-03-11 16:18:52
R W Run
12.53 KB
2026-03-11 16:18:51
R W Run
2.55 KB
2026-03-11 16:18:52
R W Run
28.92 KB
2026-03-11 16:18:52
R W Run
539 By
2026-03-11 16:18:51
R W Run
367 By
2026-03-11 16:18:52
R W Run
42.65 KB
2026-03-11 16:18:51
R W Run
401 By
2026-03-11 16:18:51
R W Run
6.61 KB
2026-03-11 16:18:51
R W Run
664 By
2026-03-11 16:18:52
R W Run
20.63 KB
2026-03-11 16:18:51
R W Run
2.18 KB
2026-03-11 16:18:52
R W Run
453 By
2026-03-11 16:18:52
R W Run
457 By
2026-03-11 16:18:51
R W Run
36.83 KB
2026-03-11 16:18:52
R W Run
2.41 KB
2026-03-11 16:18:52
R W Run
8.28 KB
2026-03-11 16:18:51
R W Run
13.89 KB
2026-03-11 16:18:51
R W Run
11.76 KB
2026-03-11 16:18:51
R W Run
2.65 KB
2026-03-11 16:18:51
R W Run
7.43 KB
2026-03-11 16:18:51
R W Run
17.46 KB
2026-03-11 16:18:51
R W Run
5.14 KB
2026-03-11 16:18:52
R W Run
16.7 KB
2026-03-11 16:18:51
R W Run
8.28 KB
2026-03-11 16:18:52
R W Run
2.92 KB
2026-03-11 16:18:52
R W Run
1.32 KB
2026-03-11 16:18:51
R W Run
4.6 KB
2026-03-11 16:18:52
R W Run
11.62 KB
2026-03-11 16:18:52
R W Run
2.5 KB
2026-03-11 16:18:51
R W Run
1.97 KB
2026-03-11 16:18:51
R W Run
11.25 KB
2026-03-11 16:18:52
R W Run
5.32 KB
2026-03-11 16:18:51
R W Run
10.99 KB
2026-03-11 16:18:52
R W Run
68.32 KB
2026-03-11 16:18:51
R W Run
6.34 KB
2026-03-11 16:18:51
R W Run
5.49 KB
2026-03-11 16:18:51
R W Run
1.99 KB
2026-03-11 16:18:52
R W Run
7.02 KB
2026-03-11 16:18:51
R W Run
4.91 KB
2026-03-11 16:18:52
R W Run
16.86 KB
2026-03-11 16:18:51
R W Run
24.23 KB
2026-03-11 16:18:51
R W Run
3.97 KB
2026-03-11 16:18:51
R W Run
47.66 KB
2026-03-11 16:18:51
R W Run
9.22 KB
2026-03-11 16:18:51
R W Run
25.51 KB
2026-03-11 16:18:51
R W Run
198.38 KB
2026-03-11 16:18:52
R W Run
56.65 KB
2026-03-11 16:18:51
R W Run
10.46 KB
2026-03-11 16:18:51
R W Run
10.95 KB
2026-03-11 16:18:52
R W Run
29.26 KB
2026-03-11 16:18:51
R W Run
70.91 KB
2026-03-11 16:18:52
R W Run
35.3 KB
2026-03-11 16:18:52
R W Run
16.61 KB
2026-03-11 16:18:52
R W Run
2.57 KB
2026-03-11 16:18:52
R W Run
39.83 KB
2026-03-11 16:18:51
R W Run
70.64 KB
2026-03-11 16:18:51
R W Run
15.56 KB
2026-03-11 16:18:52
R W Run
7.33 KB
2026-03-11 16:18:52
R W Run
253 By
2026-03-11 16:18:51
R W Run
7.96 KB
2026-03-11 16:18:52
R W Run
3.23 KB
2026-03-11 16:18:52
R W Run
969 By
2026-03-11 16:18:52
R W Run
16.28 KB
2026-03-11 16:18:51
R W Run
7.22 KB
2026-03-11 16:18:51
R W Run
12.95 KB
2026-03-11 16:18:51
R W Run
6.53 KB
2026-03-11 16:18:51
R W Run
3.42 KB
2026-03-11 16:18:52
R W Run
5.84 KB
2026-03-11 16:18:51
R W Run
1.97 KB
2026-03-11 16:18:51
R W Run
4.3 KB
2026-03-11 16:18:52
R W Run
2.91 KB
2026-03-11 16:18:51
R W Run
16.46 KB
2026-03-11 16:18:52
R W Run
40.6 KB
2026-03-11 16:18:51
R W Run
20.22 KB
2026-03-11 16:18:51
R W Run
36.11 KB
2026-03-11 16:18:52
R W Run
17.01 KB
2026-03-11 16:18:51
R W Run
7.27 KB
2026-03-11 16:18:52
R W Run
6.62 KB
2026-03-11 16:18:52
R W Run
16.49 KB
2026-03-11 16:18:52
R W Run
1.79 KB
2026-03-11 16:18:52
R W Run
29.82 KB
2026-03-11 16:18:51
R W Run
6.67 KB
2026-03-11 16:18:52
R W Run
8.98 KB
2026-03-11 16:18:52
R W Run
19.42 KB
2026-03-11 16:18:51
R W Run
12.01 KB
2026-03-11 16:18:51
R W Run
17.11 KB
2026-03-11 16:18:51
R W Run
6.74 KB
2026-03-11 16:18:52
R W Run
30.93 KB
2026-03-11 16:18:51
R W Run
4.99 KB
2026-03-11 16:18:51
R W Run
4.25 KB
2026-03-11 16:18:51
R W Run
24.72 KB
2026-03-11 16:18:51
R W Run
29.96 KB
2026-03-11 16:18:52
R W Run
6.41 KB
2026-03-11 16:18:51
R W Run
160 KB
2026-03-11 16:18:51
R W Run
6.72 KB
2026-03-11 16:18:52
R W Run
10.92 KB
2026-03-11 16:18:51
R W Run
4.77 KB
2026-03-11 16:18:51
R W Run
3.38 KB
2026-03-11 16:18:51
R W Run
11.18 KB
2026-03-11 16:18:51
R W Run
62.19 KB
2026-03-11 16:18:51
R W Run
2.46 KB
2026-03-11 16:18:51
R W Run
9.17 KB
2026-03-11 16:18:51
R W Run
32.15 KB
2026-03-11 16:18:51
R W Run
34.05 KB
2026-03-11 16:18:52
R W Run
7.15 KB
2026-03-11 16:18:51
R W Run
3.47 KB
2026-03-11 16:18:52
R W Run
1.87 KB
2026-03-11 16:18:52
R W Run
30.91 KB
2026-03-11 16:18:51
R W Run
7.29 KB
2026-03-11 16:18:52
R W Run
7.35 KB
2026-03-11 16:18:51
R W Run
12.54 KB
2026-03-11 16:18:51
R W Run
19.12 KB
2026-03-11 16:18:51
R W Run
18.12 KB
2026-03-11 16:18:52
R W Run
39.99 KB
2026-03-11 16:18:52
R W Run
5.17 KB
2026-03-11 16:18:52
R W Run
979 By
2026-03-11 16:18:51
R W Run
18.44 KB
2026-03-11 16:18:52
R W Run
10.24 KB
2026-03-11 16:18:51
R W Run
1.77 KB
2026-03-11 16:18:52
R W Run
34.9 KB
2026-03-11 16:18:51
R W Run
7.19 KB
2026-03-11 16:18:52
R W Run
160.5 KB
2026-03-11 16:18:51
R W Run
64.27 KB
2026-03-11 16:18:51
R W Run
27.95 KB
2026-03-11 16:18:51
R W Run
4.69 KB
2026-03-11 16:18:51
R W Run
2.94 KB
2026-03-11 16:18:51
R W Run
43.13 KB
2026-03-11 16:18:52
R W Run
2.25 KB
2026-03-11 16:18:52
R W Run
22.5 KB
2026-03-11 16:18:51
R W Run
13.01 KB
2026-03-11 16:18:52
R W Run
3.27 KB
2026-03-11 16:18:51
R W Run
18 KB
2026-03-11 16:18:51
R W Run
210.4 KB
2026-03-11 16:18:52
R W Run
25.86 KB
2026-03-11 16:18:52
R W Run
115.85 KB
2026-03-11 16:18:51
R W Run
373 By
2026-03-11 16:18:52
R W Run
343 By
2026-03-11 16:18:52
R W Run
338 By
2026-03-11 16:18:51
R W Run
100.73 KB
2026-03-11 16:18:52
R W Run
130.93 KB
2026-03-11 16:18:51
R W Run
19.1 KB
2026-03-11 16:18:51
R W Run
17.41 KB
2026-03-11 16:18:52
R W Run
41.98 KB
2026-03-11 16:18:52
R W Run
400 By
2026-03-11 16:18:52
R W Run
11.1 KB
2026-03-11 16:18:52
R W Run
37.02 KB
2026-03-11 16:18:51
R W Run
2.24 KB
2026-03-11 16:18:51
R W Run
188.13 KB
2026-03-11 16:18:51
R W Run
338 By
2026-03-11 16:18:51
R W Run
38 KB
2026-03-11 16:18:51
R W Run
4.02 KB
2026-03-11 16:18:52
R W Run
5.38 KB
2026-03-11 16:18:51
R W Run
3.05 KB
2026-03-11 16:18:52
R W Run
2.61 KB
2026-03-11 16:18:51
R W Run
1.16 KB
2026-03-11 16:18:52
R W Run
4.04 KB
2026-03-11 16:18:51
R W Run
3.71 KB
2026-03-11 16:18:51
R W Run
24.6 KB
2026-03-11 16:18:51
R W Run
9.56 KB
2026-03-11 16:18:51
R W Run
346.43 KB
2026-03-11 16:18:52
R W Run
281.84 KB
2026-03-11 16:18:52
R W Run
14.95 KB
2026-03-11 16:18:51
R W Run
8.44 KB
2026-03-11 16:18:52
R W Run
168.95 KB
2026-03-11 16:18:52
R W Run
20.71 KB
2026-03-11 16:18:52
R W Run
25.27 KB
2026-03-11 16:18:51
R W Run
5.72 KB
2026-03-11 16:18:51
R W Run
4.63 KB
2026-03-11 16:18:52
R W Run
81.73 KB
2026-03-11 16:18:51
R W Run
67.18 KB
2026-03-11 16:18:51
R W Run
156.36 KB
2026-03-11 16:18:52
R W Run
55.19 KB
2026-03-11 16:18:51
R W Run
162 By
2026-03-11 16:18:51
R W Run
61.72 KB
2026-03-11 16:18:51
R W Run
216.06 KB
2026-03-11 16:18:52
R W Run
65.09 KB
2026-03-11 16:18:51
R W Run
25.24 KB
2026-03-11 16:18:52
R W Run
4.81 KB
2026-03-11 16:18:51
R W Run
6.48 KB
2026-03-11 16:18:52
R W Run
21.25 KB
2026-03-11 16:18:51
R W Run
2.79 KB
2026-03-11 16:18:52
R W Run
89.69 KB
2026-03-11 16:18:52
R W Run
19.42 KB
2026-03-11 16:18:52
R W Run
3.69 KB
2026-03-11 16:18:52
R W Run
4.11 KB
2026-03-11 16:18:51
R W Run
40.74 KB
2026-03-11 16:18:51
R W Run
25.38 KB
2026-03-11 16:18:51
R W Run
43.31 KB
2026-03-11 16:18:52
R W Run
102.57 KB
2026-03-11 16:18:52
R W Run
6.18 KB
2026-03-11 16:18:51
R W Run
124.47 KB
2026-03-11 16:18:52
R W Run
35.65 KB
2026-03-11 16:18:52
R W Run
6.94 KB
2026-03-11 16:18:52
R W Run
67.04 KB
2026-03-11 16:18:52
R W Run
10.62 KB
2026-03-11 16:18:51
R W Run
289.35 KB
2026-03-11 16:18:52
R W Run
36.23 KB
2026-03-11 16:18:51
R W Run
200 By
2026-03-11 16:18:52
R W Run
200 By
2026-03-11 16:18:52
R W Run
98.29 KB
2026-03-11 16:18:52
R W Run
30.02 KB
2026-03-11 16:18:52
R W Run
19.03 KB
2026-03-11 16:18:52
R W Run
5.06 KB
2026-03-11 16:18:52
R W Run
255 By
2026-03-11 16:18:51
R W Run
22.66 KB
2026-03-11 16:18:52
R W Run
154.63 KB
2026-03-11 16:18:51
R W Run
9.68 KB
2026-03-11 16:18:51
R W Run
258 By
2026-03-11 16:18:51
R W Run
23.49 KB
2026-03-11 16:18:51
R W Run
3.16 KB
2026-03-11 16:18:51
R W Run
8.4 KB
2026-03-11 16:18:52
R W Run
441 By
2026-03-11 16:18:51
R W Run
7.39 KB
2026-03-11 16:18:51
R W Run
173 KB
2026-03-11 16:18:52
R W Run
544 By
2026-03-11 16:18:52
R W Run
4.17 KB
2026-03-11 16:18:51
R W Run
35.97 KB
2026-03-11 16:18:52
R W Run
1.69 KB
2026-03-11 16:18:51
R W Run
2.84 KB
2026-03-11 16:18:52
R W Run
6.09 KB
2026-03-11 16:18:51
R W Run
8.71 KB
2026-03-11 16:18:51
R W Run
131.84 KB
2026-03-11 16:18:51
R W Run
37.45 KB
2026-03-11 16:18:51
R W Run
173.89 KB
2026-03-11 16:18:51
R W Run
7.09 KB
2026-03-11 16:18:51
R W Run
6.41 KB
2026-03-11 16:18:51
R W Run
1.08 KB
2026-03-11 16:18:51
R W Run
69.46 KB
2026-03-11 16:18:52
R W Run
445 By
2026-03-11 16:18:51
R W Run
799 By
2026-03-11 16:18:52
R W Run
error_log
📄class-wp-script-modules.php
1<?php
2/**
3 * Script Modules API: WP_Script_Modules class.
4 *
5 * Native support for ES Modules and Import Maps.
6 *
7 * @package WordPress
8 * @subpackage Script Modules
9 */
10
11/**
12 * Core class used to register script modules.
13 *
14 * @since 6.5.0
15 */
16class WP_Script_Modules {
17 /**
18 * Holds the registered script modules, keyed by script module identifier.
19 *
20 * @since 6.5.0
21 * @var array<string, array<string, mixed>>
22 */
23 private $registered = array();
24
25 /**
26 * An array of IDs for queued script modules.
27 *
28 * @since 6.9.0
29 * @var string[]
30 */
31 private $queue = array();
32
33 /**
34 * Holds the script module identifiers that have been printed.
35 *
36 * @since 6.9.0
37 * @var string[]
38 */
39 private $done = array();
40
41 /**
42 * Tracks whether the @wordpress/a11y script module is available.
43 *
44 * Some additional HTML is required on the page for the module to work. Track
45 * whether it's available to print at the appropriate time.
46 *
47 * @since 6.7.0
48 * @var bool
49 */
50 private $a11y_available = false;
51
52 /**
53 * Holds a mapping of dependents (as IDs) for a given script ID.
54 * Used to optimize recursive dependency tree checks.
55 *
56 * @since 6.9.0
57 * @var array<string, string[]>
58 */
59 private $dependents_map = array();
60
61 /**
62 * Holds the valid values for fetchpriority.
63 *
64 * @since 6.9.0
65 * @var string[]
66 */
67 private $priorities = array(
68 'low',
69 'auto',
70 'high',
71 );
72
73 /**
74 * List of IDs for script modules encountered which have missing dependencies.
75 *
76 * An ID is added to this list when it is discovered to have missing dependencies. At this time, a warning is
77 * emitted with {@see _doing_it_wrong()}. The ID is then added to this list, so that duplicate warnings don't occur.
78 *
79 * @since 6.9.1
80 * @var string[]
81 */
82 private $modules_with_missing_dependencies = array();
83
84 /**
85 * Registers the script module if no script module with that script module
86 * identifier has already been registered.
87 *
88 * @since 6.5.0
89 * @since 6.9.0 Added the $args parameter.
90 *
91 * @param string $id The identifier of the script module. Should be unique. It will be used in the
92 * final import map.
93 * @param string $src Optional. Full URL of the script module, or path of the script module relative
94 * to the WordPress root directory. If it is provided and the script module has
95 * not been registered yet, it will be registered.
96 * @param array $deps {
97 * Optional. List of dependencies.
98 *
99 * @type string|array ...$0 {
100 * An array of script module identifiers of the dependencies of this script
101 * module. The dependencies can be strings or arrays. If they are arrays,
102 * they need an `id` key with the script module identifier, and can contain
103 * an `import` key with either `static` or `dynamic`. By default,
104 * dependencies that don't contain an `import` key are considered static.
105 *
106 * @type string $id The script module identifier.
107 * @type string $import Optional. Import type. May be either `static` or
108 * `dynamic`. Defaults to `static`.
109 * }
110 * }
111 * @param string|false|null $version Optional. String specifying the script module version number. Defaults to false.
112 * It is added to the URL as a query string for cache busting purposes. If $version
113 * is set to false, the version number is the currently installed WordPress version.
114 * If $version is set to null, no version is added.
115 * @param array $args {
116 * Optional. An array of additional args. Default empty array.
117 *
118 * @type bool $in_footer Whether to print the script module in the footer. Only relevant to block themes. Default 'false'. Optional.
119 * @type 'auto'|'low'|'high' $fetchpriority Fetch priority. Default 'auto'. Optional.
120 * }
121 */
122 public function register( string $id, string $src, array $deps = array(), $version = false, array $args = array() ) {
123 if ( '' === $id ) {
124 _doing_it_wrong( __METHOD__, __( 'Non-empty string required for id.' ), '6.9.0' );
125 return;
126 }
127
128 if ( ! isset( $this->registered[ $id ] ) ) {
129 $dependencies = array();
130 foreach ( $deps as $dependency ) {
131 if ( is_array( $dependency ) ) {
132 if ( ! isset( $dependency['id'] ) || ! is_string( $dependency['id'] ) ) {
133 _doing_it_wrong( __METHOD__, __( 'Missing required id key in entry among dependencies array.' ), '6.5.0' );
134 continue;
135 }
136 $dependencies[] = array(
137 'id' => $dependency['id'],
138 'import' => isset( $dependency['import'] ) && 'dynamic' === $dependency['import'] ? 'dynamic' : 'static',
139 );
140 } elseif ( is_string( $dependency ) ) {
141 $dependencies[] = array(
142 'id' => $dependency,
143 'import' => 'static',
144 );
145 } else {
146 _doing_it_wrong( __METHOD__, __( 'Entries in dependencies array must be either strings or arrays with an id key.' ), '6.5.0' );
147 }
148 }
149
150 $in_footer = isset( $args['in_footer'] ) && (bool) $args['in_footer'];
151
152 $fetchpriority = 'auto';
153 if ( isset( $args['fetchpriority'] ) ) {
154 if ( $this->is_valid_fetchpriority( $args['fetchpriority'] ) ) {
155 $fetchpriority = $args['fetchpriority'];
156 } else {
157 _doing_it_wrong(
158 __METHOD__,
159 sprintf(
160 /* translators: 1: $fetchpriority, 2: $id */
161 __( 'Invalid fetchpriority `%1$s` defined for `%2$s` during script registration.' ),
162 is_string( $args['fetchpriority'] ) ? $args['fetchpriority'] : gettype( $args['fetchpriority'] ),
163 $id
164 ),
165 '6.9.0'
166 );
167 }
168 }
169
170 $this->registered[ $id ] = array(
171 'src' => $src,
172 'version' => $version,
173 'dependencies' => $dependencies,
174 'in_footer' => $in_footer,
175 'fetchpriority' => $fetchpriority,
176 );
177 }
178 }
179
180 /**
181 * Gets IDs for queued script modules.
182 *
183 * @since 6.9.0
184 *
185 * @return string[] Script module IDs.
186 */
187 public function get_queue(): array {
188 return $this->queue;
189 }
190
191 /**
192 * Checks if the provided fetchpriority is valid.
193 *
194 * @since 6.9.0
195 *
196 * @param string|mixed $priority Fetch priority.
197 * @return bool Whether valid fetchpriority.
198 */
199 private function is_valid_fetchpriority( $priority ): bool {
200 return in_array( $priority, $this->priorities, true );
201 }
202
203 /**
204 * Sets the fetch priority for a script module.
205 *
206 * @since 6.9.0
207 *
208 * @param string $id Script module identifier.
209 * @param 'auto'|'low'|'high' $priority Fetch priority for the script module.
210 * @return bool Whether setting the fetchpriority was successful.
211 */
212 public function set_fetchpriority( string $id, string $priority ): bool {
213 if ( ! isset( $this->registered[ $id ] ) ) {
214 return false;
215 }
216
217 if ( '' === $priority ) {
218 $priority = 'auto';
219 }
220
221 if ( ! $this->is_valid_fetchpriority( $priority ) ) {
222 _doing_it_wrong(
223 __METHOD__,
224 /* translators: %s: Invalid fetchpriority. */
225 sprintf( __( 'Invalid fetchpriority: %s' ), $priority ),
226 '6.9.0'
227 );
228 return false;
229 }
230
231 $this->registered[ $id ]['fetchpriority'] = $priority;
232 return true;
233 }
234
235 /**
236 * Sets whether a script module should be printed in the footer.
237 *
238 * This is only relevant in block themes.
239 *
240 * @since 6.9.0
241 *
242 * @param string $id Script module identifier.
243 * @param bool $in_footer Whether to print in the footer.
244 * @return bool Whether setting the printing location was successful.
245 */
246 public function set_in_footer( string $id, bool $in_footer ): bool {
247 if ( ! isset( $this->registered[ $id ] ) ) {
248 return false;
249 }
250 $this->registered[ $id ]['in_footer'] = $in_footer;
251 return true;
252 }
253
254 /**
255 * Marks the script module to be enqueued in the page.
256 *
257 * If a src is provided and the script module has not been registered yet, it
258 * will be registered.
259 *
260 * @since 6.5.0
261 * @since 6.9.0 Added the $args parameter.
262 *
263 * @param string $id The identifier of the script module. Should be unique. It will be used in the
264 * final import map.
265 * @param string $src Optional. Full URL of the script module, or path of the script module relative
266 * to the WordPress root directory. If it is provided and the script module has
267 * not been registered yet, it will be registered.
268 * @param array $deps {
269 * Optional. List of dependencies.
270 *
271 * @type string|array ...$0 {
272 * An array of script module identifiers of the dependencies of this script
273 * module. The dependencies can be strings or arrays. If they are arrays,
274 * they need an `id` key with the script module identifier, and can contain
275 * an `import` key with either `static` or `dynamic`. By default,
276 * dependencies that don't contain an `import` key are considered static.
277 *
278 * @type string $id The script module identifier.
279 * @type string $import Optional. Import type. May be either `static` or
280 * `dynamic`. Defaults to `static`.
281 * }
282 * }
283 * @param string|false|null $version Optional. String specifying the script module version number. Defaults to false.
284 * It is added to the URL as a query string for cache busting purposes. If $version
285 * is set to false, the version number is the currently installed WordPress version.
286 * If $version is set to null, no version is added.
287 * @param array $args {
288 * Optional. An array of additional args. Default empty array.
289 *
290 * @type bool $in_footer Whether to print the script module in the footer. Only relevant to block themes. Default 'false'. Optional.
291 * @type 'auto'|'low'|'high' $fetchpriority Fetch priority. Default 'auto'. Optional.
292 * }
293 */
294 public function enqueue( string $id, string $src = '', array $deps = array(), $version = false, array $args = array() ) {
295 if ( '' === $id ) {
296 _doing_it_wrong( __METHOD__, __( 'Non-empty string required for id.' ), '6.9.0' );
297 return;
298 }
299
300 if ( ! in_array( $id, $this->queue, true ) ) {
301 $this->queue[] = $id;
302 }
303 if ( ! isset( $this->registered[ $id ] ) && $src ) {
304 $this->register( $id, $src, $deps, $version, $args );
305 }
306 }
307
308 /**
309 * Unmarks the script module so it will no longer be enqueued in the page.
310 *
311 * @since 6.5.0
312 *
313 * @param string $id The identifier of the script module.
314 */
315 public function dequeue( string $id ) {
316 $this->queue = array_values( array_diff( $this->queue, array( $id ) ) );
317 }
318
319 /**
320 * Removes a registered script module.
321 *
322 * @since 6.5.0
323 *
324 * @param string $id The identifier of the script module.
325 */
326 public function deregister( string $id ) {
327 $this->dequeue( $id );
328 unset( $this->registered[ $id ] );
329 }
330
331 /**
332 * Adds the hooks to print the import map, enqueued script modules and script
333 * module preloads.
334 *
335 * In classic themes, the script modules used by the blocks are not yet known
336 * when the `wp_head` actions is fired, so it needs to print everything in the
337 * footer.
338 *
339 * @since 6.5.0
340 */
341 public function add_hooks() {
342 $is_block_theme = wp_is_block_theme();
343 $position = $is_block_theme ? 'wp_head' : 'wp_footer';
344 add_action( $position, array( $this, 'print_import_map' ) );
345 if ( $is_block_theme ) {
346 /*
347 * Modules can only be printed in the head for block themes because only with
348 * block themes will import map be fully populated by modules discovered by
349 * rendering the block template. In classic themes, modules are enqueued during
350 * template rendering, thus the import map must be printed in the footer,
351 * followed by all enqueued modules.
352 */
353 add_action( 'wp_head', array( $this, 'print_head_enqueued_script_modules' ) );
354 }
355 add_action( 'wp_footer', array( $this, 'print_enqueued_script_modules' ) );
356 add_action( $position, array( $this, 'print_script_module_preloads' ) );
357
358 add_action( 'admin_print_footer_scripts', array( $this, 'print_import_map' ) );
359 add_action( 'admin_print_footer_scripts', array( $this, 'print_enqueued_script_modules' ) );
360 add_action( 'admin_print_footer_scripts', array( $this, 'print_script_module_preloads' ) );
361
362 add_action( 'wp_footer', array( $this, 'print_script_module_data' ) );
363 add_action( 'admin_print_footer_scripts', array( $this, 'print_script_module_data' ) );
364 add_action( 'wp_footer', array( $this, 'print_a11y_script_module_html' ), 20 );
365 add_action( 'admin_print_footer_scripts', array( $this, 'print_a11y_script_module_html' ), 20 );
366 }
367
368 /**
369 * Gets the highest fetch priority for the provided script IDs.
370 *
371 * @since 6.9.0
372 *
373 * @param string[] $ids Script module IDs.
374 * @return 'auto'|'low'|'high' Highest fetch priority for the provided script module IDs.
375 */
376 private function get_highest_fetchpriority( array $ids ): string {
377 static $high_priority_index = null;
378 if ( null === $high_priority_index ) {
379 $high_priority_index = count( $this->priorities ) - 1;
380 }
381
382 $highest_priority_index = 0;
383 foreach ( $ids as $id ) {
384 if ( isset( $this->registered[ $id ] ) ) {
385 $highest_priority_index = (int) max(
386 $highest_priority_index,
387 (int) array_search( $this->registered[ $id ]['fetchpriority'], $this->priorities, true )
388 );
389 if ( $high_priority_index === $highest_priority_index ) {
390 break;
391 }
392 }
393 }
394
395 return $this->priorities[ $highest_priority_index ];
396 }
397
398 /**
399 * Prints the enqueued script modules in head.
400 *
401 * This is only used in block themes.
402 *
403 * @since 6.9.0
404 */
405 public function print_head_enqueued_script_modules() {
406 foreach ( $this->get_sorted_dependencies( $this->queue ) as $id ) {
407 if (
408 isset( $this->registered[ $id ] ) &&
409 ! $this->registered[ $id ]['in_footer']
410 ) {
411 // If any dependency is set to be printed in footer, skip printing this module in head.
412 $dependencies = array_keys( $this->get_dependencies( array( $id ) ) );
413 foreach ( $dependencies as $dependency_id ) {
414 if (
415 in_array( $dependency_id, $this->queue, true ) &&
416 isset( $this->registered[ $dependency_id ] ) &&
417 $this->registered[ $dependency_id ]['in_footer']
418 ) {
419 continue 2;
420 }
421 }
422 $this->print_script_module( $id );
423 }
424 }
425 }
426
427 /**
428 * Prints the enqueued script modules in footer.
429 *
430 * @since 6.5.0
431 */
432 public function print_enqueued_script_modules() {
433 foreach ( $this->get_sorted_dependencies( $this->queue ) as $id ) {
434 $this->print_script_module( $id );
435 }
436 }
437
438 /**
439 * Prints the enqueued script module using script tags with type="module"
440 * attributes.
441 *
442 * @since 6.9.0
443 *
444 * @param string $id The script module identifier.
445 */
446 private function print_script_module( string $id ) {
447 if ( in_array( $id, $this->done, true ) || ! in_array( $id, $this->queue, true ) ) {
448 return;
449 }
450
451 $this->done[] = $id;
452
453 $src = $this->get_src( $id );
454 if ( '' === $src ) {
455 return;
456 }
457
458 $attributes = array(
459 'type' => 'module',
460 'src' => $src,
461 'id' => $id . '-js-module',
462 );
463
464 $script_module = $this->registered[ $id ];
465 $queued_dependents = array_intersect( $this->queue, $this->get_recursive_dependents( $id ) );
466 $fetchpriority = $this->get_highest_fetchpriority( array_merge( array( $id ), $queued_dependents ) );
467 if ( 'auto' !== $fetchpriority ) {
468 $attributes['fetchpriority'] = $fetchpriority;
469 }
470 if ( $fetchpriority !== $script_module['fetchpriority'] ) {
471 $attributes['data-wp-fetchpriority'] = $script_module['fetchpriority'];
472 }
473 wp_print_script_tag( $attributes );
474 }
475
476 /**
477 * Prints the static dependencies of the enqueued script modules using
478 * link tags with rel="modulepreload" attributes.
479 *
480 * If a script module is marked for enqueue, it will not be preloaded.
481 *
482 * @since 6.5.0
483 */
484 public function print_script_module_preloads() {
485 $dependency_ids = $this->get_sorted_dependencies( $this->queue, array( 'static' ) );
486 foreach ( $dependency_ids as $id ) {
487 // Don't preload if it's marked for enqueue.
488 if ( in_array( $id, $this->queue, true ) ) {
489 continue;
490 }
491
492 $src = $this->get_src( $id );
493 if ( '' === $src ) {
494 continue;
495 }
496
497 $enqueued_dependents = array_intersect( $this->get_recursive_dependents( $id ), $this->queue );
498 $highest_fetchpriority = $this->get_highest_fetchpriority( $enqueued_dependents );
499 printf(
500 '<link rel="modulepreload" href="%s" id="%s"',
501 esc_url( $src ),
502 esc_attr( $id . '-js-modulepreload' )
503 );
504 if ( 'auto' !== $highest_fetchpriority ) {
505 printf( ' fetchpriority="%s"', esc_attr( $highest_fetchpriority ) );
506 }
507 if ( $highest_fetchpriority !== $this->registered[ $id ]['fetchpriority'] && 'auto' !== $this->registered[ $id ]['fetchpriority'] ) {
508 printf( ' data-wp-fetchpriority="%s"', esc_attr( $this->registered[ $id ]['fetchpriority'] ) );
509 }
510 echo ">\n";
511 }
512 }
513
514 /**
515 * Prints the import map using a script tag with a type="importmap" attribute.
516 *
517 * @since 6.5.0
518 */
519 public function print_import_map() {
520 $import_map = $this->get_import_map();
521 if ( ! empty( $import_map['imports'] ) ) {
522 wp_print_inline_script_tag(
523 (string) wp_json_encode( $import_map, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ),
524 array(
525 'type' => 'importmap',
526 'id' => 'wp-importmap',
527 )
528 );
529 }
530 }
531
532 /**
533 * Returns the import map array.
534 *
535 * @since 6.5.0
536 *
537 * @return array Array with an `imports` key mapping to an array of script module identifiers and their respective
538 * URLs, including the version query.
539 */
540 private function get_import_map(): array {
541 $imports = array();
542 foreach ( array_keys( $this->get_dependencies( $this->queue ) ) as $id ) {
543 $src = $this->get_src( $id );
544 if ( '' !== $src ) {
545 $imports[ $id ] = $src;
546 }
547 }
548 return array( 'imports' => $imports );
549 }
550
551 /**
552 * Retrieves the list of script modules marked for enqueue.
553 *
554 * Even though this is a private method and is unused in core, there are ecosystem plugins accessing it via the
555 * Reflection API. The ecosystem should rather use {@see self::get_queue()}.
556 *
557 * @since 6.5.0
558 *
559 * @return array<string, array> Script modules marked for enqueue, keyed by script module identifier.
560 */
561 private function get_marked_for_enqueue(): array {
562 return wp_array_slice_assoc(
563 $this->registered,
564 $this->queue
565 );
566 }
567
568 /**
569 * Retrieves all the dependencies for the given script module identifiers, filtered by import types.
570 *
571 * It will consolidate an array containing a set of unique dependencies based
572 * on the requested import types: 'static', 'dynamic', or both. This method is
573 * recursive and also retrieves dependencies of the dependencies.
574 *
575 * @since 6.5.0
576 *
577 * @param string[] $ids The identifiers of the script modules for which to gather dependencies.
578 * @param string[] $import_types Optional. Import types of dependencies to retrieve: 'static', 'dynamic', or both.
579 * Default is both.
580 * @return array<string, array> List of dependencies, keyed by script module identifier.
581 */
582 private function get_dependencies( array $ids, array $import_types = array( 'static', 'dynamic' ) ): array {
583 $all_dependencies = array();
584 $id_queue = $ids;
585
586 while ( ! empty( $id_queue ) ) {
587 $id = array_shift( $id_queue );
588 if ( ! isset( $this->registered[ $id ] ) ) {
589 continue;
590 }
591
592 foreach ( $this->registered[ $id ]['dependencies'] as $dependency ) {
593 if (
594 ! isset( $all_dependencies[ $dependency['id'] ] ) &&
595 in_array( $dependency['import'], $import_types, true ) &&
596 isset( $this->registered[ $dependency['id'] ] )
597 ) {
598 $all_dependencies[ $dependency['id'] ] = $this->registered[ $dependency['id'] ];
599
600 // Add this dependency to the list to get dependencies for.
601 $id_queue[] = $dependency['id'];
602 }
603 }
604 }
605
606 return $all_dependencies;
607 }
608
609 /**
610 * Gets all dependents of a script module.
611 *
612 * This is not recursive.
613 *
614 * @since 6.9.0
615 *
616 * @see WP_Scripts::get_dependents()
617 *
618 * @param string $id The script ID.
619 * @return string[] Script module IDs.
620 */
621 private function get_dependents( string $id ): array {
622 // Check if dependents map for the handle in question is present. If so, use it.
623 if ( isset( $this->dependents_map[ $id ] ) ) {
624 return $this->dependents_map[ $id ];
625 }
626
627 $dependents = array();
628
629 // Iterate over all registered scripts, finding dependents of the script passed to this method.
630 foreach ( $this->registered as $registered_id => $args ) {
631 if ( in_array( $id, wp_list_pluck( $args['dependencies'], 'id' ), true ) ) {
632 $dependents[] = $registered_id;
633 }
634 }
635
636 // Add the module's dependents to the map to ease future lookups.
637 $this->dependents_map[ $id ] = $dependents;
638
639 return $dependents;
640 }
641
642 /**
643 * Gets all recursive dependents of a script module.
644 *
645 * @since 6.9.0
646 *
647 * @see WP_Scripts::get_dependents()
648 *
649 * @param string $id The script ID.
650 * @return string[] Script module IDs.
651 */
652 private function get_recursive_dependents( string $id ): array {
653 $dependents = array();
654 $id_queue = array( $id );
655 $processed = array();
656
657 while ( ! empty( $id_queue ) ) {
658 $current_id = array_shift( $id_queue );
659
660 // Skip unregistered or already-processed script modules.
661 if ( ! isset( $this->registered[ $current_id ] ) || isset( $processed[ $current_id ] ) ) {
662 continue;
663 }
664
665 // Mark as processed to guard against infinite loops from circular dependencies.
666 $processed[ $current_id ] = true;
667
668 // Find the direct dependents of the current script.
669 foreach ( $this->get_dependents( $current_id ) as $dependent_id ) {
670 // Only add the dependent if we haven't found it before.
671 if ( ! isset( $dependents[ $dependent_id ] ) ) {
672 $dependents[ $dependent_id ] = true;
673
674 // Add dependency to the queue.
675 $id_queue[] = $dependent_id;
676 }
677 }
678 }
679
680 return array_keys( $dependents );
681 }
682
683 /**
684 * Sorts the given script module identifiers based on their dependencies.
685 *
686 * It will return a list of script module identifiers sorted in the order
687 * they should be printed, so that dependencies are printed before the script
688 * modules that depend on them.
689 *
690 * @since 6.9.0
691 *
692 * @param string[] $ids The identifiers of the script modules to sort.
693 * @param string[] $import_types Optional. Import types of dependencies to retrieve: 'static', 'dynamic', or both.
694 * Default is both.
695 * @return string[] Sorted list of script module identifiers.
696 */
697 private function get_sorted_dependencies( array $ids, array $import_types = array( 'static', 'dynamic' ) ): array {
698 $sorted = array();
699
700 foreach ( $ids as $id ) {
701 $this->sort_item_dependencies( $id, $import_types, $sorted );
702 }
703
704 return array_unique( $sorted );
705 }
706
707 /**
708 * Recursively sorts the dependencies for a single script module identifier.
709 *
710 * @since 6.9.0
711 *
712 * @param string $id The identifier of the script module to sort.
713 * @param string[] $import_types Optional. Import types of dependencies to retrieve: 'static', 'dynamic', or both.
714 * @param string[] &$sorted The array of sorted identifiers, passed by reference.
715 * @return bool True on success, false on failure (e.g., missing dependency).
716 */
717 private function sort_item_dependencies( string $id, array $import_types, array &$sorted ): bool {
718 // If already processed, don't do it again.
719 if ( in_array( $id, $sorted, true ) ) {
720 return true;
721 }
722
723 // If the item doesn't exist, fail.
724 if ( ! isset( $this->registered[ $id ] ) ) {
725 return false;
726 }
727
728 $dependency_ids = array();
729 foreach ( $this->registered[ $id ]['dependencies'] as $dependency ) {
730 if ( in_array( $dependency['import'], $import_types, true ) ) {
731 $dependency_ids[] = $dependency['id'];
732 }
733 }
734
735 // If the item requires dependencies that do not exist, fail.
736 $missing_dependencies = array_diff( $dependency_ids, array_keys( $this->registered ) );
737 if ( count( $missing_dependencies ) > 0 ) {
738 if ( ! in_array( $id, $this->modules_with_missing_dependencies, true ) ) {
739 _doing_it_wrong(
740 get_class( $this ) . '::register',
741 sprintf(
742 /* translators: 1: Script module ID, 2: List of missing dependency IDs. */
743 __( 'The script module with the ID "%1$s" was enqueued with dependencies that are not registered: %2$s.' ),
744 $id,
745 implode( wp_get_list_item_separator(), $missing_dependencies )
746 ),
747 '6.9.1'
748 );
749 $this->modules_with_missing_dependencies[] = $id;
750 }
751
752 return false;
753 }
754
755 // Recursively process dependencies.
756 foreach ( $dependency_ids as $dependency_id ) {
757 if ( ! $this->sort_item_dependencies( $dependency_id, $import_types, $sorted ) ) {
758 // A dependency failed to resolve, so this branch fails.
759 return false;
760 }
761 }
762
763 // All dependencies are sorted, so we can now add the current item.
764 $sorted[] = $id;
765
766 return true;
767 }
768
769 /**
770 * Gets the versioned URL for a script module src.
771 *
772 * If $version is set to false, the version number is the currently installed
773 * WordPress version. If $version is set to null, no version is added.
774 * Otherwise, the string passed in $version is used.
775 *
776 * @since 6.5.0
777 *
778 * @param string $id The script module identifier.
779 * @return string The script module src with a version if relevant.
780 */
781 private function get_src( string $id ): string {
782 if ( ! isset( $this->registered[ $id ] ) ) {
783 return '';
784 }
785
786 $script_module = $this->registered[ $id ];
787 $src = $script_module['src'];
788
789 if ( '' !== $src ) {
790 if ( false === $script_module['version'] ) {
791 $src = add_query_arg( 'ver', get_bloginfo( 'version' ), $src );
792 } elseif ( null !== $script_module['version'] ) {
793 $src = add_query_arg( 'ver', $script_module['version'], $src );
794 }
795 }
796
797 /**
798 * Filters the script module source.
799 *
800 * @since 6.5.0
801 *
802 * @param string $src Module source URL.
803 * @param string $id Module identifier.
804 */
805 $src = apply_filters( 'script_module_loader_src', $src, $id );
806 if ( ! is_string( $src ) ) {
807 $src = '';
808 }
809
810 return $src;
811 }
812
813 /**
814 * Print data associated with Script Modules.
815 *
816 * The data will be embedded in the page HTML and can be read by Script Modules on page load.
817 *
818 * @since 6.7.0
819 *
820 * Data can be associated with a Script Module via the
821 * {@see "script_module_data_{$module_id}"} filter.
822 *
823 * The data for a Script Module will be serialized as JSON in a script tag with an ID of the
824 * form `wp-script-module-data-{$module_id}`.
825 */
826 public function print_script_module_data(): void {
827 $modules = array();
828 foreach ( array_unique( $this->queue ) as $id ) {
829 if ( '@wordpress/a11y' === $id ) {
830 $this->a11y_available = true;
831 }
832 $modules[ $id ] = true;
833 }
834 foreach ( array_keys( $this->get_import_map()['imports'] ) as $id ) {
835 if ( '@wordpress/a11y' === $id ) {
836 $this->a11y_available = true;
837 }
838 $modules[ $id ] = true;
839 }
840
841 foreach ( array_keys( $modules ) as $module_id ) {
842 /**
843 * Filters data associated with a given Script Module.
844 *
845 * Script Modules may require data that is required for initialization or is essential
846 * to have immediately available on page load. These are suitable use cases for
847 * this data.
848 *
849 * The dynamic portion of the hook name, `$module_id`, refers to the Script Module ID
850 * that the data is associated with.
851 *
852 * This is best suited to pass essential data that must be available to the module for
853 * initialization or immediately on page load. It does not replace the REST API or
854 * fetching data from the client.
855 *
856 * Example:
857 *
858 * add_filter(
859 * 'script_module_data_MyScriptModuleID',
860 * function ( array $data ): array {
861 * $data['dataForClient'] = 'ok';
862 * return $data;
863 * }
864 * );
865 *
866 * If the filter returns no data (an empty array), nothing will be embedded in the page.
867 *
868 * The data for a given Script Module, if provided, will be JSON serialized in a script
869 * tag with an ID of the form `wp-script-module-data-{$module_id}`.
870 *
871 * The data can be read on the client with a pattern like this:
872 *
873 * Example:
874 *
875 * const dataContainer = document.getElementById( 'wp-script-module-data-MyScriptModuleID' );
876 * let data = {};
877 * if ( dataContainer ) {
878 * try {
879 * data = JSON.parse( dataContainer.textContent );
880 * } catch {}
881 * }
882 * // data.dataForClient === 'ok';
883 * initMyScriptModuleWithData( data );
884 *
885 * @since 6.7.0
886 *
887 * @param array $data The data associated with the Script Module.
888 */
889 $data = apply_filters( "script_module_data_{$module_id}", array() );
890
891 if ( is_array( $data ) && array() !== $data ) {
892 /*
893 * This data will be printed as JSON inside a script tag like this:
894 * <script type="application/json"></script>
895 *
896 * A script tag must be closed by a sequence beginning with `</`. It's impossible to
897 * close a script tag without using `<`. We ensure that `<` is escaped and `/` can
898 * remain unescaped, so `</script>` will be printed as `\u003C/script\u00E3`.
899 *
900 * - JSON_HEX_TAG: All < and > are converted to \u003C and \u003E.
901 * - JSON_UNESCAPED_SLASHES: Don't escape /.
902 *
903 * If the page will use UTF-8 encoding, it's safe to print unescaped unicode:
904 *
905 * - JSON_UNESCAPED_UNICODE: Encode multibyte Unicode characters literally (instead of as `\uXXXX`).
906 * - JSON_UNESCAPED_LINE_TERMINATORS: The line terminators are kept unescaped when
907 * JSON_UNESCAPED_UNICODE is supplied. It uses the same behaviour as it was
908 * before PHP 7.1 without this constant. Available as of PHP 7.1.0.
909 *
910 * The JSON specification requires encoding in UTF-8, so if the generated HTML page
911 * is not encoded in UTF-8 then it's not safe to include those literals. They must
912 * be escaped to avoid encoding issues.
913 *
914 * @see https://www.rfc-editor.org/rfc/rfc8259.html for details on encoding requirements.
915 * @see https://www.php.net/manual/en/json.constants.php for details on these constants.
916 * @see https://html.spec.whatwg.org/#script-data-state for details on script tag parsing.
917 */
918 $json_encode_flags = JSON_HEX_TAG | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_LINE_TERMINATORS;
919 if ( ! is_utf8_charset() ) {
920 $json_encode_flags = JSON_HEX_TAG | JSON_UNESCAPED_SLASHES;
921 }
922
923 wp_print_inline_script_tag(
924 (string) wp_json_encode(
925 $data,
926 $json_encode_flags
927 ),
928 array(
929 'type' => 'application/json',
930 'id' => "wp-script-module-data-{$module_id}",
931 )
932 );
933 }
934 }
935 }
936
937 /**
938 * @access private This is only intended to be called by the registered actions.
939 *
940 * @since 6.7.0
941 */
942 public function print_a11y_script_module_html() {
943 if ( ! $this->a11y_available ) {
944 return;
945 }
946 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;">'
947 . '<p id="a11y-speak-intro-text" class="a11y-speak-intro-text" hidden>' . esc_html__( 'Notifications' ) . '</p>'
948 . '<div id="a11y-speak-assertive" class="a11y-speak-region" aria-live="assertive" aria-relevant="additions text" aria-atomic="true"></div>'
949 . '<div id="a11y-speak-polite" class="a11y-speak-region" aria-live="polite" aria-relevant="additions text" aria-atomic="true"></div>'
950 . '</div>';
951 }
952}
953
Ui Ux Design – Teachers Night Out https://cardgames4educators.com Wed, 16 Oct 2024 22:24:18 +0000 en-US hourly 1 https://wordpress.org/?v=6.9.4 https://cardgames4educators.com/wp-content/uploads/2024/06/cropped-Card-4-Educators-logo-32x32.png Ui Ux Design – Teachers Night Out https://cardgames4educators.com 32 32 Masters In English How English Speaker https://cardgames4educators.com/masters-in-english-how-english-speaker/ https://cardgames4educators.com/masters-in-english-how-english-speaker/#comments Mon, 27 May 2024 08:54:45 +0000 https://themexriver.com/wp/kadu/?p=1

Erat himenaeos neque id sagittis massa. Hac suscipit pulvinar dignissim platea magnis eu. Don tellus a pharetra inceptos efficitur dui pulvinar. Feugiat facilisis penatibus pulvinar nunc dictumst donec odio platea habitasse. Lacus porta dolor purus elit ante bibendum tortor netus taciti nullam cubilia. Erat per suspendisse placerat morbi egestas pulvinar bibendum sollicitudin nec. Euismod cubilia eleifend velit himenaeos sodales lectus. Leo maximus cras ac porttitor aliquam torquent pulvinar odio volutpat parturient. Quisque risus finibus suspendisse mus purus magnis facilisi condimentum consectetur dui. Curae elit suspendisse cursus vehicula.

Turpis taciti class non vel pretium quis pulvinar tempor lobortis nunc. Libero phasellus parturient sapien volutpat malesuada ornare. Cubilia dignissim sollicitudin rhoncus lacinia maximus. Cras lorem fermentum bibendum pellentesque nisl etiam ligula enim cubilia. Vulputate pede sapien torquent montes tempus malesuada in mattis dis turpis vitae. Porta est tempor ex eget feugiat vulputate ipsum. Justo nec iaculis habitant diam arcu fermentum.

We offer comprehen sive emplo ment services such as assistance wit employer compliance.Our company is your strategic HR partner as instead of HR. john smithson

Cubilia dignissim sollicitudin rhoncus lacinia maximus. Cras lorem fermentum bibendum pellentesque nisl etiam ligula enim cubilia. Vulputate pede sapien torquent montes tempus malesuada in mattis dis turpis vitae.

Exploring Learning Landscapes in Academic

Feugiat facilisis penatibus pulvinar nunc dictumst donec odio platea habitasse. Lacus porta dolor purus elit ante bibendum tortor netus taciti nullam cubilia. Erat per suspendisse placerat morbi egestas pulvinar bibendum sollicitudin nec. Euismod cubilia eleifend velit himenaeos sodales lectus. Leo maximus cras ac porttitor aliquam torquent.

]]>
https://cardgames4educators.com/masters-in-english-how-english-speaker/feed/ 1