diff --git a/includes/amp-helper-functions.php b/includes/amp-helper-functions.php index b5dbd116ee4..d5f53c694f4 100644 --- a/includes/amp-helper-functions.php +++ b/includes/amp-helper-functions.php @@ -361,8 +361,23 @@ function amp_get_asset_url( $file ) { * @return string Boilerplate code. */ function amp_get_boilerplate_code() { - return '' - . ''; + $stylesheets = amp_get_boilerplate_stylesheets(); + return sprintf( '', $stylesheets[0], $stylesheets[1] ); +} + +/** + * Get AMP boilerplate stylesheets. + * + * @since 1.3 + * @link https://www.ampproject.org/docs/reference/spec#boilerplate + * + * @return string[] Stylesheets, where first is contained in style[amp-boilerplate] and the second in noscript>style[amp-boilerplate]. + */ +function amp_get_boilerplate_stylesheets() { + return [ + 'body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}', + 'body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}', + ]; } /** diff --git a/includes/class-amp-story-post-type.php b/includes/class-amp-story-post-type.php index 5f8ba10dc2b..79b499ea4ad 100644 --- a/includes/class-amp-story-post-type.php +++ b/includes/class-amp-story-post-type.php @@ -197,6 +197,30 @@ public static function register() { add_action( 'wp_enqueue_scripts', [ __CLASS__, 'add_custom_stories_styles' ] ); + add_action( + 'amp_story_head', + function() { + // Theme support for title-tag is implied for stories. See _wp_render_title_tag(). + echo '' . esc_html( wp_get_document_title() ) . '' . "\n"; + }, + 1 + ); + add_action( 'amp_story_head', 'wp_enqueue_scripts', 1 ); + add_action( + 'amp_story_head', + function() { + /* + * Same as wp_print_styles() but importantly omitting the wp_print_styles action, which themes/plugins + * can use to output arbitrary styling. Styling is constrained in story template via the + * \AMP_Story_Post_Type::filter_frontend_print_styles_array() method. + */ + wp_styles()->do_items(); + }, + 8 + ); + add_action( 'amp_story_head', 'rel_canonical' ); + add_action( 'amp_story_head', 'amp_add_generator_metadata' ); + // Remove unnecessary settings. add_filter( 'block_editor_settings', [ __CLASS__, 'filter_block_editor_settings' ], 10, 2 ); diff --git a/includes/class-amp-theme-support.php b/includes/class-amp-theme-support.php index e02cf242fbf..799a6ec4354 100644 --- a/includes/class-amp-theme-support.php +++ b/includes/class-amp-theme-support.php @@ -1016,34 +1016,6 @@ static function( $html ) { 1 ); - /* - * "AMP HTML documents MUST contain the AMP boilerplate code (head > style[amp-boilerplate] and noscript > style[amp-boilerplate]) - * in their head tag." {@link https://www.ampproject.org/docs/fundamentals/spec#required-markup AMP Required markup} - * - * After "Specify the tag for your favicon.", then - * "Specify any custom styles by using the '; - }, - 0 - ); - add_action( - 'wp_head', - static function() { - echo amp_get_boilerplate_code(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - }, - PHP_INT_MAX - ); - add_action( 'admin_bar_init', [ __CLASS__, 'init_admin_bar' ] ); add_action( 'wp_head', 'amp_add_generator_metadata', 20 ); add_action( 'wp_enqueue_scripts', [ __CLASS__, 'enqueue_assets' ], 0 ); // Enqueue before theme's styles. @@ -1434,8 +1406,9 @@ static function( $body_classes ) { * * @since 0.7 * @link https://www.ampproject.org/docs/reference/spec#required-markup - * @link https://docs.google.com/document/d/169XUxtSSEJb16NfkrCr9y5lqhUR7vxXEAsNxBzg07fM/edit#heading=h.2ha259c3ffos + * @link https://amp.dev/documentation/guides-and-tutorials/optimize-and-measure/optimize_amp/ * @todo All of this might be better placed inside of a sanitizer. + * @todo Consider removing any scripts that are not among the $script_handles. * * @param DOMDocument $dom Document. * @param string[] $script_handles AMP script handles for components identified during output buffering. @@ -1447,6 +1420,8 @@ public static function ensure_required_markup( DOMDocument $dom, $script_handles * @var DOMElement $meta * @var DOMElement $script * @var DOMElement $link + * @var DOMElement $style + * @var DOMElement $noscript */ $xpath = new DOMXPath( $dom ); @@ -1496,9 +1471,9 @@ public static function ensure_required_markup( DOMDocument $dom, $script_handles * there are a few basic optimizations that you can apply. The key is to structure the section * in a way so that all render-blocking scripts and custom fonts load as fast as possible." * - * "The first tag should be the meta charset tag, followed by any remaining meta tags." + * "1. The first tag should be the meta charset tag, followed by any remaining meta tags." * - * {@link https://docs.google.com/document/d/169XUxtSSEJb16NfkrCr9y5lqhUR7vxXEAsNxBzg07fM/edit#heading=h.2ha259c3ffos Optimize the AMP Runtime loading} + * {@link https://amp.dev/documentation/guides-and-tutorials/optimize-and-measure/optimize_amp/ Optimize the AMP Runtime loading} */ $meta_charset = null; $meta_viewport = null; @@ -1606,10 +1581,10 @@ public static function ensure_required_markup( DOMDocument $dom, $script_handles /* phpcs:ignore Squiz.PHP.CommentedOutCode.Found * - * "Next, preload the AMP runtime v0.js - assertStringEndsWith( '/assets/foo.jpg', amp_get_asset_url( 'foo.jpg' ) ); + } + + /** + * Test amp_get_boilerplate_code. + * + * @covers ::amp_get_boilerplate_code() + */ + public function test_amp_get_boilerplate_code() { + $boilerplate_code = amp_get_boilerplate_code(); + $this->assertStringStartsWith( '#s', - '##s', '', - '