diff --git a/assets/src/admin/paired-browsing/app.js b/assets/src/admin/paired-browsing/app.js index db2bbfec6a0..a034de4eb27 100644 --- a/assets/src/admin/paired-browsing/app.js +++ b/assets/src/admin/paired-browsing/app.js @@ -8,7 +8,7 @@ import { addQueryArgs, hasQueryArg, removeQueryArgs } from '@wordpress/url'; import './app.css'; const { app, history } = window; -const { ampSlug, ampPairedBrowsingQueryVar, ampValidationErrorsQueryVar, documentTitlePrefix } = app; +const { ampSlug, ampRuntimeScriptSrc, ampPairedBrowsingQueryVar, ampValidationErrorsQueryVar, documentTitlePrefix } = app; class PairedBrowsingApp { /** @@ -119,7 +119,7 @@ class PairedBrowsingApp { * @return {boolean} True if AMP compatible, false if not. */ documentIsAmp( doc ) { - return doc.querySelector( 'head > script[src="https://cdn.ampproject.org/v0.js"]' ); + return doc.querySelector( `head > script[src="${ampRuntimeScriptSrc}"]` ); } /** diff --git a/includes/amp-helper-functions.php b/includes/amp-helper-functions.php index 1697e50c1c7..26dde75a457 100644 --- a/includes/amp-helper-functions.php +++ b/includes/amp-helper-functions.php @@ -421,11 +421,26 @@ function amp_register_default_scripts( $wp_scripts ) { } } + /** + * Filters whether to use the LTS release channel. + * + * @since 1.5 + * + * @param bool $use_lts Whether to use the LTS release channel. Defaults to false (so the stable channel is used). + */ + $lts_release_channel = apply_filters( 'amp_lts_release_channel', false ); + + if ( $lts_release_channel ) { + $base_url = 'https://cdn.ampproject.org/lts'; + } else { + $base_url = 'https://cdn.ampproject.org'; + } + // AMP Runtime. $handle = 'amp-runtime'; $wp_scripts->add( $handle, - 'https://cdn.ampproject.org/v0.js', + $base_url . '/v0.js', [], null ); @@ -433,7 +448,8 @@ function amp_register_default_scripts( $wp_scripts ) { $handle, 'amp_script_attributes', [ - 'async' => true, + 'async' => true, + 'crossorigin' => 'anonymous', ] ); @@ -441,7 +457,7 @@ function amp_register_default_scripts( $wp_scripts ) { $handle = 'amp-shadow'; $wp_scripts->add( $handle, - 'https://cdn.ampproject.org/shadow-v0.js', + $base_url . '/shadow-v0.js', [], null ); @@ -449,14 +465,16 @@ function amp_register_default_scripts( $wp_scripts ) { $handle, 'amp_script_attributes', [ - 'async' => true, + 'async' => true, + 'crossorigin' => 'anonymous', ] ); // Register all AMP components as defined in the spec. foreach ( AMP_Allowed_Tags_Generated::get_extension_specs() as $extension_name => $extension_spec ) { $src = sprintf( - 'https://cdn.ampproject.org/v0/%s-%s.js', + '%s/v0/%s-%s.js', + $base_url, $extension_name, end( $extension_spec['version'] ) ); @@ -537,9 +555,11 @@ function amp_filter_script_loader_tag( $tag, $handle ) { /* * All scripts from AMP CDN should be loaded async. * See . + * For crossorigin=anonymous, see . */ $attributes = [ - 'async' => true, + 'async' => true, + 'crossorigin' => 'anonymous', ]; // Add custom-template and custom-element attributes. All component scripts look like https://cdn.ampproject.org/v0/:name-:version.js. diff --git a/includes/class-amp-theme-support.php b/includes/class-amp-theme-support.php index 4572bf6c19b..671157b86c5 100644 --- a/includes/class-amp-theme-support.php +++ b/includes/class-amp-theme-support.php @@ -1626,8 +1626,9 @@ public static function ensure_required_markup( Document $dom, $script_handles = $dom, Tag::LINK, [ - Attribute::REL => Attribute::REL_PRECONNECT, - Attribute::HREF => 'https://cdn.ampproject.org', + Attribute::REL => Attribute::REL_PRECONNECT, + Attribute::HREF => 'https://cdn.ampproject.org', + Attribute::CROSSORIGIN => Attribute::CROSSORIGIN_ANONYMOUS, ] ), ], @@ -1696,8 +1697,9 @@ public static function ensure_required_markup( Document $dom, $script_handles = continue; } $attrs = [ - Attribute::SRC => wp_scripts()->registered[ $missing_script_handle ]->src, - Attribute::ASYNC => '', + Attribute::SRC => wp_scripts()->registered[ $missing_script_handle ]->src, + Attribute::ASYNC => '', + Attribute::CROSSORIGIN => Attribute::CROSSORIGIN_ANONYMOUS, ]; if ( Extension::MUSTACHE === $missing_script_handle ) { $attrs[ Attribute::CUSTOM_TEMPLATE ] = $missing_script_handle; @@ -1736,9 +1738,10 @@ public static function ensure_required_markup( Document $dom, $script_handles = $dom, Tag::LINK, [ - Attribute::REL => Attribute::REL_PRELOAD, - 'as' => Tag::SCRIPT, - Attribute::HREF => $runtime_src, + Attribute::REL => Attribute::REL_PRELOAD, + 'as' => Tag::SCRIPT, + Attribute::HREF => $runtime_src, + Attribute::CROSSORIGIN => Attribute::CROSSORIGIN_ANONYMOUS, ] ); @@ -1755,9 +1758,10 @@ public static function ensure_required_markup( Document $dom, $script_handles = $dom, Tag::LINK, [ - Attribute::REL => Attribute::REL_PRELOAD, - 'as' => Tag::SCRIPT, - Attribute::HREF => $amp_scripts[ $script_handle ]->getAttribute( Attribute::SRC ), + Attribute::REL => Attribute::REL_PRELOAD, + 'as' => Tag::SCRIPT, + Attribute::HREF => $amp_scripts[ $script_handle ]->getAttribute( Attribute::SRC ), + Attribute::CROSSORIGIN => Attribute::CROSSORIGIN_ANONYMOUS, ] ); } @@ -1791,6 +1795,7 @@ public static function ensure_required_markup( Document $dom, $script_handles = $script = $dom->createElement( Tag::SCRIPT ); $script->setAttribute( Attribute::ASYNC, '' ); $script->setAttribute( Attribute::SRC, $runtime_src ); + $script->setAttribute( Attribute::CROSSORIGIN, Attribute::CROSSORIGIN_ANONYMOUS ); $ordered_scripts[ Amp::RUNTIME ] = $script; } @@ -2382,6 +2387,7 @@ public static function serve_paired_browsing_experience( $template ) { 'ampPairedBrowsingQueryVar' => self::PAIRED_BROWSING_QUERY_VAR, 'ampValidationErrorsQueryVar' => AMP_Validation_Manager::VALIDATION_ERRORS_QUERY_VAR, 'documentTitlePrefix' => __( 'AMP Paired Browsing:', 'amp' ), + 'ampRuntimeScriptSrc' => wp_scripts()->registered['amp-runtime']->src, ] ); diff --git a/includes/sanitizers/class-amp-style-sanitizer.php b/includes/sanitizers/class-amp-style-sanitizer.php index 963fe95242c..a241200424c 100644 --- a/includes/sanitizers/class-amp-style-sanitizer.php +++ b/includes/sanitizers/class-amp-style-sanitizer.php @@ -1304,7 +1304,7 @@ private function process_link_element( DOMElement $element ) { [ 'rel' => 'preconnect', 'href' => 'https://fonts.gstatic.com/', - 'crossorigin' => '', + 'crossorigin' => 'anonymous', ] ); $this->dom->head->insertBefore( $link ); // Note that \AMP_Theme_Support::ensure_required_markup() will put this in the optimal order. diff --git a/lib/common/src/Attribute.php b/lib/common/src/Attribute.php index 8321e408596..dde85a59121 100644 --- a/lib/common/src/Attribute.php +++ b/lib/common/src/Attribute.php @@ -32,6 +32,7 @@ interface Attribute const CHARSET = 'charset'; const CLASS_ = 'class'; // Underscore needed because 'class' is a PHP keyword. const CONTENT = 'content'; + const CROSSORIGIN = 'crossorigin'; const CUSTOM_ELEMENT = 'custom-element'; const CUSTOM_TEMPLATE = 'custom-template'; const HEIGHT = 'height'; @@ -71,4 +72,6 @@ interface Attribute const REL_PRELOAD = 'preload'; const REL_PRERENDER = 'prerender'; const REL_STYLESHEET = 'stylesheet'; + + const CROSSORIGIN_ANONYMOUS = 'anonymous'; } diff --git a/tests/php/test-amp-helper-functions.php b/tests/php/test-amp-helper-functions.php index c0156cdb482..9408475bd35 100644 --- a/tests/php/test-amp-helper-functions.php +++ b/tests/php/test-amp-helper-functions.php @@ -723,9 +723,9 @@ public function test_script_registering() { $output = get_echo( 'wp_print_scripts' ); - $this->assertContains( '', $output ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript - $this->assertContains( '', $output ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript - $this->assertContains( '', $output ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript + $this->assertContains( '', $output ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript + $this->assertContains( '', $output ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript + $this->assertContains( '', $output ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript // Try rendering via amp_render_scripts() instead of amp_render_scripts(), which is how component scripts get added normally. $output = amp_render_scripts( @@ -736,13 +736,13 @@ public function test_script_registering() { ] ); $this->assertNotContains( 'amp-mathml', $output, 'The amp-mathml component was already printed above.' ); - $this->assertContains( '', $output ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript - $this->assertContains( '', $output ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript + $this->assertContains( '', $output ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript + $this->assertContains( '', $output ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript // Try some experimental component to ensure expected script attributes are added. wp_register_script( 'amp-foo', 'https://cdn.ampproject.org/v0/amp-foo-0.1.js', [ 'amp-runtime' ], null ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NotInFooter, WordPress.WP.EnqueuedResourceParameters.MissingVersion $output = get_echo( 'wp_print_scripts', [ 'amp-foo' ] ); - $this->assertContains( '', $output ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript + $this->assertContains( '', $output ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript } /** diff --git a/tests/php/test-class-amp-theme-support.php b/tests/php/test-class-amp-theme-support.php index 43843a7b178..f20b2f6df2d 100644 --- a/tests/php/test-class-amp-theme-support.php +++ b/tests/php/test-class-amp-theme-support.php @@ -625,7 +625,7 @@ public function test_validate_non_amp_theme() { $this->assertContains( '', $sanitized_html ); // MathML script was added. - $this->assertContains( '', $sanitized_html ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript + $this->assertContains( '', $sanitized_html ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript } /** @@ -1981,21 +1981,21 @@ static function ( $url ) { '', '', - '', + '', + '', '', - '', - '', - '', - '', + '', + '', + '', + '', '', - '', + '', - '#\s*#s', - '##s', - '', - '', + '#\s*#s', + '##s', + '', + '', '', '',