settings = $settings; } /** * Sanitizes a document. * * @since 1.1.0 * * @param Document $document Document instance. */ public function sanitize_document( Document $document ): void { $sanitizers = $this->get_sanitizers(); $result = AMP_Content_Sanitizer::sanitize_document( $document, $sanitizers, [] ); $this->ensure_required_markup( $document, $result['scripts'] ); } /** * Validation error callback. * * @since 1.1.0 * * @see AMP_Validation_Error_Taxonomy::get_validation_error_sanitization * * @param array{code: string} $error Error info, especially code. * @param array{node?: DOMElement|DOMNode} $data Additional data, including the node. * @return bool Whether the validation error should be sanitized. */ public function validation_error_callback( array $error, array $data = [] ): bool { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed /** * Filters whether the validation error should be sanitized. * * Returning true this indicates that the validation error is acceptable * and should not be considered a blocker to render AMP. Returning null * means that the default status should be used. * * Note that the $node is not passed here to ensure that the filter can be * applied on validation errors that have been stored. Likewise, the $sources * are also omitted because these are only available during an explicit * validation request and so they are not suitable for plugins to vary * sanitization by. * * @since 1.1.0 * * @see AMP_Validation_Manager::is_sanitization_auto_accepted() Which controls whether an error is initially accepted or rejected for sanitization. * * @param bool $sanitized Whether the validation error should be sanitized. * @param array $error Validation error being sanitized. */ return apply_filters( 'web_stories_amp_validation_error_sanitized', true, $error ); } /** * Adds missing scripts. * * @SuppressWarnings(PHPMD) * * @since 1.1.0 * * @link https://github.com/ampproject/amp-wp/blob/2.1.3/includes/class-amp-theme-support.php#L1381-L1594 * @see \AMP_Theme_Support::ensure_required_markup * * @param Document $document Document instance. * @param array $scripts List of found scripts. */ protected function ensure_required_markup( Document $document, array $scripts ): void { // phpcs:ignore SlevomatCodingStandard.Complexity.Cognitive.ComplexityTooHigh /** * Link elements. * * @var array{preconnect: \DOMElement[]|null,dns-prefetch: \DOMElement[]|null,preload: \DOMElement[]|null, prerender: \DOMElement[]|null, prefetch: \DOMElement[]|null } */ $links = [ Attribute::REL_PRECONNECT => [ // Include preconnect link for AMP CDN for browsers that don't support preload. AMP_DOM_Utils::create_node( $document, Tag::LINK, [ Attribute::REL => Attribute::REL_PRECONNECT, Attribute::HREF => 'https://cdn.ampproject.org', ] ), ], ]; // Obtain the existing AMP scripts. $amp_scripts = []; $ordered_scripts = []; $head_scripts = []; $runtime_src = 'https://cdn.ampproject.org/v0.js'; /** * Script element. * * @var DOMElement $script */ foreach ( $document->head->getElementsByTagName( Tag::SCRIPT ) as $script ) { $head_scripts[] = $script; } foreach ( $head_scripts as $script ) { $src = $script->getAttribute( Attribute::SRC ); if ( ! $src || ! str_starts_with( $src, 'https://cdn.ampproject.org/' ) ) { continue; } if ( 'v0.js' === substr( $src, - \strlen( 'v0.js' ) ) ) { $amp_scripts[ Amp::RUNTIME ] = $script; } elseif ( $script->hasAttribute( Attribute::CUSTOM_ELEMENT ) ) { $amp_scripts[ $script->getAttribute( Attribute::CUSTOM_ELEMENT ) ] = $script; } elseif ( $script->hasAttribute( Attribute::CUSTOM_TEMPLATE ) ) { $amp_scripts[ $script->getAttribute( Attribute::CUSTOM_TEMPLATE ) ] = $script; } // It will be added back further down. $document->head->removeChild( $script ); } $specs = $this->get_extension_sources(); // Create scripts for any components discovered from output buffering that are missing. foreach ( array_diff( array_keys( $scripts ), array_keys( $amp_scripts ) ) as $missing_script_handle ) { $attrs = [ Attribute::SRC => $specs[ $missing_script_handle ], Attribute::ASYNC => '', ]; if ( Extension::MUSTACHE === $missing_script_handle ) { $attrs[ Attribute::CUSTOM_TEMPLATE ] = (string) $missing_script_handle; } else { $attrs[ Attribute::CUSTOM_ELEMENT ] = (string) $missing_script_handle; } $amp_scripts[ $missing_script_handle ] = AMP_DOM_Utils::create_node( $document, Tag::SCRIPT, $attrs ); } // Remove scripts that had already been added but couldn't be detected from output buffering. $extension_specs = AMP_Allowed_Tags_Generated::get_extension_specs(); $superfluous_script_handles = array_diff( array_keys( $amp_scripts ), [ ...array_keys( $scripts ), Amp::RUNTIME ] ); foreach ( $superfluous_script_handles as $superfluous_script_handle ) { if ( ! empty( $extension_specs[ $superfluous_script_handle ]['requires_usage'] ) ) { unset( $amp_scripts[ $superfluous_script_handle ] ); } } /* phpcs:ignore Squiz.PHP.CommentedOutCode.Found * * "2. Next, preload the AMP runtime v0.js