|
1 <?php |
|
2 /** |
|
3 * Dependencies API: WP_Scripts class |
|
4 * |
|
5 * @since 2.6.0 |
|
6 * |
|
7 * @package WordPress |
|
8 * @subpackage Dependencies |
|
9 */ |
|
10 |
|
11 /** |
|
12 * Core class used to register scripts. |
|
13 * |
|
14 * @since 2.1.0 |
|
15 * |
|
16 * @see WP_Dependencies |
|
17 */ |
|
18 class WP_Scripts extends WP_Dependencies { |
|
19 /** |
|
20 * Base URL for scripts. |
|
21 * |
|
22 * Full URL with trailing slash. |
|
23 * |
|
24 * @since 2.6.0 |
|
25 * @var string |
|
26 */ |
|
27 public $base_url; |
|
28 |
|
29 /** |
|
30 * URL of the content directory. |
|
31 * |
|
32 * @since 2.8.0 |
|
33 * @var string |
|
34 */ |
|
35 public $content_url; |
|
36 |
|
37 /** |
|
38 * Default version string for scripts. |
|
39 * |
|
40 * @since 2.6.0 |
|
41 * @var string |
|
42 */ |
|
43 public $default_version; |
|
44 |
|
45 /** |
|
46 * Holds handles of scripts which are enqueued in footer. |
|
47 * |
|
48 * @since 2.8.0 |
|
49 * @var array |
|
50 */ |
|
51 public $in_footer = array(); |
|
52 |
|
53 /** |
|
54 * Holds a list of script handles which will be concatenated. |
|
55 * |
|
56 * @since 2.8.0 |
|
57 * @var string |
|
58 */ |
|
59 public $concat = ''; |
|
60 |
|
61 /** |
|
62 * Holds a string which contains script handles and their version. |
|
63 * |
|
64 * @since 2.8.0 |
|
65 * @deprecated 3.4.0 |
|
66 * @var string |
|
67 */ |
|
68 public $concat_version = ''; |
|
69 |
|
70 /** |
|
71 * Whether to perform concatenation. |
|
72 * |
|
73 * @since 2.8.0 |
|
74 * @var bool |
|
75 */ |
|
76 public $do_concat = false; |
|
77 |
|
78 /** |
|
79 * Holds HTML markup of scripts and additional data if concatenation |
|
80 * is enabled. |
|
81 * |
|
82 * @since 2.8.0 |
|
83 * @var string |
|
84 */ |
|
85 public $print_html = ''; |
|
86 |
|
87 /** |
|
88 * Holds inline code if concatenation is enabled. |
|
89 * |
|
90 * @since 2.8.0 |
|
91 * @var string |
|
92 */ |
|
93 public $print_code = ''; |
|
94 |
|
95 /** |
|
96 * Holds a list of script handles which are not in the default directory |
|
97 * if concatenation is enabled. |
|
98 * |
|
99 * Unused in core. |
|
100 * |
|
101 * @since 2.8.0 |
|
102 * @var string |
|
103 */ |
|
104 public $ext_handles = ''; |
|
105 |
|
106 /** |
|
107 * Holds a string which contains handles and versions of scripts which |
|
108 * are not in the default directory if concatenation is enabled. |
|
109 * |
|
110 * Unused in core. |
|
111 * |
|
112 * @since 2.8.0 |
|
113 * @var string |
|
114 */ |
|
115 public $ext_version = ''; |
|
116 |
|
117 /** |
|
118 * List of default directories. |
|
119 * |
|
120 * @since 2.8.0 |
|
121 * @var array |
|
122 */ |
|
123 public $default_dirs; |
|
124 |
|
125 /** |
|
126 * Holds a mapping of dependents (as handles) for a given script handle. |
|
127 * Used to optimize recursive dependency tree checks. |
|
128 * |
|
129 * @since 6.3.0 |
|
130 * @var array |
|
131 */ |
|
132 private $dependents_map = array(); |
|
133 |
|
134 /** |
|
135 * Holds a reference to the delayed (non-blocking) script loading strategies. |
|
136 * Used by methods that validate loading strategies. |
|
137 * |
|
138 * @since 6.3.0 |
|
139 * @var string[] |
|
140 */ |
|
141 private $delayed_strategies = array( 'defer', 'async' ); |
|
142 |
|
143 /** |
|
144 * Constructor. |
|
145 * |
|
146 * @since 2.6.0 |
|
147 */ |
|
148 public function __construct() { |
|
149 $this->init(); |
|
150 add_action( 'init', array( $this, 'init' ), 0 ); |
|
151 } |
|
152 |
|
153 /** |
|
154 * Initialize the class. |
|
155 * |
|
156 * @since 3.4.0 |
|
157 */ |
|
158 public function init() { |
|
159 /** |
|
160 * Fires when the WP_Scripts instance is initialized. |
|
161 * |
|
162 * @since 2.6.0 |
|
163 * |
|
164 * @param WP_Scripts $wp_scripts WP_Scripts instance (passed by reference). |
|
165 */ |
|
166 do_action_ref_array( 'wp_default_scripts', array( &$this ) ); |
|
167 } |
|
168 |
|
169 /** |
|
170 * Prints scripts. |
|
171 * |
|
172 * Prints the scripts passed to it or the print queue. Also prints all necessary dependencies. |
|
173 * |
|
174 * @since 2.1.0 |
|
175 * @since 2.8.0 Added the `$group` parameter. |
|
176 * |
|
177 * @param string|string[]|false $handles Optional. Scripts to be printed: queue (false), |
|
178 * single script (string), or multiple scripts (array of strings). |
|
179 * Default false. |
|
180 * @param int|false $group Optional. Group level: level (int), no groups (false). |
|
181 * Default false. |
|
182 * @return string[] Handles of scripts that have been printed. |
|
183 */ |
|
184 public function print_scripts( $handles = false, $group = false ) { |
|
185 return $this->do_items( $handles, $group ); |
|
186 } |
|
187 |
|
188 /** |
|
189 * Prints extra scripts of a registered script. |
|
190 * |
|
191 * @since 2.1.0 |
|
192 * @since 2.8.0 Added the `$display` parameter. |
|
193 * @deprecated 3.3.0 |
|
194 * |
|
195 * @see print_extra_script() |
|
196 * |
|
197 * @param string $handle The script's registered handle. |
|
198 * @param bool $display Optional. Whether to print the extra script |
|
199 * instead of just returning it. Default true. |
|
200 * @return bool|string|void Void if no data exists, extra scripts if `$display` is true, |
|
201 * true otherwise. |
|
202 */ |
|
203 public function print_scripts_l10n( $handle, $display = true ) { |
|
204 _deprecated_function( __FUNCTION__, '3.3.0', 'WP_Scripts::print_extra_script()' ); |
|
205 return $this->print_extra_script( $handle, $display ); |
|
206 } |
|
207 |
|
208 /** |
|
209 * Prints extra scripts of a registered script. |
|
210 * |
|
211 * @since 3.3.0 |
|
212 * |
|
213 * @param string $handle The script's registered handle. |
|
214 * @param bool $display Optional. Whether to print the extra script |
|
215 * instead of just returning it. Default true. |
|
216 * @return bool|string|void Void if no data exists, extra scripts if `$display` is true, |
|
217 * true otherwise. |
|
218 */ |
|
219 public function print_extra_script( $handle, $display = true ) { |
|
220 $output = $this->get_data( $handle, 'data' ); |
|
221 if ( ! $output ) { |
|
222 return; |
|
223 } |
|
224 |
|
225 if ( ! $display ) { |
|
226 return $output; |
|
227 } |
|
228 |
|
229 wp_print_inline_script_tag( $output, array( 'id' => "{$handle}-js-extra" ) ); |
|
230 |
|
231 return true; |
|
232 } |
|
233 |
|
234 /** |
|
235 * Checks whether all dependents of a given handle are in the footer. |
|
236 * |
|
237 * If there are no dependents, this is considered the same as if all dependents were in the footer. |
|
238 * |
|
239 * @since 6.4.0 |
|
240 * |
|
241 * @param string $handle Script handle. |
|
242 * @return bool Whether all dependents are in the footer. |
|
243 */ |
|
244 private function are_all_dependents_in_footer( $handle ) { |
|
245 foreach ( $this->get_dependents( $handle ) as $dep ) { |
|
246 if ( isset( $this->groups[ $dep ] ) && 0 === $this->groups[ $dep ] ) { |
|
247 return false; |
|
248 } |
|
249 } |
|
250 return true; |
|
251 } |
|
252 |
|
253 /** |
|
254 * Processes a script dependency. |
|
255 * |
|
256 * @since 2.6.0 |
|
257 * @since 2.8.0 Added the `$group` parameter. |
|
258 * |
|
259 * @see WP_Dependencies::do_item() |
|
260 * |
|
261 * @param string $handle The script's registered handle. |
|
262 * @param int|false $group Optional. Group level: level (int), no groups (false). |
|
263 * Default false. |
|
264 * @return bool True on success, false on failure. |
|
265 */ |
|
266 public function do_item( $handle, $group = false ) { |
|
267 if ( ! parent::do_item( $handle ) ) { |
|
268 return false; |
|
269 } |
|
270 |
|
271 if ( 0 === $group && $this->groups[ $handle ] > 0 ) { |
|
272 $this->in_footer[] = $handle; |
|
273 return false; |
|
274 } |
|
275 |
|
276 if ( false === $group && in_array( $handle, $this->in_footer, true ) ) { |
|
277 $this->in_footer = array_diff( $this->in_footer, (array) $handle ); |
|
278 } |
|
279 |
|
280 $obj = $this->registered[ $handle ]; |
|
281 |
|
282 if ( null === $obj->ver ) { |
|
283 $ver = ''; |
|
284 } else { |
|
285 $ver = $obj->ver ? $obj->ver : $this->default_version; |
|
286 } |
|
287 |
|
288 if ( isset( $this->args[ $handle ] ) ) { |
|
289 $ver = $ver ? $ver . '&' . $this->args[ $handle ] : $this->args[ $handle ]; |
|
290 } |
|
291 |
|
292 $src = $obj->src; |
|
293 $strategy = $this->get_eligible_loading_strategy( $handle ); |
|
294 $intended_strategy = (string) $this->get_data( $handle, 'strategy' ); |
|
295 $cond_before = ''; |
|
296 $cond_after = ''; |
|
297 $conditional = isset( $obj->extra['conditional'] ) ? $obj->extra['conditional'] : ''; |
|
298 |
|
299 if ( ! $this->is_delayed_strategy( $intended_strategy ) ) { |
|
300 $intended_strategy = ''; |
|
301 } |
|
302 |
|
303 /* |
|
304 * Move this script to the footer if: |
|
305 * 1. The script is in the header group. |
|
306 * 2. The current output is the header. |
|
307 * 3. The intended strategy is delayed. |
|
308 * 4. The actual strategy is not delayed. |
|
309 * 5. All dependent scripts are in the footer. |
|
310 */ |
|
311 if ( |
|
312 0 === $group && |
|
313 0 === $this->groups[ $handle ] && |
|
314 $intended_strategy && |
|
315 ! $this->is_delayed_strategy( $strategy ) && |
|
316 $this->are_all_dependents_in_footer( $handle ) |
|
317 ) { |
|
318 $this->in_footer[] = $handle; |
|
319 return false; |
|
320 } |
|
321 |
|
322 if ( $conditional ) { |
|
323 $cond_before = "<!--[if {$conditional}]>\n"; |
|
324 $cond_after = "<![endif]-->\n"; |
|
325 } |
|
326 |
|
327 $before_script = $this->get_inline_script_tag( $handle, 'before' ); |
|
328 $after_script = $this->get_inline_script_tag( $handle, 'after' ); |
|
329 |
|
330 if ( $before_script || $after_script ) { |
|
331 $inline_script_tag = $cond_before . $before_script . $after_script . $cond_after; |
|
332 } else { |
|
333 $inline_script_tag = ''; |
|
334 } |
|
335 |
|
336 /* |
|
337 * Prevent concatenation of scripts if the text domain is defined |
|
338 * to ensure the dependency order is respected. |
|
339 */ |
|
340 $translations_stop_concat = ! empty( $obj->textdomain ); |
|
341 |
|
342 $translations = $this->print_translations( $handle, false ); |
|
343 if ( $translations ) { |
|
344 $translations = wp_get_inline_script_tag( $translations, array( 'id' => "{$handle}-js-translations" ) ); |
|
345 } |
|
346 |
|
347 if ( $this->do_concat ) { |
|
348 /** |
|
349 * Filters the script loader source. |
|
350 * |
|
351 * @since 2.2.0 |
|
352 * |
|
353 * @param string $src Script loader source path. |
|
354 * @param string $handle Script handle. |
|
355 */ |
|
356 $srce = apply_filters( 'script_loader_src', $src, $handle ); |
|
357 |
|
358 if ( |
|
359 $this->in_default_dir( $srce ) |
|
360 && ( $before_script || $after_script || $translations_stop_concat || $this->is_delayed_strategy( $strategy ) ) |
|
361 ) { |
|
362 $this->do_concat = false; |
|
363 |
|
364 // Have to print the so-far concatenated scripts right away to maintain the right order. |
|
365 _print_scripts(); |
|
366 $this->reset(); |
|
367 } elseif ( $this->in_default_dir( $srce ) && ! $conditional ) { |
|
368 $this->print_code .= $this->print_extra_script( $handle, false ); |
|
369 $this->concat .= "$handle,"; |
|
370 $this->concat_version .= "$handle$ver"; |
|
371 return true; |
|
372 } else { |
|
373 $this->ext_handles .= "$handle,"; |
|
374 $this->ext_version .= "$handle$ver"; |
|
375 } |
|
376 } |
|
377 |
|
378 $has_conditional_data = $conditional && $this->get_data( $handle, 'data' ); |
|
379 |
|
380 if ( $has_conditional_data ) { |
|
381 echo $cond_before; |
|
382 } |
|
383 |
|
384 $this->print_extra_script( $handle ); |
|
385 |
|
386 if ( $has_conditional_data ) { |
|
387 echo $cond_after; |
|
388 } |
|
389 |
|
390 // A single item may alias a set of items, by having dependencies, but no source. |
|
391 if ( ! $src ) { |
|
392 if ( $inline_script_tag ) { |
|
393 if ( $this->do_concat ) { |
|
394 $this->print_html .= $inline_script_tag; |
|
395 } else { |
|
396 echo $inline_script_tag; |
|
397 } |
|
398 } |
|
399 |
|
400 return true; |
|
401 } |
|
402 |
|
403 if ( ! preg_match( '|^(https?:)?//|', $src ) && ! ( $this->content_url && str_starts_with( $src, $this->content_url ) ) ) { |
|
404 $src = $this->base_url . $src; |
|
405 } |
|
406 |
|
407 if ( ! empty( $ver ) ) { |
|
408 $src = add_query_arg( 'ver', $ver, $src ); |
|
409 } |
|
410 |
|
411 /** This filter is documented in wp-includes/class-wp-scripts.php */ |
|
412 $src = esc_url_raw( apply_filters( 'script_loader_src', $src, $handle ) ); |
|
413 |
|
414 if ( ! $src ) { |
|
415 return true; |
|
416 } |
|
417 |
|
418 $attr = array( |
|
419 'src' => $src, |
|
420 'id' => "{$handle}-js", |
|
421 ); |
|
422 if ( $strategy ) { |
|
423 $attr[ $strategy ] = true; |
|
424 } |
|
425 if ( $intended_strategy ) { |
|
426 $attr['data-wp-strategy'] = $intended_strategy; |
|
427 } |
|
428 $tag = $translations . $cond_before . $before_script; |
|
429 $tag .= wp_get_script_tag( $attr ); |
|
430 $tag .= $after_script . $cond_after; |
|
431 |
|
432 /** |
|
433 * Filters the HTML script tag of an enqueued script. |
|
434 * |
|
435 * @since 4.1.0 |
|
436 * |
|
437 * @param string $tag The `<script>` tag for the enqueued script. |
|
438 * @param string $handle The script's registered handle. |
|
439 * @param string $src The script's source URL. |
|
440 */ |
|
441 $tag = apply_filters( 'script_loader_tag', $tag, $handle, $src ); |
|
442 |
|
443 if ( $this->do_concat ) { |
|
444 $this->print_html .= $tag; |
|
445 } else { |
|
446 echo $tag; |
|
447 } |
|
448 |
|
449 return true; |
|
450 } |
|
451 |
|
452 /** |
|
453 * Adds extra code to a registered script. |
|
454 * |
|
455 * @since 4.5.0 |
|
456 * |
|
457 * @param string $handle Name of the script to add the inline script to. |
|
458 * Must be lowercase. |
|
459 * @param string $data String containing the JavaScript to be added. |
|
460 * @param string $position Optional. Whether to add the inline script |
|
461 * before the handle or after. Default 'after'. |
|
462 * @return bool True on success, false on failure. |
|
463 */ |
|
464 public function add_inline_script( $handle, $data, $position = 'after' ) { |
|
465 if ( ! $data ) { |
|
466 return false; |
|
467 } |
|
468 |
|
469 if ( 'after' !== $position ) { |
|
470 $position = 'before'; |
|
471 } |
|
472 |
|
473 $script = (array) $this->get_data( $handle, $position ); |
|
474 $script[] = $data; |
|
475 |
|
476 return $this->add_data( $handle, $position, $script ); |
|
477 } |
|
478 |
|
479 /** |
|
480 * Prints inline scripts registered for a specific handle. |
|
481 * |
|
482 * @since 4.5.0 |
|
483 * @deprecated 6.3.0 Use methods get_inline_script_tag() or get_inline_script_data() instead. |
|
484 * |
|
485 * @param string $handle Name of the script to print inline scripts for. |
|
486 * Must be lowercase. |
|
487 * @param string $position Optional. Whether to add the inline script |
|
488 * before the handle or after. Default 'after'. |
|
489 * @param bool $display Optional. Whether to print the script tag |
|
490 * instead of just returning the script data. Default true. |
|
491 * @return string|false Script data on success, false otherwise. |
|
492 */ |
|
493 public function print_inline_script( $handle, $position = 'after', $display = true ) { |
|
494 _deprecated_function( __METHOD__, '6.3.0', 'WP_Scripts::get_inline_script_data() or WP_Scripts::get_inline_script_tag()' ); |
|
495 |
|
496 $output = $this->get_inline_script_data( $handle, $position ); |
|
497 if ( empty( $output ) ) { |
|
498 return false; |
|
499 } |
|
500 |
|
501 if ( $display ) { |
|
502 echo $this->get_inline_script_tag( $handle, $position ); |
|
503 } |
|
504 return $output; |
|
505 } |
|
506 |
|
507 /** |
|
508 * Gets data for inline scripts registered for a specific handle. |
|
509 * |
|
510 * @since 6.3.0 |
|
511 * |
|
512 * @param string $handle Name of the script to get data for. |
|
513 * Must be lowercase. |
|
514 * @param string $position Optional. Whether to add the inline script |
|
515 * before the handle or after. Default 'after'. |
|
516 * @return string Inline script, which may be empty string. |
|
517 */ |
|
518 public function get_inline_script_data( $handle, $position = 'after' ) { |
|
519 $data = $this->get_data( $handle, $position ); |
|
520 if ( empty( $data ) || ! is_array( $data ) ) { |
|
521 return ''; |
|
522 } |
|
523 |
|
524 return trim( implode( "\n", $data ), "\n" ); |
|
525 } |
|
526 |
|
527 /** |
|
528 * Gets tags for inline scripts registered for a specific handle. |
|
529 * |
|
530 * @since 6.3.0 |
|
531 * |
|
532 * @param string $handle Name of the script to get associated inline script tag for. |
|
533 * Must be lowercase. |
|
534 * @param string $position Optional. Whether to get tag for inline |
|
535 * scripts in the before or after position. Default 'after'. |
|
536 * @return string Inline script, which may be empty string. |
|
537 */ |
|
538 public function get_inline_script_tag( $handle, $position = 'after' ) { |
|
539 $js = $this->get_inline_script_data( $handle, $position ); |
|
540 if ( empty( $js ) ) { |
|
541 return ''; |
|
542 } |
|
543 |
|
544 $id = "{$handle}-js-{$position}"; |
|
545 |
|
546 return wp_get_inline_script_tag( $js, compact( 'id' ) ); |
|
547 } |
|
548 |
|
549 /** |
|
550 * Localizes a script, only if the script has already been added. |
|
551 * |
|
552 * @since 2.1.0 |
|
553 * |
|
554 * @param string $handle Name of the script to attach data to. |
|
555 * @param string $object_name Name of the variable that will contain the data. |
|
556 * @param array $l10n Array of data to localize. |
|
557 * @return bool True on success, false on failure. |
|
558 */ |
|
559 public function localize( $handle, $object_name, $l10n ) { |
|
560 if ( 'jquery' === $handle ) { |
|
561 $handle = 'jquery-core'; |
|
562 } |
|
563 |
|
564 if ( is_array( $l10n ) && isset( $l10n['l10n_print_after'] ) ) { // back compat, preserve the code in 'l10n_print_after' if present. |
|
565 $after = $l10n['l10n_print_after']; |
|
566 unset( $l10n['l10n_print_after'] ); |
|
567 } |
|
568 |
|
569 if ( ! is_array( $l10n ) ) { |
|
570 _doing_it_wrong( |
|
571 __METHOD__, |
|
572 sprintf( |
|
573 /* translators: 1: $l10n, 2: wp_add_inline_script() */ |
|
574 __( 'The %1$s parameter must be an array. To pass arbitrary data to scripts, use the %2$s function instead.' ), |
|
575 '<code>$l10n</code>', |
|
576 '<code>wp_add_inline_script()</code>' |
|
577 ), |
|
578 '5.7.0' |
|
579 ); |
|
580 |
|
581 if ( false === $l10n ) { |
|
582 // This should really not be needed, but is necessary for backward compatibility. |
|
583 $l10n = array( $l10n ); |
|
584 } |
|
585 } |
|
586 |
|
587 if ( is_string( $l10n ) ) { |
|
588 $l10n = html_entity_decode( $l10n, ENT_QUOTES, 'UTF-8' ); |
|
589 } elseif ( is_array( $l10n ) ) { |
|
590 foreach ( $l10n as $key => $value ) { |
|
591 if ( ! is_scalar( $value ) ) { |
|
592 continue; |
|
593 } |
|
594 |
|
595 $l10n[ $key ] = html_entity_decode( (string) $value, ENT_QUOTES, 'UTF-8' ); |
|
596 } |
|
597 } |
|
598 |
|
599 $script = "var $object_name = " . wp_json_encode( $l10n ) . ';'; |
|
600 |
|
601 if ( ! empty( $after ) ) { |
|
602 $script .= "\n$after;"; |
|
603 } |
|
604 |
|
605 $data = $this->get_data( $handle, 'data' ); |
|
606 |
|
607 if ( ! empty( $data ) ) { |
|
608 $script = "$data\n$script"; |
|
609 } |
|
610 |
|
611 return $this->add_data( $handle, 'data', $script ); |
|
612 } |
|
613 |
|
614 /** |
|
615 * Sets handle group. |
|
616 * |
|
617 * @since 2.8.0 |
|
618 * |
|
619 * @see WP_Dependencies::set_group() |
|
620 * |
|
621 * @param string $handle Name of the item. Should be unique. |
|
622 * @param bool $recursion Internal flag that calling function was called recursively. |
|
623 * @param int|false $group Optional. Group level: level (int), no groups (false). |
|
624 * Default false. |
|
625 * @return bool Not already in the group or a lower group. |
|
626 */ |
|
627 public function set_group( $handle, $recursion, $group = false ) { |
|
628 if ( isset( $this->registered[ $handle ]->args ) && 1 === $this->registered[ $handle ]->args ) { |
|
629 $grp = 1; |
|
630 } else { |
|
631 $grp = (int) $this->get_data( $handle, 'group' ); |
|
632 } |
|
633 |
|
634 if ( false !== $group && $grp > $group ) { |
|
635 $grp = $group; |
|
636 } |
|
637 |
|
638 return parent::set_group( $handle, $recursion, $grp ); |
|
639 } |
|
640 |
|
641 /** |
|
642 * Sets a translation textdomain. |
|
643 * |
|
644 * @since 5.0.0 |
|
645 * @since 5.1.0 The `$domain` parameter was made optional. |
|
646 * |
|
647 * @param string $handle Name of the script to register a translation domain to. |
|
648 * @param string $domain Optional. Text domain. Default 'default'. |
|
649 * @param string $path Optional. The full file path to the directory containing translation files. |
|
650 * @return bool True if the text domain was registered, false if not. |
|
651 */ |
|
652 public function set_translations( $handle, $domain = 'default', $path = '' ) { |
|
653 if ( ! isset( $this->registered[ $handle ] ) ) { |
|
654 return false; |
|
655 } |
|
656 |
|
657 /** @var \_WP_Dependency $obj */ |
|
658 $obj = $this->registered[ $handle ]; |
|
659 |
|
660 if ( ! in_array( 'wp-i18n', $obj->deps, true ) ) { |
|
661 $obj->deps[] = 'wp-i18n'; |
|
662 } |
|
663 |
|
664 return $obj->set_translations( $domain, $path ); |
|
665 } |
|
666 |
|
667 /** |
|
668 * Prints translations set for a specific handle. |
|
669 * |
|
670 * @since 5.0.0 |
|
671 * |
|
672 * @param string $handle Name of the script to add the inline script to. |
|
673 * Must be lowercase. |
|
674 * @param bool $display Optional. Whether to print the script |
|
675 * instead of just returning it. Default true. |
|
676 * @return string|false Script on success, false otherwise. |
|
677 */ |
|
678 public function print_translations( $handle, $display = true ) { |
|
679 if ( ! isset( $this->registered[ $handle ] ) || empty( $this->registered[ $handle ]->textdomain ) ) { |
|
680 return false; |
|
681 } |
|
682 |
|
683 $domain = $this->registered[ $handle ]->textdomain; |
|
684 $path = ''; |
|
685 |
|
686 if ( isset( $this->registered[ $handle ]->translations_path ) ) { |
|
687 $path = $this->registered[ $handle ]->translations_path; |
|
688 } |
|
689 |
|
690 $json_translations = load_script_textdomain( $handle, $domain, $path ); |
|
691 |
|
692 if ( ! $json_translations ) { |
|
693 return false; |
|
694 } |
|
695 |
|
696 $output = <<<JS |
|
697 ( function( domain, translations ) { |
|
698 var localeData = translations.locale_data[ domain ] || translations.locale_data.messages; |
|
699 localeData[""].domain = domain; |
|
700 wp.i18n.setLocaleData( localeData, domain ); |
|
701 } )( "{$domain}", {$json_translations} ); |
|
702 JS; |
|
703 |
|
704 if ( $display ) { |
|
705 wp_print_inline_script_tag( $output, array( 'id' => "{$handle}-js-translations" ) ); |
|
706 } |
|
707 |
|
708 return $output; |
|
709 } |
|
710 |
|
711 /** |
|
712 * Determines script dependencies. |
|
713 * |
|
714 * @since 2.1.0 |
|
715 * |
|
716 * @see WP_Dependencies::all_deps() |
|
717 * |
|
718 * @param string|string[] $handles Item handle (string) or item handles (array of strings). |
|
719 * @param bool $recursion Optional. Internal flag that function is calling itself. |
|
720 * Default false. |
|
721 * @param int|false $group Optional. Group level: level (int), no groups (false). |
|
722 * Default false. |
|
723 * @return bool True on success, false on failure. |
|
724 */ |
|
725 public function all_deps( $handles, $recursion = false, $group = false ) { |
|
726 $r = parent::all_deps( $handles, $recursion, $group ); |
|
727 if ( ! $recursion ) { |
|
728 /** |
|
729 * Filters the list of script dependencies left to print. |
|
730 * |
|
731 * @since 2.3.0 |
|
732 * |
|
733 * @param string[] $to_do An array of script dependency handles. |
|
734 */ |
|
735 $this->to_do = apply_filters( 'print_scripts_array', $this->to_do ); |
|
736 } |
|
737 return $r; |
|
738 } |
|
739 |
|
740 /** |
|
741 * Processes items and dependencies for the head group. |
|
742 * |
|
743 * @since 2.8.0 |
|
744 * |
|
745 * @see WP_Dependencies::do_items() |
|
746 * |
|
747 * @return string[] Handles of items that have been processed. |
|
748 */ |
|
749 public function do_head_items() { |
|
750 $this->do_items( false, 0 ); |
|
751 return $this->done; |
|
752 } |
|
753 |
|
754 /** |
|
755 * Processes items and dependencies for the footer group. |
|
756 * |
|
757 * @since 2.8.0 |
|
758 * |
|
759 * @see WP_Dependencies::do_items() |
|
760 * |
|
761 * @return string[] Handles of items that have been processed. |
|
762 */ |
|
763 public function do_footer_items() { |
|
764 $this->do_items( false, 1 ); |
|
765 return $this->done; |
|
766 } |
|
767 |
|
768 /** |
|
769 * Whether a handle's source is in a default directory. |
|
770 * |
|
771 * @since 2.8.0 |
|
772 * |
|
773 * @param string $src The source of the enqueued script. |
|
774 * @return bool True if found, false if not. |
|
775 */ |
|
776 public function in_default_dir( $src ) { |
|
777 if ( ! $this->default_dirs ) { |
|
778 return true; |
|
779 } |
|
780 |
|
781 if ( str_starts_with( $src, '/' . WPINC . '/js/l10n' ) ) { |
|
782 return false; |
|
783 } |
|
784 |
|
785 foreach ( (array) $this->default_dirs as $test ) { |
|
786 if ( str_starts_with( $src, $test ) ) { |
|
787 return true; |
|
788 } |
|
789 } |
|
790 return false; |
|
791 } |
|
792 |
|
793 /** |
|
794 * This overrides the add_data method from WP_Dependencies, to support normalizing of $args. |
|
795 * |
|
796 * @since 6.3.0 |
|
797 * |
|
798 * @param string $handle Name of the item. Should be unique. |
|
799 * @param string $key The data key. |
|
800 * @param mixed $value The data value. |
|
801 * @return bool True on success, false on failure. |
|
802 */ |
|
803 public function add_data( $handle, $key, $value ) { |
|
804 if ( ! isset( $this->registered[ $handle ] ) ) { |
|
805 return false; |
|
806 } |
|
807 |
|
808 if ( 'strategy' === $key ) { |
|
809 if ( ! empty( $value ) && ! $this->is_delayed_strategy( $value ) ) { |
|
810 _doing_it_wrong( |
|
811 __METHOD__, |
|
812 sprintf( |
|
813 /* translators: 1: $strategy, 2: $handle */ |
|
814 __( 'Invalid strategy `%1$s` defined for `%2$s` during script registration.' ), |
|
815 $value, |
|
816 $handle |
|
817 ), |
|
818 '6.3.0' |
|
819 ); |
|
820 return false; |
|
821 } elseif ( ! $this->registered[ $handle ]->src && $this->is_delayed_strategy( $value ) ) { |
|
822 _doing_it_wrong( |
|
823 __METHOD__, |
|
824 sprintf( |
|
825 /* translators: 1: $strategy, 2: $handle */ |
|
826 __( 'Cannot supply a strategy `%1$s` for script `%2$s` because it is an alias (it lacks a `src` value).' ), |
|
827 $value, |
|
828 $handle |
|
829 ), |
|
830 '6.3.0' |
|
831 ); |
|
832 return false; |
|
833 } |
|
834 } |
|
835 return parent::add_data( $handle, $key, $value ); |
|
836 } |
|
837 |
|
838 /** |
|
839 * Gets all dependents of a script. |
|
840 * |
|
841 * @since 6.3.0 |
|
842 * |
|
843 * @param string $handle The script handle. |
|
844 * @return string[] Script handles. |
|
845 */ |
|
846 private function get_dependents( $handle ) { |
|
847 // Check if dependents map for the handle in question is present. If so, use it. |
|
848 if ( isset( $this->dependents_map[ $handle ] ) ) { |
|
849 return $this->dependents_map[ $handle ]; |
|
850 } |
|
851 |
|
852 $dependents = array(); |
|
853 |
|
854 // Iterate over all registered scripts, finding dependents of the script passed to this method. |
|
855 foreach ( $this->registered as $registered_handle => $args ) { |
|
856 if ( in_array( $handle, $args->deps, true ) ) { |
|
857 $dependents[] = $registered_handle; |
|
858 } |
|
859 } |
|
860 |
|
861 // Add the handles dependents to the map to ease future lookups. |
|
862 $this->dependents_map[ $handle ] = $dependents; |
|
863 |
|
864 return $dependents; |
|
865 } |
|
866 |
|
867 /** |
|
868 * Checks if the strategy passed is a valid delayed (non-blocking) strategy. |
|
869 * |
|
870 * @since 6.3.0 |
|
871 * |
|
872 * @param string $strategy The strategy to check. |
|
873 * @return bool True if $strategy is one of the delayed strategies, otherwise false. |
|
874 */ |
|
875 private function is_delayed_strategy( $strategy ) { |
|
876 return in_array( |
|
877 $strategy, |
|
878 $this->delayed_strategies, |
|
879 true |
|
880 ); |
|
881 } |
|
882 |
|
883 /** |
|
884 * Gets the best eligible loading strategy for a script. |
|
885 * |
|
886 * @since 6.3.0 |
|
887 * |
|
888 * @param string $handle The script handle. |
|
889 * @return string The best eligible loading strategy. |
|
890 */ |
|
891 private function get_eligible_loading_strategy( $handle ) { |
|
892 $intended = (string) $this->get_data( $handle, 'strategy' ); |
|
893 |
|
894 // Bail early if there is no intended strategy. |
|
895 if ( ! $intended ) { |
|
896 return ''; |
|
897 } |
|
898 |
|
899 /* |
|
900 * If the intended strategy is 'defer', limit the initial list of eligible |
|
901 * strategies, since 'async' can fallback to 'defer', but not vice-versa. |
|
902 */ |
|
903 $initial = ( 'defer' === $intended ) ? array( 'defer' ) : null; |
|
904 |
|
905 $eligible = $this->filter_eligible_strategies( $handle, $initial ); |
|
906 |
|
907 // Return early once we know the eligible strategy is blocking. |
|
908 if ( empty( $eligible ) ) { |
|
909 return ''; |
|
910 } |
|
911 |
|
912 return in_array( 'async', $eligible, true ) ? 'async' : 'defer'; |
|
913 } |
|
914 |
|
915 /** |
|
916 * Filter the list of eligible loading strategies for a script. |
|
917 * |
|
918 * @since 6.3.0 |
|
919 * |
|
920 * @param string $handle The script handle. |
|
921 * @param string[]|null $eligible Optional. The list of strategies to filter. Default null. |
|
922 * @param array<string, true> $checked Optional. An array of already checked script handles, used to avoid recursive loops. |
|
923 * @return string[] A list of eligible loading strategies that could be used. |
|
924 */ |
|
925 private function filter_eligible_strategies( $handle, $eligible = null, $checked = array() ) { |
|
926 // If no strategies are being passed, all strategies are eligible. |
|
927 if ( null === $eligible ) { |
|
928 $eligible = $this->delayed_strategies; |
|
929 } |
|
930 |
|
931 // If this handle was already checked, return early. |
|
932 if ( isset( $checked[ $handle ] ) ) { |
|
933 return $eligible; |
|
934 } |
|
935 |
|
936 // Mark this handle as checked. |
|
937 $checked[ $handle ] = true; |
|
938 |
|
939 // If this handle isn't registered, don't filter anything and return. |
|
940 if ( ! isset( $this->registered[ $handle ] ) ) { |
|
941 return $eligible; |
|
942 } |
|
943 |
|
944 // If the handle is not enqueued, don't filter anything and return. |
|
945 if ( ! $this->query( $handle, 'enqueued' ) ) { |
|
946 return $eligible; |
|
947 } |
|
948 |
|
949 $is_alias = (bool) ! $this->registered[ $handle ]->src; |
|
950 $intended_strategy = $this->get_data( $handle, 'strategy' ); |
|
951 |
|
952 // For non-alias handles, an empty intended strategy filters all strategies. |
|
953 if ( ! $is_alias && empty( $intended_strategy ) ) { |
|
954 return array(); |
|
955 } |
|
956 |
|
957 // Handles with inline scripts attached in the 'after' position cannot be delayed. |
|
958 if ( $this->has_inline_script( $handle, 'after' ) ) { |
|
959 return array(); |
|
960 } |
|
961 |
|
962 // If the intended strategy is 'defer', filter out 'async'. |
|
963 if ( 'defer' === $intended_strategy ) { |
|
964 $eligible = array( 'defer' ); |
|
965 } |
|
966 |
|
967 $dependents = $this->get_dependents( $handle ); |
|
968 |
|
969 // Recursively filter eligible strategies for dependents. |
|
970 foreach ( $dependents as $dependent ) { |
|
971 // Bail early once we know the eligible strategy is blocking. |
|
972 if ( empty( $eligible ) ) { |
|
973 return array(); |
|
974 } |
|
975 |
|
976 $eligible = $this->filter_eligible_strategies( $dependent, $eligible, $checked ); |
|
977 } |
|
978 |
|
979 return $eligible; |
|
980 } |
|
981 |
|
982 /** |
|
983 * Gets data for inline scripts registered for a specific handle. |
|
984 * |
|
985 * @since 6.3.0 |
|
986 * |
|
987 * @param string $handle Name of the script to get data for. Must be lowercase. |
|
988 * @param string $position The position of the inline script. |
|
989 * @return bool Whether the handle has an inline script (either before or after). |
|
990 */ |
|
991 private function has_inline_script( $handle, $position = null ) { |
|
992 if ( $position && in_array( $position, array( 'before', 'after' ), true ) ) { |
|
993 return (bool) $this->get_data( $handle, $position ); |
|
994 } |
|
995 |
|
996 return (bool) ( $this->get_data( $handle, 'before' ) || $this->get_data( $handle, 'after' ) ); |
|
997 } |
|
998 |
|
999 /** |
|
1000 * Resets class properties. |
|
1001 * |
|
1002 * @since 2.8.0 |
|
1003 */ |
|
1004 public function reset() { |
|
1005 $this->do_concat = false; |
|
1006 $this->print_code = ''; |
|
1007 $this->concat = ''; |
|
1008 $this->concat_version = ''; |
|
1009 $this->print_html = ''; |
|
1010 $this->ext_version = ''; |
|
1011 $this->ext_handles = ''; |
|
1012 } |
|
1013 } |