| @@ -462,12 +462,60 @@ | ||
| 462 | 462 | return $processor->get_updated_html(); |
| 463 | 463 | } |
| 464 | 464 | |
| 465 | 465 | /** |
| 466 | + * Updates `crossorigin` attributes in the printed media templates. | |
| 467 | + * | |
| 468 | + * Adds `crossorigin="anonymous"` to AUDIO and VIDEO tags inside the | |
| 469 | + * Backbone `<script type="text/html">` templates so the media modal can | |
| 470 | + * play cross-origin audio and video under cross-origin isolation. Tags | |
| 471 | + * that already have the attribute are left untouched so the output does | |
| 472 | + * not gain duplicates on WordPress versions where Core adds it itself. | |
| 473 | + * | |
| 474 | + * IMG is intentionally excluded: under | |
| 475 | + * `Document-Isolation-Policy: isolate-and-credentialless` the browser | |
| 476 | + * already loads cross-origin images in credentialless mode, so forcing | |
| 477 | + * `crossorigin="anonymous"` triggers a CORS request that breaks previews | |
| 478 | + * of images served without CORS headers, such as media offloaded to a | |
| 479 | + * CDN. See https://core.trac.wordpress.org/ticket/65673. | |
| 480 | + * | |
| 481 | + * @param string $html The printed media templates. | |
| 482 | + * | |
| 483 | + * @return string Modified media templates. | |
| 484 | + */ | |
| 485 | +function gutenberg_update_media_template_crossorigin_attributes( string $html ): string { | |
| 486 | + /* | |
| 487 | + * The media templates are inside <script type="text/html"> tags, | |
| 488 | + * whose content is treated as raw text by the HTML Tag Processor. | |
| 489 | + * Extract each script block's content, process it separately, | |
| 490 | + * then reassemble the full output. | |
| 491 | + */ | |
| 492 | + $script_processor = new WP_HTML_Tag_Processor( $html ); | |
| 493 | + while ( $script_processor->next_tag( 'SCRIPT' ) ) { | |
| 494 | + if ( 'text/html' !== $script_processor->get_attribute( 'type' ) ) { | |
| 495 | + continue; | |
| 496 | + } | |
| 497 | + $template_processor = new WP_HTML_Tag_Processor( $script_processor->get_modifiable_text() ); | |
| 498 | + while ( $template_processor->next_tag() ) { | |
| 499 | + if ( | |
| 500 | + in_array( $template_processor->get_tag(), array( 'AUDIO', 'VIDEO' ), true ) | |
| 501 | + && ! is_string( $template_processor->get_attribute( 'crossorigin' ) ) | |
| 502 | + ) { | |
| 503 | + $template_processor->set_attribute( 'crossorigin', 'anonymous' ); | |
| 504 | + } | |
| 505 | + } | |
| 506 | + $script_processor->set_modifiable_text( $template_processor->get_updated_html() ); | |
| 507 | + } | |
| 508 | + | |
| 509 | + return $script_processor->get_updated_html(); | |
| 510 | +} | |
| 511 | + | |
| 512 | +/** | |
| 466 | 513 | * Overrides templates from wp_print_media_templates with custom ones. |
| 467 | 514 | * |
| 468 | - * Adds `crossorigin` attribute to all tags that | |
| 469 | - * could have assets loaded from a different domain. | |
| 515 | + * Updates the `crossorigin` attributes on media tags so cross-origin | |
| 516 | + * audio and video can be processed under cross-origin isolation without | |
| 517 | + * breaking previews of images served without CORS headers. | |
| 470 | 518 | */ |
| 471 | 519 | function gutenberg_override_media_templates(): void { |
| 472 | 520 | remove_action( 'admin_footer', 'wp_print_media_templates' ); |
| 473 | 521 | add_action( |
| @@ -476,19 +524,9 @@ | ||
| 476 | 524 | ob_start(); |
| 477 | 525 | wp_print_media_templates(); |
| 478 | 526 | $html = (string) ob_get_clean(); |
| 479 | 527 | |
| 480 | - $tags = array( | |
| 481 | - 'audio', | |
| 482 | - 'img', | |
| 483 | - 'video', | |
| 484 | - ); | |
| 485 | - | |
| 486 | - foreach ( $tags as $tag ) { | |
| 487 | - $html = (string) str_replace( "<$tag", "<$tag crossorigin=\"anonymous\"", $html ); | |
| 488 | - } | |
| 489 | - | |
| 490 | - echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped | |
| 528 | + echo gutenberg_update_media_template_crossorigin_attributes( $html ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped | |
| 491 | 529 | } |
| 492 | 530 | ); |
| 493 | 531 | } |
| 494 | 532 | |