+ * This header allows the specified source-origin to read the authorization response. The source-origin is
+ * the value specified and verified in the "__amp_source_origin" URL parameter (for example, "https://publisher1.com").
+ *
+ * Access-Control-Expose-Headers: AMP-Access-Control-Allow-Source-Origin
+ * This header simply allows the CORS response to contain the AMP-Access-Control-Allow-Source-Origin header.
+ *
+ * @link https://www.ampproject.org/docs/fundamentals/amp-cors-requests
+ * @since 1.0
+ */
+ public static function send_cors_headers() {
+ $origin = null;
+ $source_origin = null;
+ if ( isset( $_SERVER['HTTP_ORIGIN'] ) ) {
+ $origin = wp_validate_redirect( wp_sanitize_redirect( esc_url_raw( wp_unslash( $_SERVER['HTTP_ORIGIN'] ) ) ) );
+ }
+ if ( isset( self::$purged_amp_query_vars['__amp_source_origin'] ) ) {
+ $source_origin = wp_validate_redirect( wp_sanitize_redirect( esc_url_raw( self::$purged_amp_query_vars['__amp_source_origin'] ) ) );
+ }
+ if ( ! $origin ) {
+ $origin = $source_origin;
+ }
+
+ if ( $origin ) {
+ self::send_header( 'Access-Control-Allow-Origin', $origin, array( 'replace' => false ) );
+ self::send_header( 'Access-Control-Allow-Credentials', 'true' );
+ self::send_header( 'Vary', 'Origin', array( 'replace' => false ) );
+ }
+ if ( $source_origin ) {
+ self::send_header( 'AMP-Access-Control-Allow-Source-Origin', $source_origin );
+ self::send_header( 'Access-Control-Expose-Headers', 'AMP-Access-Control-Allow-Source-Origin', array( 'replace' => false ) );
+ }
+ }
+
+ /**
+ * Hook into a POST form submissions, such as the comment form or some other form submission.
+ *
+ * @since 0.7.0
+ * @since 1.0 Moved to AMP_HTTP class. Extracted some logic to send_cors_headers method.
+ */
+ public static function handle_xhr_request() {
+ $is_amp_xhr = (
+ ! empty( self::$purged_amp_query_vars['_wp_amp_action_xhr_converted'] )
+ &&
+ ( ! empty( $_SERVER['REQUEST_METHOD'] ) && 'POST' === $_SERVER['REQUEST_METHOD'] )
+ );
+ if ( ! $is_amp_xhr ) {
+ return;
+ }
+
+ // Intercept POST requests which redirect.
+ add_filter( 'wp_redirect', array( __CLASS__, 'intercept_post_request_redirect' ), PHP_INT_MAX );
+
+ // Add special handling for redirecting after comment submission.
+ add_filter( 'comment_post_redirect', array( __CLASS__, 'filter_comment_post_redirect' ), PHP_INT_MAX, 2 );
+
+ // Add die handler for AMP error display, most likely due to problem with comment.
+ add_filter( 'wp_die_handler', function () {
+ return array( __CLASS__, 'handle_wp_die' );
+ } );
+ }
+
+ /**
+ * Intercept the response to a POST request.
+ *
+ * @since 0.7.0
+ * @since 1.0 Moved to AMP_HTTP class.
+ * @see wp_redirect()
+ *
+ * @param string $location The location to redirect to.
+ */
+ public static function intercept_post_request_redirect( $location ) {
+
+ // Make sure relative redirects get made absolute.
+ $parsed_location = array_merge(
+ array(
+ 'scheme' => 'https',
+ 'host' => wp_parse_url( home_url(), PHP_URL_HOST ),
+ 'path' => isset( $_SERVER['REQUEST_URI'] ) ? strtok( wp_unslash( $_SERVER['REQUEST_URI'] ), '?' ) : '/',
+ ),
+ wp_parse_url( $location )
+ );
+
+ $absolute_location = '';
+ if ( 'https' === $parsed_location['scheme'] ) {
+ $absolute_location .= $parsed_location['scheme'] . ':';
+ }
+ $absolute_location .= '//' . $parsed_location['host'];
+ if ( isset( $parsed_location['port'] ) ) {
+ $absolute_location .= ':' . $parsed_location['port'];
+ }
+ $absolute_location .= $parsed_location['path'];
+ if ( isset( $parsed_location['query'] ) ) {
+ $absolute_location .= '?' . $parsed_location['query'];
+ }
+ if ( isset( $parsed_location['fragment'] ) ) {
+ $absolute_location .= '#' . $parsed_location['fragment'];
+ }
+
+ self::send_header( 'AMP-Redirect-To', $absolute_location );
+ self::send_header( 'Access-Control-Expose-Headers', 'AMP-Redirect-To', array( 'replace' => false ) );
+
+ wp_send_json_success();
+ }
+
+ /**
+ * New error handler for AMP form submission.
+ *
+ * @since 0.7.0
+ * @since 1.0 Moved to AMP_HTTP class.
+ * @see wp_die()
+ *
+ * @param WP_Error|string $error The error to handle.
+ * @param string|int $title Optional. Error title. If `$message` is a `WP_Error` object,
+ * error data with the key 'title' may be used to specify the title.
+ * If `$title` is an integer, then it is treated as the response
+ * code. Default empty.
+ * @param string|array|int $args {
+ * Optional. Arguments to control behavior. If `$args` is an integer, then it is treated
+ * as the response code. Default empty array.
+ *
+ * @type int $response The HTTP response code. Default 200 for Ajax requests, 500 otherwise.
+ * }
+ */
+ public static function handle_wp_die( $error, $title = '', $args = array() ) {
+ if ( is_int( $title ) ) {
+ $status_code = $title;
+ } elseif ( is_int( $args ) ) {
+ $status_code = $args;
+ } elseif ( is_array( $args ) && isset( $args['response'] ) ) {
+ $status_code = $args['response'];
+ } else {
+ $status_code = 500;
+ }
+ status_header( $status_code );
+
+ if ( is_wp_error( $error ) ) {
+ $error = $error->get_error_message();
+ }
+
+ // Message will be shown in template defined by AMP_Theme_Support::amend_comment_form().
+ wp_send_json( array(
+ 'error' => amp_wp_kses_mustache( $error ),
+ ) );
+ }
+
+ /**
+ * Handle comment_post_redirect to ensure page reload is done when comments_live_list is not supported, while sending back a success message when it is.
+ *
+ * @since 0.7.0
+ * @since 1.0 Moved to AMP_HTTP class.
+ *
+ * @param string $url Comment permalink to redirect to.
+ * @param WP_Comment $comment Posted comment.
+ *
+ * @return string|null URL if redirect to be done; otherwise function will exist.
+ */
+ public static function filter_comment_post_redirect( $url, $comment ) {
+ $theme_support = AMP_Theme_Support::get_theme_support_args();
+
+ // Cause a page refresh if amp-live-list is not implemented for comments via add_theme_support( 'amp', array( 'comments_live_list' => true ) ).
+ if ( empty( $theme_support['comments_live_list'] ) ) {
+ /*
+ * Add the comment ID to the URL to force AMP to refresh the page.
+ * This is ideally a temporary workaround to deal with https://github.com/ampproject/amphtml/issues/14170
+ */
+ $url = add_query_arg( 'comment', $comment->comment_ID, $url );
+
+ // Pass URL along to wp_redirect().
+ return $url;
+ }
+
+ // Create a success message to display to the user.
+ if ( '1' === (string) $comment->comment_approved ) {
+ $message = __( 'Your comment has been posted.', 'amp' );
+ } else {
+ $message = __( 'Your comment is awaiting moderation.', 'default' ); // Note core string re-use.
+ }
+
+ /**
+ * Filters the message when comment submitted success message when
+ *
+ * @since 0.7
+ */
+ $message = apply_filters( 'amp_comment_posted_message', $message, $comment );
+
+ // Message will be shown in template defined by AMP_Theme_Support::amend_comment_form().
+ wp_send_json( array(
+ 'message' => amp_wp_kses_mustache( $message ),
+ ) );
+
+ return null;
+ }
+}
diff --git a/includes/class-amp-response-headers.php b/includes/class-amp-response-headers.php
deleted file mode 100644
index 8066240a1b0..00000000000
--- a/includes/class-amp-response-headers.php
+++ /dev/null
@@ -1,90 +0,0 @@
- true,
- 'status_code' => null,
- ),
- $args
- );
-
- self::$headers_sent[] = array_merge( compact( 'name', 'value' ), $args );
- if ( headers_sent() ) {
- return false;
- }
-
- header(
- sprintf( '%s: %s', $name, $value ),
- $args['replace'],
- $args['status_code']
- );
- return true;
- }
-
- /**
- * Send Server-Timing header.
- *
- * If WP_DEBUG is not enabled and an admin user (who can manage_options) is not logged-in, the Server-Header will not be sent.
- *
- * @since 1.0
- *
- * @param string $name Name.
- * @param float $duration Duration. If negative, will be added to microtime( true ). Optional.
- * @param string $description Description. Optional.
- * @return bool Return value of send_header call. If WP_DEBUG is not enabled or admin user (who can manage_options) is not logged-in, this will always return false.
- */
- public static function send_server_timing( $name, $duration = null, $description = null ) {
- if ( ! WP_DEBUG && ! current_user_can( 'manage_options' ) ) {
- return false;
- }
- $value = $name;
- if ( isset( $description ) ) {
- $value .= sprintf( ';desc="%s"', str_replace( array( '\\', '"' ), '', substr( $description, 0, 100 ) ) );
- }
- if ( isset( $duration ) ) {
- if ( $duration < 0 ) {
- $duration = microtime( true ) + $duration;
- }
- $value .= sprintf( ';dur=%f', $duration * 1000 );
- }
- return self::send_header( 'Server-Timing', $value, array( 'replace' => false ) );
- }
-}
diff --git a/includes/class-amp-story-post-type.php b/includes/class-amp-story-post-type.php
index 3e5214075c6..9685ff5d933 100644
--- a/includes/class-amp-story-post-type.php
+++ b/includes/class-amp-story-post-type.php
@@ -126,7 +126,10 @@ public static function filter_kses_allowed_html( $allowed_tags ) {
// @todo This perhaps should not be allowed if user does not have capability.
foreach ( $allowed_tags as &$allowed_tag ) {
- $allowed_tag['grid-area'] = true;
+ $allowed_tag['grid-area'] = true;
+ $allowed_tag['animate-in'] = true;
+ $allowed_tag['animate-in-duration'] = true;
+ $allowed_tag['animate-in-delay'] = true;
}
return $allowed_tags;
diff --git a/includes/class-amp-theme-support.php b/includes/class-amp-theme-support.php
index 2cb96fd7023..5ff1e50f386 100644
--- a/includes/class-amp-theme-support.php
+++ b/includes/class-amp-theme-support.php
@@ -93,15 +93,6 @@ class AMP_Theme_Support {
'attachment',
);
- /**
- * AMP-specific query vars that were purged.
- *
- * @since 0.7
- * @see AMP_Theme_Support::purge_amp_query_vars()
- * @var string[]
- */
- public static $purged_amp_query_vars = array();
-
/**
* Start time when init was called.
*
@@ -139,9 +130,6 @@ public static function init() {
self::$init_start_time = microtime( true );
- self::purge_amp_query_vars();
- self::handle_xhr_request();
-
require_once AMP__DIR__ . '/includes/amp-post-template-actions.php';
add_action( 'widgets_init', array( __CLASS__, 'register_widgets' ) );
@@ -842,242 +830,6 @@ public static function add_hooks() {
// @todo Add character conversion.
}
- /**
- * Remove query vars that come in requests such as for amp-live-list.
- *
- * WordPress should generally not respond differently to requests when these parameters
- * are present. In some cases, when a query param such as __amp_source_origin is present
- * then it would normally get included into pagination links generated by get_pagenum_link().
- * The whitelist sanitizer empties out links that contain this string as it matches the
- * blacklisted_value_regex. So by preemptively scrubbing any reference to these query vars
- * we can ensure that WordPress won't end up referencing them in any way.
- *
- * @since 0.7
- */
- public static function purge_amp_query_vars() {
- $query_vars = array(
- '__amp_source_origin',
- '_wp_amp_action_xhr_converted',
- 'amp_latest_update_time',
- 'amp_last_check_time',
- );
-
- // Scrub input vars.
- foreach ( $query_vars as $query_var ) {
- if ( ! isset( $_GET[ $query_var ] ) ) { // phpcs:ignore
- continue;
- }
- self::$purged_amp_query_vars[ $query_var ] = wp_unslash( $_GET[ $query_var ] ); // phpcs:ignore
- unset( $_REQUEST[ $query_var ], $_GET[ $query_var ] );
- $scrubbed = true;
- }
-
- if ( isset( $scrubbed ) ) {
- $build_query = function( $query ) use ( $query_vars ) {
- $pattern = '/^(' . join( '|', $query_vars ) . ')(?==|$)/';
- $pairs = array();
- foreach ( explode( '&', $query ) as $pair ) {
- if ( ! preg_match( $pattern, $pair ) ) {
- $pairs[] = $pair;
- }
- }
- return join( '&', $pairs );
- };
-
- // Scrub QUERY_STRING.
- if ( ! empty( $_SERVER['QUERY_STRING'] ) ) {
- $_SERVER['QUERY_STRING'] = $build_query( $_SERVER['QUERY_STRING'] );
- }
-
- // Scrub REQUEST_URI.
- if ( ! empty( $_SERVER['REQUEST_URI'] ) ) {
- list( $path, $query ) = explode( '?', $_SERVER['REQUEST_URI'], 2 );
-
- $pairs = $build_query( $query );
- $_SERVER['REQUEST_URI'] = $path;
- if ( ! empty( $pairs ) ) {
- $_SERVER['REQUEST_URI'] .= "?{$pairs}";
- }
- }
- }
- }
-
- /**
- * Hook into a POST form submissions, such as the comment form or some other form submission.
- *
- * @since 0.7.0
- */
- public static function handle_xhr_request() {
- $is_amp_xhr = (
- ! empty( self::$purged_amp_query_vars['_wp_amp_action_xhr_converted'] )
- &&
- ! empty( self::$purged_amp_query_vars['__amp_source_origin'] )
- &&
- ( ! empty( $_SERVER['REQUEST_METHOD'] ) && 'POST' === $_SERVER['REQUEST_METHOD'] )
- );
- if ( ! $is_amp_xhr ) {
- return;
- }
-
- // Send AMP response header.
- $origin = wp_validate_redirect( wp_sanitize_redirect( esc_url_raw( self::$purged_amp_query_vars['__amp_source_origin'] ) ) );
- if ( $origin ) {
- AMP_Response_Headers::send_header( 'AMP-Access-Control-Allow-Source-Origin', $origin, array( 'replace' => true ) );
- }
-
- // Intercept POST requests which redirect.
- add_filter( 'wp_redirect', array( __CLASS__, 'intercept_post_request_redirect' ), PHP_INT_MAX );
-
- // Add special handling for redirecting after comment submission.
- add_filter( 'comment_post_redirect', array( __CLASS__, 'filter_comment_post_redirect' ), PHP_INT_MAX, 2 );
-
- // Add die handler for AMP error display, most likely due to problem with comment.
- add_filter( 'wp_die_handler', function() {
- return array( __CLASS__, 'handle_wp_die' );
- } );
-
- }
-
- /**
- * Strip tags that are not allowed in amp-mustache.
- *
- * @since 0.7.0
- *
- * @param string $text Text to sanitize.
- * @return string Sanitized text.
- */
- protected static function wp_kses_amp_mustache( $text ) {
- $amp_mustache_allowed_html_tags = array( 'strong', 'b', 'em', 'i', 'u', 's', 'small', 'mark', 'del', 'ins', 'sup', 'sub' );
- return wp_kses( $text, array_fill_keys( $amp_mustache_allowed_html_tags, array() ) );
- }
-
- /**
- * Handle comment_post_redirect to ensure page reload is done when comments_live_list is not supported, while sending back a success message when it is.
- *
- * @since 0.7.0
- *
- * @param string $url Comment permalink to redirect to.
- * @param WP_Comment $comment Posted comment.
- * @return string|null URL if redirect to be done; otherwise function will exist.
- */
- public static function filter_comment_post_redirect( $url, $comment ) {
- $theme_support = self::get_theme_support_args();
-
- // Cause a page refresh if amp-live-list is not implemented for comments via add_theme_support( 'amp', array( 'comments_live_list' => true ) ).
- if ( empty( $theme_support['comments_live_list'] ) ) {
- /*
- * Add the comment ID to the URL to force AMP to refresh the page.
- * This is ideally a temporary workaround to deal with https://github.com/ampproject/amphtml/issues/14170
- */
- $url = add_query_arg( 'comment', $comment->comment_ID, $url );
-
- // Pass URL along to wp_redirect().
- return $url;
- }
-
- // Create a success message to display to the user.
- if ( '1' === (string) $comment->comment_approved ) {
- $message = __( 'Your comment has been posted.', 'amp' );
- } else {
- $message = __( 'Your comment is awaiting moderation.', 'default' ); // Note core string re-use.
- }
-
- /**
- * Filters the message when comment submitted success message when
- *
- * @since 0.7
- */
- $message = apply_filters( 'amp_comment_posted_message', $message, $comment );
-
- // Message will be shown in template defined by AMP_Theme_Support::amend_comment_form().
- wp_send_json( array(
- 'message' => self::wp_kses_amp_mustache( $message ),
- ) );
- return null;
- }
-
- /**
- * New error handler for AMP form submission.
- *
- * @since 0.7.0
- * @see wp_die()
- *
- * @param WP_Error|string $error The error to handle.
- * @param string|int $title Optional. Error title. If `$message` is a `WP_Error` object,
- * error data with the key 'title' may be used to specify the title.
- * If `$title` is an integer, then it is treated as the response
- * code. Default empty.
- * @param string|array|int $args {
- * Optional. Arguments to control behavior. If `$args` is an integer, then it is treated
- * as the response code. Default empty array.
- *
- * @type int $response The HTTP response code. Default 200 for Ajax requests, 500 otherwise.
- * }
- */
- public static function handle_wp_die( $error, $title = '', $args = array() ) {
- if ( is_int( $title ) ) {
- $status_code = $title;
- } elseif ( is_int( $args ) ) {
- $status_code = $args;
- } elseif ( is_array( $args ) && isset( $args['response'] ) ) {
- $status_code = $args['response'];
- } else {
- $status_code = 500;
- }
- status_header( $status_code );
-
- if ( is_wp_error( $error ) ) {
- $error = $error->get_error_message();
- }
-
- // Message will be shown in template defined by AMP_Theme_Support::amend_comment_form().
- wp_send_json( array(
- 'error' => self::wp_kses_amp_mustache( $error ),
- ) );
- }
-
- /**
- * Intercept the response to a POST request.
- *
- * @since 0.7.0
- * @see wp_redirect()
- *
- * @param string $location The location to redirect to.
- */
- public static function intercept_post_request_redirect( $location ) {
-
- // Make sure relative redirects get made absolute.
- $parsed_location = array_merge(
- array(
- 'scheme' => 'https',
- 'host' => wp_parse_url( home_url(), PHP_URL_HOST ),
- 'path' => isset( $_SERVER['REQUEST_URI'] ) ? strtok( wp_unslash( $_SERVER['REQUEST_URI'] ), '?' ) : '/',
- ),
- wp_parse_url( $location )
- );
-
- $absolute_location = '';
- if ( 'https' === $parsed_location['scheme'] ) {
- $absolute_location .= $parsed_location['scheme'] . ':';
- }
- $absolute_location .= '//' . $parsed_location['host'];
- if ( isset( $parsed_location['port'] ) ) {
- $absolute_location .= ':' . $parsed_location['port'];
- }
- $absolute_location .= $parsed_location['path'];
- if ( isset( $parsed_location['query'] ) ) {
- $absolute_location .= '?' . $parsed_location['query'];
- }
- if ( isset( $parsed_location['fragment'] ) ) {
- $absolute_location .= '#' . $parsed_location['fragment'];
- }
-
- AMP_Response_Headers::send_header( 'AMP-Redirect-To', $absolute_location );
- AMP_Response_Headers::send_header( 'Access-Control-Expose-Headers', 'AMP-Redirect-To' );
-
- wp_send_json_success();
- }
-
/**
* Register/override widgets.
*
@@ -1853,7 +1605,7 @@ public static function prepare_response( $response, $args = array() ) {
};
}
- AMP_Response_Headers::send_server_timing( 'amp_output_buffer', -self::$init_start_time, 'AMP Output Buffer' );
+ AMP_HTTP::send_server_timing( 'amp_output_buffer', -self::$init_start_time, 'AMP Output Buffer' );
$dom_parse_start = microtime( true );
@@ -1903,7 +1655,7 @@ public static function prepare_response( $response, $args = array() ) {
$dom->documentElement->setAttribute( 'amp', '' );
}
- AMP_Response_Headers::send_server_timing( 'amp_dom_parse', -$dom_parse_start, 'AMP DOM Parse' );
+ AMP_HTTP::send_server_timing( 'amp_dom_parse', -$dom_parse_start, 'AMP DOM Parse' );
$assets = AMP_Content_Sanitizer::sanitize_document( $dom, self::$sanitizer_classes, $args );
@@ -1987,7 +1739,7 @@ public static function prepare_response( $response, $args = array() ) {
$response = "\n";
$response .= AMP_DOM_Utils::get_content_from_dom_node( $dom, $dom->documentElement );
- AMP_Response_Headers::send_server_timing( 'amp_dom_serialize', -$dom_serialize_start, 'AMP DOM Serialize' );
+ AMP_HTTP::send_server_timing( 'amp_dom_serialize', -$dom_serialize_start, 'AMP DOM Serialize' );
// Cache response if enabled.
if ( $cache_response ) {
diff --git a/includes/options/class-amp-options-menu.php b/includes/options/class-amp-options-menu.php
index 327cb9f17d8..854838c2af3 100644
--- a/includes/options/class-amp-options-menu.php
+++ b/includes/options/class-amp-options-menu.php
@@ -291,15 +291,33 @@ public function render_validation_handling() {
diff --git a/includes/sanitizers/class-amp-allowed-tags-generated.php b/includes/sanitizers/class-amp-allowed-tags-generated.php
index 93e1a868212..650da65f819 100644
--- a/includes/sanitizers/class-amp-allowed-tags-generated.php
+++ b/includes/sanitizers/class-amp-allowed-tags-generated.php
@@ -13,7 +13,7 @@
*/
class AMP_Allowed_Tags_Generated {
- private static $spec_file_revision = 712;
+ private static $spec_file_revision = 720;
private static $minimum_validator_revision_required = 348;
private static $allowed_tags = array(
@@ -1133,6 +1133,16 @@ class AMP_Allowed_Tags_Generated {
4,
),
),
+ 'reference_points' => array(
+ 'AMP-CAROUSEL lightbox [child]' => array(
+ 'mandatory' => false,
+ 'unique' => false,
+ ),
+ 'AMP-CAROUSEL lightbox [lightbox-exclude]' => array(
+ 'mandatory' => false,
+ 'unique' => false,
+ ),
+ ),
'requires_extension' => array(
'amp-carousel',
'amp-lightbox-gallery',
@@ -1284,6 +1294,7 @@ class AMP_Allowed_Tags_Generated {
),
'when-ended' => array(
'value_casei' => array(
+ 'continue',
'stop',
),
),
@@ -2340,6 +2351,33 @@ class AMP_Allowed_Tags_Generated {
),
),
),
+ 'amp-image-slider' => array(
+ array(
+ 'attr_spec_list' => array(
+ 'disable-hint-reappear' => array(),
+ 'media' => array(),
+ 'noloading' => array(
+ 'value' => array(
+ '',
+ ),
+ ),
+ ),
+ 'tag_spec' => array(
+ 'amp_layout' => array(
+ 'supported_layouts' => array(
+ 2,
+ 9,
+ 1,
+ 4,
+ ),
+ ),
+ 'requires_extension' => array(
+ 'amp-image-slider',
+ ),
+ 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-image-slider',
+ ),
+ ),
+ ),
'amp-img' => array(
array(
'attr_spec_list' => array(
@@ -2598,6 +2636,7 @@ class AMP_Allowed_Tags_Generated {
9,
1,
4,
+ 5,
),
),
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-layout',
@@ -2607,6 +2646,7 @@ class AMP_Allowed_Tags_Generated {
'amp-lightbox' => array(
array(
'attr_spec_list' => array(
+ '[open]' => array(),
'animate-in' => array(
'value_casei' => array(
'fade-in',
@@ -2724,6 +2764,20 @@ class AMP_Allowed_Tags_Generated {
3,
),
),
+ 'reference_points' => array(
+ 'AMP-LIVE-LIST [items]' => array(
+ 'mandatory' => true,
+ 'unique' => true,
+ ),
+ 'AMP-LIVE-LIST [pagination]' => array(
+ 'mandatory' => false,
+ 'unique' => true,
+ ),
+ 'AMP-LIVE-LIST [update]' => array(
+ 'mandatory' => true,
+ 'unique' => true,
+ ),
+ ),
'requires_extension' => array(
'amp-live-list',
),
@@ -2760,6 +2814,16 @@ class AMP_Allowed_Tags_Generated {
array(
'attr_spec_list' => array(),
'tag_spec' => array(
+ 'reference_points' => array(
+ 'AMP-NEXT-PAGE > [separator]' => array(
+ 'mandatory' => false,
+ 'unique' => true,
+ ),
+ 'amp-next-page extension .json configuration' => array(
+ 'mandatory' => true,
+ 'unique' => true,
+ ),
+ ),
'requires_extension' => array(
'amp-next-page',
),
@@ -2782,6 +2846,12 @@ class AMP_Allowed_Tags_Generated {
),
),
'tag_spec' => array(
+ 'reference_points' => array(
+ 'AMP-NEXT-PAGE > [separator]' => array(
+ 'mandatory' => false,
+ 'unique' => true,
+ ),
+ ),
'requires_extension' => array(
'amp-next-page',
),
@@ -2951,6 +3021,11 @@ class AMP_Allowed_Tags_Generated {
'amp-pan-zoom' => array(
array(
'attr_spec_list' => array(
+ 'disable-double-tap' => array(
+ 'value' => array(
+ '',
+ ),
+ ),
'initial-scale' => array(
'value_regex' => '[0-9]+(\\.[0-9]+)?',
),
@@ -3292,6 +3367,16 @@ class AMP_Allowed_Tags_Generated {
'disallowed_ancestor' => array(
'amp-selector',
),
+ 'reference_points' => array(
+ 'AMP-SELECTOR child' => array(
+ 'mandatory' => false,
+ 'unique' => false,
+ ),
+ 'AMP-SELECTOR option' => array(
+ 'mandatory' => false,
+ 'unique' => false,
+ ),
+ ),
'requires_extension' => array(
'amp-selector',
),
@@ -3661,6 +3746,12 @@ class AMP_Allowed_Tags_Generated {
'attr_spec_list' => array(),
'tag_spec' => array(
'mandatory_ancestor' => 'amp-story-page',
+ 'reference_points' => array(
+ 'AMP-STORY-CTA-LAYER animate-in' => array(
+ 'mandatory' => false,
+ 'unique' => false,
+ ),
+ ),
),
),
),
@@ -3679,6 +3770,16 @@ class AMP_Allowed_Tags_Generated {
),
'tag_spec' => array(
'mandatory_ancestor' => 'amp-story-page',
+ 'reference_points' => array(
+ 'AMP-STORY-GRID-LAYER animate-in' => array(
+ 'mandatory' => false,
+ 'unique' => false,
+ ),
+ 'AMP-STORY-GRID-LAYER default' => array(
+ 'mandatory' => false,
+ 'unique' => false,
+ ),
+ ),
),
),
),
@@ -4097,6 +4198,40 @@ class AMP_Allowed_Tags_Generated {
),
),
),
+ 'amp-viqeo-player' => array(
+ array(
+ 'attr_spec_list' => array(
+ 'autoplay' => array(),
+ 'data-profileid' => array(
+ 'mandatory' => true,
+ 'value_regex' => '[0-9a-f]*',
+ ),
+ 'data-videoid' => array(
+ 'mandatory' => true,
+ ),
+ 'media' => array(),
+ 'noloading' => array(
+ 'value' => array(
+ '',
+ ),
+ ),
+ ),
+ 'tag_spec' => array(
+ 'amp_layout' => array(
+ 'supported_layouts' => array(
+ 6,
+ 2,
+ 3,
+ 7,
+ 4,
+ ),
+ ),
+ 'requires_extension' => array(
+ 'amp-viqeo-player',
+ ),
+ ),
+ ),
+ ),
'amp-vk' => array(
array(
'attr_spec_list' => array(
@@ -4961,6 +5096,30 @@ class AMP_Allowed_Tags_Generated {
'spec_name' => 'FORM DIV [submit-error][template]',
),
),
+ array(
+ 'attr_spec_list' => array(
+ 'first' => array(
+ 'mandatory' => true,
+ ),
+ ),
+ 'tag_spec' => array(
+ 'mandatory_parent' => 'amp-image-slider',
+ 'spec_name' => 'AMP-IMAGE-SLIDER > DIV [first]',
+ 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-image-slider',
+ ),
+ ),
+ array(
+ 'attr_spec_list' => array(
+ 'second' => array(
+ 'mandatory' => true,
+ ),
+ ),
+ 'tag_spec' => array(
+ 'mandatory_parent' => 'amp-image-slider',
+ 'spec_name' => 'AMP-IMAGE-SLIDER > DIV [second]',
+ 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-image-slider',
+ ),
+ ),
),
'dl' => array(
array(
@@ -10082,6 +10241,31 @@ class AMP_Allowed_Tags_Generated {
),
),
),
+ array(
+ 'attr_spec_list' => array(
+ 'async' => array(
+ 'mandatory' => true,
+ 'value' => array(
+ '',
+ ),
+ ),
+ 'nonce' => array(),
+ 'type' => array(
+ 'value_casei' => array(
+ 'text/javascript',
+ ),
+ ),
+ ),
+ 'tag_spec' => array(
+ 'extension_spec' => array(
+ 'name' => 'amp-image-slider',
+ 'version' => array(
+ '0.1',
+ 'latest',
+ ),
+ ),
+ ),
+ ),
array(
'attr_spec_list' => array(
'async' => array(
@@ -11247,6 +11431,31 @@ class AMP_Allowed_Tags_Generated {
),
),
),
+ array(
+ 'attr_spec_list' => array(
+ 'async' => array(
+ 'mandatory' => true,
+ 'value' => array(
+ '',
+ ),
+ ),
+ 'nonce' => array(),
+ 'type' => array(
+ 'value_casei' => array(
+ 'text/javascript',
+ ),
+ ),
+ ),
+ 'tag_spec' => array(
+ 'extension_spec' => array(
+ 'name' => 'amp-viqeo-player',
+ 'version' => array(
+ '0.1',
+ 'latest',
+ ),
+ ),
+ ),
+ ),
array(
'attr_spec_list' => array(
'async' => array(
@@ -11916,6 +12125,9 @@ class AMP_Allowed_Tags_Generated {
'stroke-miterlimit' => array(),
'stroke-opacity' => array(),
'stroke-width' => array(),
+ 'style' => array(
+ 'blacklisted_value_regex' => '!important',
+ ),
'systemlanguage' => array(),
'text-anchor' => array(),
'text-decoration' => array(),
@@ -12230,6 +12442,16 @@ class AMP_Allowed_Tags_Generated {
),
'tag_spec' => array(
'mandatory_parent' => 'amp-story-auto-ads',
+ 'reference_points' => array(
+ 'AMP-STORY-GRID-LAYER animate-in' => array(
+ 'mandatory' => false,
+ 'unique' => false,
+ ),
+ 'AMP-STORY-GRID-LAYER default' => array(
+ 'mandatory' => false,
+ 'unique' => false,
+ ),
+ ),
'requires_extension' => array(
'amp-mustache',
),
@@ -13450,6 +13672,305 @@ class AMP_Allowed_Tags_Generated {
);
+ private static $reference_points = array(
+ 'AMP-CAROUSEL lightbox [child]' => array(
+ 'attr_spec_list' => array(
+ 'lightbox-thumbnail-id' => array(
+ 'value_regex_casei' => '^[a-z][a-z\\d_-]*',
+ ),
+ ),
+ 'tag_spec' => array(
+ 'spec_name' => 'AMP-CAROUSEL lightbox [child]',
+ ),
+ ),
+ 'AMP-CAROUSEL lightbox [lightbox-exclude]' => array(
+ 'attr_spec_list' => array(
+ 'lightbox-exclude' => array(
+ 'mandatory' => true,
+ ),
+ ),
+ 'tag_spec' => array(
+ 'spec_name' => 'AMP-CAROUSEL lightbox [lightbox-exclude]',
+ ),
+ ),
+ 'AMP-LIVE-LIST [items]' => array(
+ 'attr_spec_list' => array(
+ 'items' => array(
+ 'mandatory' => true,
+ ),
+ ),
+ 'tag_spec' => array(
+ 'reference_points' => array(
+ 'AMP-LIVE-LIST [items] item' => array(
+ 'mandatory' => false,
+ 'unique' => false,
+ ),
+ ),
+ 'spec_name' => 'AMP-LIVE-LIST [items]',
+ 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-live-list#items',
+ ),
+ ),
+ 'AMP-LIVE-LIST [items] item' => array(
+ 'attr_spec_list' => array(
+ 'data-sort-time' => array(
+ 'mandatory' => true,
+ ),
+ 'data-tombstone' => array(),
+ 'data-update-time' => array(),
+ 'id' => array(
+ 'mandatory' => true,
+ ),
+ ),
+ 'tag_spec' => array(
+ 'spec_name' => 'AMP-LIVE-LIST [items] item',
+ 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-live-list#items',
+ ),
+ ),
+ 'AMP-LIVE-LIST [pagination]' => array(
+ 'attr_spec_list' => array(
+ 'pagination' => array(
+ 'mandatory' => true,
+ ),
+ ),
+ 'tag_spec' => array(
+ 'spec_name' => 'AMP-LIVE-LIST [pagination]',
+ 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-live-list#pagination',
+ ),
+ ),
+ 'AMP-LIVE-LIST [update]' => array(
+ 'attr_spec_list' => array(
+ 'update' => array(
+ 'mandatory' => true,
+ ),
+ ),
+ 'tag_spec' => array(
+ 'spec_name' => 'AMP-LIVE-LIST [update]',
+ 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-live-list#update',
+ ),
+ ),
+ 'AMP-NEXT-PAGE > [separator]' => array(
+ 'attr_spec_list' => array(
+ 'separator' => array(
+ 'mandatory' => true,
+ ),
+ ),
+ 'tag_spec' => array(
+ 'mandatory_parent' => 'amp-next-page',
+ 'spec_name' => 'AMP-NEXT-PAGE > [separator]',
+ ),
+ ),
+ 'AMP-SELECTOR child' => array(
+ 'attr_spec_list' => array(),
+ 'tag_spec' => array(
+ 'reference_points' => array(
+ 'AMP-SELECTOR child' => array(
+ 'mandatory' => false,
+ 'unique' => false,
+ ),
+ 'AMP-SELECTOR option' => array(
+ 'mandatory' => false,
+ 'unique' => false,
+ ),
+ ),
+ 'spec_name' => 'AMP-SELECTOR child',
+ ),
+ ),
+ 'AMP-SELECTOR option' => array(
+ 'attr_spec_list' => array(
+ 'disabled' => array(
+ 'value' => array(
+ '',
+ ),
+ ),
+ 'option' => array(
+ 'mandatory' => true,
+ ),
+ 'selected' => array(
+ 'value' => array(
+ '',
+ ),
+ ),
+ ),
+ 'tag_spec' => array(
+ 'spec_name' => 'AMP-SELECTOR option',
+ 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-selector',
+ ),
+ ),
+ 'AMP-STORY-CTA-LAYER animate-in' => array(
+ 'attr_spec_list' => array(
+ 'animate-in' => array(
+ 'value' => array(
+ 'drop',
+ 'fade-in',
+ 'fly-in-bottom',
+ 'fly-in-left',
+ 'fly-in-right',
+ 'fly-in-top',
+ 'pan-down',
+ 'pan-left',
+ 'pan-right',
+ 'pan-up',
+ 'pulse',
+ 'rotate-in-left',
+ 'rotate-in-right',
+ 'twirl-in',
+ 'whoosh-in-left',
+ 'whoosh-in-right',
+ 'zoom-in',
+ 'zoom-out',
+ ),
+ ),
+ 'animate-in-after' => array(),
+ 'animate-in-delay' => array(),
+ 'animate-in-duration' => array(),
+ ),
+ 'tag_spec' => array(
+ 'reference_points' => array(
+ 'AMP-STORY-CTA-LAYER animate-in' => array(
+ 'mandatory' => false,
+ 'unique' => false,
+ ),
+ ),
+ 'spec_name' => 'AMP-STORY-CTA-LAYER animate-in',
+ 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-story',
+ ),
+ ),
+ 'AMP-STORY-GRID-LAYER animate-in' => array(
+ 'attr_spec_list' => array(
+ 'animate-in' => array(
+ 'value' => array(
+ 'drop',
+ 'fade-in',
+ 'fly-in-bottom',
+ 'fly-in-left',
+ 'fly-in-right',
+ 'fly-in-top',
+ 'pan-down',
+ 'pan-left',
+ 'pan-right',
+ 'pan-up',
+ 'pulse',
+ 'rotate-in-left',
+ 'rotate-in-right',
+ 'twirl-in',
+ 'whoosh-in-left',
+ 'whoosh-in-right',
+ 'zoom-in',
+ 'zoom-out',
+ ),
+ ),
+ 'animate-in-after' => array(),
+ 'animate-in-delay' => array(),
+ 'animate-in-duration' => array(),
+ ),
+ 'tag_spec' => array(
+ 'reference_points' => array(
+ 'AMP-STORY-GRID-LAYER animate-in' => array(
+ 'mandatory' => false,
+ 'unique' => false,
+ ),
+ ),
+ 'spec_name' => 'AMP-STORY-GRID-LAYER animate-in',
+ 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-story',
+ ),
+ ),
+ 'AMP-STORY-GRID-LAYER default' => array(
+ 'attr_spec_list' => array(
+ 'align-content' => array(
+ 'value' => array(
+ 'center',
+ 'end',
+ 'space-around',
+ 'space-between',
+ 'space-evenly',
+ 'start',
+ 'stretch',
+ ),
+ ),
+ 'align-items' => array(
+ 'value' => array(
+ 'center',
+ 'end',
+ 'start',
+ 'stretch',
+ ),
+ ),
+ 'align-self' => array(
+ 'value' => array(
+ 'center',
+ 'end',
+ 'start',
+ 'stretch',
+ ),
+ ),
+ 'animate-in' => array(
+ 'value' => array(
+ 'drop',
+ 'fade-in',
+ 'fly-in-bottom',
+ 'fly-in-left',
+ 'fly-in-right',
+ 'fly-in-top',
+ 'pan-down',
+ 'pan-left',
+ 'pan-right',
+ 'pan-up',
+ 'pulse',
+ 'rotate-in-left',
+ 'rotate-in-right',
+ 'twirl-in',
+ 'whoosh-in-left',
+ 'whoosh-in-right',
+ 'zoom-in',
+ 'zoom-out',
+ ),
+ ),
+ 'animate-in-after' => array(),
+ 'animate-in-delay' => array(),
+ 'animate-in-duration' => array(),
+ 'grid-area' => array(),
+ 'justify-content' => array(
+ 'value' => array(
+ 'center',
+ 'end',
+ 'space-around',
+ 'space-between',
+ 'space-evenly',
+ 'start',
+ 'stretch',
+ ),
+ ),
+ 'justify-items' => array(
+ 'value' => array(
+ 'center',
+ 'end',
+ 'start',
+ 'stretch',
+ ),
+ ),
+ 'justify-self' => array(
+ 'value' => array(
+ 'center',
+ 'end',
+ 'start',
+ 'stretch',
+ ),
+ ),
+ ),
+ 'tag_spec' => array(
+ 'reference_points' => array(
+ 'AMP-STORY-GRID-LAYER animate-in' => array(
+ 'mandatory' => false,
+ 'unique' => false,
+ ),
+ ),
+ 'spec_name' => 'AMP-STORY-GRID-LAYER default',
+ 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-story',
+ ),
+ ),
+ );
+
+
/**
* Get allowed tags.
*
@@ -13476,6 +13997,20 @@ public static function get_allowed_tag( $node_name ) {
return null;
}
+ /**
+ * Get reference point spec.
+ *
+ * @since 1.0
+ * @param string $tag_spec_name Tag spec name.
+ * @return array|null Reference point spec, or null if does not exist.
+ */
+ public static function get_reference_point_spec( $tag_spec_name ) {
+ if ( isset( self::$reference_points[ $tag_spec_name ] ) ) {
+ return self::$reference_points[ $tag_spec_name ];
+ }
+ return null;
+ }
+
/**
* Get list of globally-allowed attributes.
*
diff --git a/includes/sanitizers/class-amp-rule-spec.php b/includes/sanitizers/class-amp-rule-spec.php
index b3b61181f21..a09fb94eb5b 100644
--- a/includes/sanitizers/class-amp-rule-spec.php
+++ b/includes/sanitizers/class-amp-rule-spec.php
@@ -70,39 +70,6 @@ abstract class AMP_Rule_Spec {
9 => 'intrinsic',
);
- /**
- * If a node type listed here is invalid, it and it's subtree will be
- * removed if it is invalid. This is mainly because any children will be
- * non-functional without this parent.
- *
- * If a tag is not listed here, it will be replaced by its children if it
- * is invalid.
- *
- * @todo There are other nodes that should probably be listed here as well.
- *
- * @var array
- */
- public static $node_types_to_remove_if_invalid = array(
- 'form',
- 'input',
- 'link',
- 'meta',
- 'style',
- // Include 'script' here?
- );
-
- /**
- * It is mentioned in the documentation in several places that data-*
- * is generally allowed, but there is no specific rule for it in the
- * protoascii file, so we include it here.
- *
- * @var array
- */
- public static $whitelisted_attr_regex = array(
- '@^data-[a-zA-Z][\\w:.-]*$@uis',
- '(update|item|pagination|option|selected|disabled)', // Allowed for live reference points.
- );
-
/**
* List of boolean attributes.
*
diff --git a/includes/sanitizers/class-amp-style-sanitizer.php b/includes/sanitizers/class-amp-style-sanitizer.php
index 050c24c69e1..4cadd3b017a 100644
--- a/includes/sanitizers/class-amp-style-sanitizer.php
+++ b/includes/sanitizers/class-amp-style-sanitizer.php
@@ -463,7 +463,7 @@ public function sanitize() {
$this->did_convert_elements = true;
if ( $this->parse_css_duration > 0.0 ) {
- AMP_Response_Headers::send_server_timing( 'amp_parse_css', $this->parse_css_duration, 'AMP Parse CSS' );
+ AMP_HTTP::send_server_timing( 'amp_parse_css', $this->parse_css_duration, 'AMP Parse CSS' );
}
}
diff --git a/includes/sanitizers/class-amp-tag-and-attribute-sanitizer.php b/includes/sanitizers/class-amp-tag-and-attribute-sanitizer.php
index b52e7dfcfb9..ec300c31675 100644
--- a/includes/sanitizers/class-amp-tag-and-attribute-sanitizer.php
+++ b/includes/sanitizers/class-amp-tag-and-attribute-sanitizer.php
@@ -240,7 +240,7 @@ private function process_alternate_names( $attr_spec_list ) {
}
/**
- * Sanitize the