AMP for WordPress - Version 1.1.2

Version Description

Download this release

Release Info

Developer westonruter
Plugin Icon 128x128 AMP for WordPress
Version 1.1.2
Comparing to
See all releases

Code changes from version 1.1.1 to 1.1.2

amp.php CHANGED
@@ -5,7 +5,7 @@
5
  * Plugin URI: https://amp-wp.org
6
  * Author: AMP Project Contributors
7
  * Author URI: https://github.com/ampproject/amp-wp/graphs/contributors
8
- * Version: 1.1.1
9
  * Text Domain: amp
10
  * Domain Path: /languages/
11
  * License: GPLv2 or later
@@ -14,108 +14,193 @@
14
  */
15
 
16
  /**
17
- * Print admin notice regarding having an old version of PHP.
18
  *
19
- * @since 0.7
 
 
20
  */
21
- function _amp_print_php_version_admin_notice() {
22
- ?>
23
- <div class="notice notice-error">
24
- <p>
25
- <?php
26
- printf(
27
- /* translators: %s: required PHP version */
28
- esc_html__( 'The AMP plugin requires PHP %s. Please contact your host to update your PHP version.', 'amp' ),
29
- '5.4+'
30
- );
31
- ?>
32
- </p>
33
- </div>
34
- <?php
35
- }
36
  if ( version_compare( phpversion(), '5.4', '<' ) ) {
37
- add_action( 'admin_notices', '_amp_print_php_version_admin_notice' );
38
- return;
 
 
 
 
 
 
39
  }
40
 
41
- /**
42
- * Print admin notice regarding DOM extension is not installed.
43
- *
44
- * @since 1.0
45
- */
46
- function _amp_print_php_dom_document_notice() {
47
- ?>
48
- <div class="notice notice-error">
49
- <p>
50
- <?php
51
- printf(
52
- /* translators: %s: PHP extension name */
53
- esc_html__( 'The AMP plugin requires the %s extension in PHP. Please contact your host to install this extension.', 'amp' ),
54
- 'DOM'
55
- );
56
- ?>
57
- </p>
58
- </div>
59
- <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  }
61
- if ( ! class_exists( 'DOMDocument' ) ) {
62
- add_action( 'admin_notices', '_amp_print_php_dom_document_notice' );
63
- return;
 
 
 
 
 
 
 
 
 
 
 
64
  }
65
-
66
- /**
67
- * Print admin notice regarding DOM extension is not installed.
68
- *
69
- * @since 1.0.1
70
- */
71
- function _amp_print_php_missing_iconv_notice() {
72
- ?>
73
- <div class="notice notice-error">
74
- <p>
75
- <?php
76
- printf(
77
- /* translators: %s: PHP extension name */
78
- esc_html__( 'The AMP plugin requires the %s extension in PHP. Please contact your host to install this extension.', 'amp' ),
79
- 'iconv'
80
- );
81
- ?>
82
- </p>
83
- </div>
84
- <?php
85
  }
86
- if ( ! function_exists( 'iconv' ) ) {
87
- add_action( 'admin_notices', '_amp_print_php_missing_iconv_notice' );
88
- return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  }
90
 
91
  /**
92
- * Print admin notice when composer install has not been performed.
93
  *
94
- * @since 1.0
 
95
  */
96
- function _amp_print_build_needed_notice() {
 
97
  ?>
98
  <div class="notice notice-error">
99
  <p>
100
- <?php
101
- printf(
102
- /* translators: %s: composer install && npm install && npm run build */
103
- __( 'You appear to be running the AMP plugin from source. Please do %s to finish installation.', 'amp' ), // phpcs:ignore WordPress.Security.EscapeOutput
104
- '<code>composer install && npm install && npm run build</code>'
105
- );
106
- ?>
 
 
 
107
  </p>
108
  </div>
109
  <?php
110
  }
111
- if ( ! file_exists( __DIR__ . '/vendor/autoload.php' ) || ! file_exists( __DIR__ . '/vendor/sabberworm/php-css-parser' ) || ! file_exists( __DIR__ . '/assets/js/amp-block-editor-toggle-compiled.js' ) ) {
112
- add_action( 'admin_notices', '_amp_print_build_needed_notice' );
 
 
 
 
 
 
 
 
 
 
 
113
  return;
114
  }
115
 
116
  define( 'AMP__FILE__', __FILE__ );
117
  define( 'AMP__DIR__', dirname( __FILE__ ) );
118
- define( 'AMP__VERSION', '1.1.1' );
119
 
120
  /**
121
  * Print admin notice if plugin installed with incorrect slug (which impacts WordPress's auto-update system).
@@ -262,6 +347,7 @@ function amp_init() {
262
  add_action( 'wp_loaded', 'amp_add_options_menu' );
263
  add_action( 'wp_loaded', 'amp_admin_pointer' );
264
  add_action( 'parse_query', 'amp_correct_query_when_is_front_page' );
 
265
 
266
  // Redirect the old url of amp page to the updated url.
267
  add_filter( 'old_slug_redirect_url', 'amp_redirect_old_slug_to_new_url' );
5
  * Plugin URI: https://amp-wp.org
6
  * Author: AMP Project Contributors
7
  * Author URI: https://github.com/ampproject/amp-wp/graphs/contributors
8
+ * Version: 1.1.2
9
  * Text Domain: amp
10
  * Domain Path: /languages/
11
  * License: GPLv2 or later
14
  */
15
 
16
  /**
17
+ * Errors encountered while loading the plugin.
18
  *
19
+ * This has to be a global for the same of PHP 5.2.
20
+ *
21
+ * @var \WP_Error $_amp_load_errors
22
  */
23
+ global $_amp_load_errors;
24
+
25
+ $_amp_load_errors = new \WP_Error();
26
+
 
 
 
 
 
 
 
 
 
 
 
27
  if ( version_compare( phpversion(), '5.4', '<' ) ) {
28
+ $_amp_load_errors->add(
29
+ 'insufficient_php_version',
30
+ sprintf(
31
+ /* translators: %s: required PHP version */
32
+ __( 'The AMP plugin requires PHP %s. Please contact your host to update your PHP version.', 'amp' ),
33
+ '5.4+'
34
+ )
35
+ );
36
  }
37
 
38
+ // See composer.json for this list.
39
+ $_amp_required_extensions = array(
40
+ // Required by FasterImage.
41
+ 'curl' => array(
42
+ 'functions' => array(
43
+ 'curl_error',
44
+ 'curl_init',
45
+ 'curl_multi_add_handle',
46
+ 'curl_multi_exec',
47
+ 'curl_multi_init',
48
+ 'curl_setopt',
49
+ ),
50
+ ),
51
+ 'dom' => array(
52
+ 'classes' => array(
53
+ 'DOMAttr',
54
+ 'DOMComment',
55
+ 'DOMDocument',
56
+ 'DOMElement',
57
+ 'DOMNode',
58
+ 'DOMNodeList',
59
+ 'DOMXPath',
60
+ ),
61
+ ),
62
+ // Required by PHP-CSS-Parser.
63
+ 'iconv' => array(
64
+ 'functions' => array( 'iconv' ),
65
+ ),
66
+ 'libxml' => array(
67
+ 'functions' => array( 'libxml_use_internal_errors' ),
68
+ ),
69
+ 'spl' => array(
70
+ 'functions' => array( 'spl_autoload_register' ),
71
+ ),
72
+ );
73
+ $_amp_missing_extensions = array();
74
+ $_amp_missing_classes = array();
75
+ $_amp_missing_functions = array();
76
+ foreach ( $_amp_required_extensions as $_amp_required_extension => $_amp_required_constructs ) {
77
+ if ( ! extension_loaded( $_amp_required_extension ) ) {
78
+ $_amp_missing_extensions[] = "<code>$_amp_required_extension</code>";
79
+ } else {
80
+ foreach ( $_amp_required_constructs as $_amp_construct_type => $_amp_constructs ) {
81
+ switch ( $_amp_construct_type ) {
82
+ case 'functions':
83
+ foreach ( $_amp_constructs as $_amp_construct ) {
84
+ if ( ! function_exists( $_amp_construct ) ) {
85
+ $_amp_missing_functions[] = "<code>$_amp_construct</code>";
86
+ }
87
+ }
88
+ break;
89
+ case 'classes':
90
+ foreach ( $_amp_constructs as $_amp_construct ) {
91
+ if ( ! class_exists( $_amp_construct ) ) {
92
+ $_amp_missing_classes[] = "<code>$_amp_construct</code>";
93
+ }
94
+ }
95
+ break;
96
+ }
97
+ }
98
+ unset( $_amp_construct_type, $_amp_constructs );
99
+ }
100
  }
101
+ if ( count( $_amp_missing_extensions ) > 0 ) {
102
+ $_amp_load_errors->add(
103
+ 'missing_extension',
104
+ sprintf(
105
+ /* translators: %s is list of missing extensions */
106
+ _n(
107
+ 'The following PHP extension is missing: %s. Please contact your host to finish installation.',
108
+ 'The following PHP extensions are missing: %s. Please contact your host to finish installation.',
109
+ count( $_amp_missing_extensions ),
110
+ 'amp'
111
+ ),
112
+ implode( ', ', $_amp_missing_extensions )
113
+ )
114
+ );
115
  }
116
+ if ( count( $_amp_missing_classes ) > 0 ) {
117
+ $_amp_load_errors->add(
118
+ 'missing_class',
119
+ sprintf(
120
+ /* translators: %s is list of missing extensions */
121
+ _n(
122
+ 'The following PHP class is missing: %s. Please contact your host to finish installation.',
123
+ 'The following PHP classes are missing: %s. Please contact your host to finish installation.',
124
+ count( $_amp_missing_classes ),
125
+ 'amp'
126
+ ),
127
+ implode( ', ', $_amp_missing_classes )
128
+ )
129
+ );
 
 
 
 
 
 
130
  }
131
+ if ( count( $_amp_missing_functions ) > 0 ) {
132
+ $_amp_load_errors->add(
133
+ 'missing_class',
134
+ sprintf(
135
+ /* translators: %s is list of missing extensions */
136
+ _n(
137
+ 'The following PHP function is missing: %s. Please contact your host to finish installation.',
138
+ 'The following PHP functions are missing: %s. Please contact your host to finish installation.',
139
+ count( $_amp_missing_functions ),
140
+ 'amp'
141
+ ),
142
+ implode( ', ', $_amp_missing_functions )
143
+ )
144
+ );
145
+ }
146
+
147
+ unset( $_amp_required_extensions, $_amp_missing_extensions, $_amp_required_constructs, $_amp_missing_classes, $_amp_missing_functions, $_amp_required_extension, $_amp_construct_type, $_amp_construct, $_amp_constructs );
148
+
149
+ if ( ! file_exists( __DIR__ . '/vendor/autoload.php' ) || ! file_exists( __DIR__ . '/vendor/sabberworm/php-css-parser' ) || ! file_exists( __DIR__ . '/assets/js/amp-block-editor-toggle-compiled.js' ) ) {
150
+ $_amp_load_errors->add(
151
+ 'build_required',
152
+ sprintf(
153
+ /* translators: %s: composer install && npm install && npm run build */
154
+ __( 'You appear to be running the AMP plugin from source. Please do %s to finish installation.', 'amp' ), // phpcs:ignore WordPress.Security.EscapeOutput
155
+ '<code>composer install && npm install && npm run build</code>'
156
+ )
157
+ );
158
  }
159
 
160
  /**
161
+ * Displays an admin notice about why the plugin is unable to load.
162
  *
163
+ * @since 1.1.2
164
+ * @global \WP_Error $_amp_load_errors
165
  */
166
+ function _amp_show_load_errors_admin_notice() {
167
+ global $_amp_load_errors;
168
  ?>
169
  <div class="notice notice-error">
170
  <p>
171
+ <strong><?php esc_html_e( 'AMP plugin unable to initialize.', 'amp' ); ?></strong>
172
+ <ul>
173
+ <?php foreach ( array_keys( $_amp_load_errors->errors ) as $error_code ) : ?>
174
+ <?php foreach ( $_amp_load_errors->get_error_messages( $error_code ) as $message ) : ?>
175
+ <li>
176
+ <?php echo wp_kses_post( $message ); ?>
177
+ </li>
178
+ <?php endforeach; ?>
179
+ <?php endforeach; ?>
180
+ </ul>
181
  </p>
182
  </div>
183
  <?php
184
  }
185
+
186
+ // Abort if dependencies are not satisfied.
187
+ if ( ! empty( $_amp_load_errors->errors ) ) {
188
+ add_action( 'admin_notices', '_amp_show_load_errors_admin_notice' );
189
+ if ( defined( 'WP_CLI' ) && WP_CLI ) {
190
+ $messages = array( __( 'AMP plugin unable to initialize.', 'amp' ) );
191
+ foreach ( array_keys( $_amp_load_errors->errors ) as $error_code ) {
192
+ $messages = array_merge( $messages, $_amp_load_errors->get_error_messages( $error_code ) );
193
+ }
194
+ $message = implode( "\n * ", $messages );
195
+ $message = str_replace( array( '<code>', '</code>' ), '`', $message );
196
+ WP_CLI::warning( $message );
197
+ }
198
  return;
199
  }
200
 
201
  define( 'AMP__FILE__', __FILE__ );
202
  define( 'AMP__DIR__', dirname( __FILE__ ) );
203
+ define( 'AMP__VERSION', '1.1.2' );
204
 
205
  /**
206
  * Print admin notice if plugin installed with incorrect slug (which impacts WordPress's auto-update system).
347
  add_action( 'wp_loaded', 'amp_add_options_menu' );
348
  add_action( 'wp_loaded', 'amp_admin_pointer' );
349
  add_action( 'parse_query', 'amp_correct_query_when_is_front_page' );
350
+ add_action( 'admin_bar_menu', 'amp_add_admin_bar_view_link', 100 );
351
 
352
  // Redirect the old url of amp page to the updated url.
353
  add_filter( 'old_slug_redirect_url', 'amp_redirect_old_slug_to_new_url' );
assets/js/amp-editor-blocks.js CHANGED
@@ -64,6 +64,7 @@ var ampEditorBlocks = ( function() { // eslint-disable-line no-unused-vars
64
  value: 'intrinsic',
65
  label: __( 'Intrinsic', 'amp' ),
66
  notAvailable: [
 
67
  'core-embed/youtube',
68
  'core-embed/facebook',
69
  'core-embed/instagram',
64
  value: 'intrinsic',
65
  label: __( 'Intrinsic', 'amp' ),
66
  notAvailable: [
67
+ 'core/video',
68
  'core-embed/youtube',
69
  'core-embed/facebook',
70
  'core-embed/instagram',
includes/amp-helper-functions.php CHANGED
@@ -1067,3 +1067,61 @@ function amp_wp_kses_mustache( $markup ) {
1067
  $amp_mustache_allowed_html_tags = array( 'strong', 'b', 'em', 'i', 'u', 's', 'small', 'mark', 'del', 'ins', 'sup', 'sub' );
1068
  return wp_kses( $markup, array_fill_keys( $amp_mustache_allowed_html_tags, array() ) );
1069
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1067
  $amp_mustache_allowed_html_tags = array( 'strong', 'b', 'em', 'i', 'u', 's', 'small', 'mark', 'del', 'ins', 'sup', 'sub' );
1068
  return wp_kses( $markup, array_fill_keys( $amp_mustache_allowed_html_tags, array() ) );
1069
  }
1070
+
1071
+ /**
1072
+ * Add "View AMP" admin bar item for Transitional/Reader mode.
1073
+ *
1074
+ * Note that when theme support is present (in Native/Transitional modes), the admin bar item will be further amended by
1075
+ * the `AMP_Validation_Manager::add_admin_bar_menu_items()` method.
1076
+ *
1077
+ * @see \AMP_Validation_Manager::add_admin_bar_menu_items()
1078
+ *
1079
+ * @param WP_Admin_Bar $wp_admin_bar Admin bar.
1080
+ */
1081
+ function amp_add_admin_bar_view_link( $wp_admin_bar ) {
1082
+ if ( is_admin() || amp_is_canonical() ) {
1083
+ return;
1084
+ }
1085
+
1086
+ if ( current_theme_supports( 'amp' ) ) {
1087
+ $available = AMP_Theme_Support::get_template_availability()['supported'];
1088
+ } elseif ( is_singular() ) {
1089
+ $post = get_queried_object();
1090
+ $available = ( $post instanceof WP_Post ) && post_supports_amp( $post );
1091
+ } else {
1092
+ $available = false;
1093
+ }
1094
+ if ( ! $available ) {
1095
+ // @todo Add note that AMP is not available?
1096
+ return;
1097
+ }
1098
+
1099
+ // Show nothing if there are rejected validation errors for this URL.
1100
+ if ( ! is_amp_endpoint() && count( AMP_Validated_URL_Post_Type::get_invalid_url_validation_errors( amp_get_current_url(), array( 'ignore_accepted' => true ) ) ) > 0 ) {
1101
+ return;
1102
+ }
1103
+
1104
+ if ( is_amp_endpoint() ) {
1105
+ $href = amp_remove_endpoint( amp_get_current_url() );
1106
+ } else {
1107
+ if ( is_singular() ) {
1108
+ $href = amp_get_permalink( get_queried_object_id() ); // For sake of Reader mode.
1109
+ } else {
1110
+ $href = add_query_arg( amp_get_slug(), '', amp_get_current_url() );
1111
+ }
1112
+ }
1113
+
1114
+ $icon = '&#x1F517;'; // LINK SYMBOL.
1115
+
1116
+ $parent = array(
1117
+ 'id' => 'amp',
1118
+ 'title' => sprintf(
1119
+ '<span id="amp-admin-bar-item-status-icon">%s</span> %s',
1120
+ $icon,
1121
+ esc_html( is_amp_endpoint() ? __( 'Non-AMP', 'amp' ) : __( 'AMP', 'amp' ) )
1122
+ ),
1123
+ 'href' => esc_url( $href ),
1124
+ );
1125
+
1126
+ $wp_admin_bar->add_menu( $parent );
1127
+ }
includes/class-amp-http.php CHANGED
@@ -20,6 +20,21 @@ class AMP_HTTP {
20
  */
21
  public static $headers_sent = array();
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  /**
24
  * AMP-specific query vars that were purged.
25
  *
@@ -83,7 +98,7 @@ class AMP_HTTP {
83
  * @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.
84
  */
85
  public static function send_server_timing( $name, $duration = null, $description = null ) {
86
- if ( ! WP_DEBUG && ! current_user_can( 'manage_options' ) ) {
87
  return false;
88
  }
89
  $value = $name;
20
  */
21
  public static $headers_sent = array();
22
 
23
+ /**
24
+ * Whether Server-Timing headers are sent.
25
+ *
26
+ * By default this is false to prevent breaking some web servers with an unexpected number of response headers. To
27
+ * enable in `WP_DEBUG` mode, consider the following plugin code:
28
+ *
29
+ * add_action( 'amp_init', function () {
30
+ * AMP_HTTP::$server_timing = ( ( defined( 'WP_DEBUG' ) && WP_DEBUG ) || current_user_can( 'manage_options' ) );
31
+ * } );
32
+ *
33
+ * @link https://gist.github.com/westonruter/053f8f47c21df51f1a081fc41b47f547
34
+ * @var bool
35
+ */
36
+ public static $server_timing = false;
37
+
38
  /**
39
  * AMP-specific query vars that were purged.
40
  *
98
  * @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.
99
  */
100
  public static function send_server_timing( $name, $duration = null, $description = null ) {
101
+ if ( ! self::$server_timing ) {
102
  return false;
103
  }
104
  $value = $name;
includes/class-amp-theme-support.php CHANGED
@@ -1167,9 +1167,9 @@ class AMP_Theme_Support {
1167
  str_replace(
1168
  '%s',
1169
  sprintf( '" + %s.replyToName + "', $state_id ),
1170
- wp_json_encode( $args['title_reply_to'] )
1171
  ),
1172
- wp_json_encode( $args['title_reply'] )
1173
  );
1174
 
1175
  $args['title_reply_before'] .= sprintf(
@@ -1252,7 +1252,7 @@ class AMP_Theme_Support {
1252
  esc_url( remove_query_arg( 'replytocom' ) . '#' . $respond_id ),
1253
  isset( $_GET['replytocom'] ) ? '' : ' hidden', // phpcs:ignore
1254
  esc_attr( sprintf( '%s.values.comment_parent == "0"', self::get_comment_form_state_id( get_the_ID() ) ) ),
1255
- esc_attr( sprintf( 'tap:AMP.setState( %s )', wp_json_encode( $tap_state ) ) ),
1256
  esc_html( $text )
1257
  );
1258
  }
@@ -1334,7 +1334,7 @@ class AMP_Theme_Support {
1334
  if ( ! $schema_org_meta_script ) {
1335
  $script = $dom->createElement( 'script' );
1336
  $script->setAttribute( 'type', 'application/ld+json' );
1337
- $script->appendChild( $dom->createTextNode( wp_json_encode( amp_get_schemaorg_metadata() ) ) );
1338
  $head->appendChild( $script );
1339
  }
1340
 
@@ -1694,35 +1694,52 @@ class AMP_Theme_Support {
1694
  $stream_fragment = WP_Service_Worker_Navigation_Routing_Component::get_stream_fragment_query_var();
1695
  }
1696
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1697
  $args = array_merge(
1698
  array(
1699
- 'content_max_width' => ! empty( $content_width ) ? $content_width : AMP_Post_Template::CONTENT_MAX_WIDTH, // Back-compat.
1700
- 'use_document_element' => true,
1701
- 'allow_dirty_styles' => self::is_customize_preview_iframe(), // Dirty styles only needed when editing (e.g. for edit shortcodes).
1702
- 'allow_dirty_scripts' => is_customize_preview(), // Scripts are always needed to inject changeset UUID.
1703
- 'enable_response_caching' => (
1704
- ! ( defined( 'WP_DEBUG' ) && WP_DEBUG )
1705
- &&
1706
- ! AMP_Validation_Manager::should_validate_response()
1707
- &&
1708
- ! is_customize_preview()
1709
- ),
1710
- 'user_can_validate' => AMP_Validation_Manager::has_cap(),
1711
- 'stream_fragment' => $stream_fragment,
1712
  ),
1713
- $args
 
1714
  );
1715
 
1716
  $current_url = amp_get_current_url();
1717
  $non_amp_url = amp_remove_endpoint( $current_url );
1718
 
1719
- // When response caching is enabled, determine if it should be turned off for cache misses.
1720
- $caches_for_url = null;
1721
- if ( true === $args['enable_response_caching'] ) {
1722
- list( $disable_response_caching, $caches_for_url ) = self::check_for_cache_misses();
1723
- $args['enable_response_caching'] = ! $disable_response_caching;
1724
- }
1725
-
1726
  /*
1727
  * Set response cache hash, the data values dictates whether a new hash key should be generated or not.
1728
  * This is also used as the ETag.
1167
  str_replace(
1168
  '%s',
1169
  sprintf( '" + %s.replyToName + "', $state_id ),
1170
+ wp_json_encode( $args['title_reply_to'], JSON_UNESCAPED_UNICODE )
1171
  ),
1172
+ wp_json_encode( $args['title_reply'], JSON_UNESCAPED_UNICODE )
1173
  );
1174
 
1175
  $args['title_reply_before'] .= sprintf(
1252
  esc_url( remove_query_arg( 'replytocom' ) . '#' . $respond_id ),
1253
  isset( $_GET['replytocom'] ) ? '' : ' hidden', // phpcs:ignore
1254
  esc_attr( sprintf( '%s.values.comment_parent == "0"', self::get_comment_form_state_id( get_the_ID() ) ) ),
1255
+ esc_attr( sprintf( 'tap:AMP.setState( %s )', wp_json_encode( $tap_state, JSON_UNESCAPED_UNICODE ) ) ),
1256
  esc_html( $text )
1257
  );
1258
  }
1334
  if ( ! $schema_org_meta_script ) {
1335
  $script = $dom->createElement( 'script' );
1336
  $script->setAttribute( 'type', 'application/ld+json' );
1337
+ $script->appendChild( $dom->createTextNode( wp_json_encode( amp_get_schemaorg_metadata(), JSON_UNESCAPED_UNICODE ) ) );
1338
  $head->appendChild( $script );
1339
  }
1340
 
1694
  $stream_fragment = WP_Service_Worker_Navigation_Routing_Component::get_stream_fragment_query_var();
1695
  }
1696
 
1697
+ /**
1698
+ * Filters whether response (post-processor) caching is enabled.
1699
+ *
1700
+ * When enabled and when an external object cache is present, the output of the post-processor phase is stored in
1701
+ * in the object cache. When another request is made that generates the same HTML output, the previously-cached
1702
+ * post-processor output will then be served immediately and bypass needlessly re-running the sanitizers.
1703
+ * This does not apply when:
1704
+ *
1705
+ * - AMP validation is being performed.
1706
+ * - The response is in the Customizer preview.
1707
+ * - Response caching is disabled due to a high-rate of cache misses.
1708
+ *
1709
+ * @param bool $enable_response_caching Whether response caching is enabled.
1710
+ */
1711
+ $enable_response_caching = apply_filters( 'amp_response_caching_enabled', ! ( defined( 'WP_DEBUG' ) && WP_DEBUG ) || ! empty( $args['enable_response_caching'] ) );
1712
+ $enable_response_caching = (
1713
+ $enable_response_caching
1714
+ &&
1715
+ ! AMP_Validation_Manager::should_validate_response()
1716
+ &&
1717
+ ! is_customize_preview()
1718
+ );
1719
+
1720
+ // When response caching is enabled, determine if it should be turned off for cache misses.
1721
+ $caches_for_url = null;
1722
+ if ( $enable_response_caching ) {
1723
+ list( $disable_response_caching, $caches_for_url ) = self::check_for_cache_misses();
1724
+ $enable_response_caching = ! $disable_response_caching;
1725
+ }
1726
+
1727
  $args = array_merge(
1728
  array(
1729
+ 'content_max_width' => ! empty( $content_width ) ? $content_width : AMP_Post_Template::CONTENT_MAX_WIDTH, // Back-compat.
1730
+ 'use_document_element' => true,
1731
+ 'allow_dirty_styles' => self::is_customize_preview_iframe(), // Dirty styles only needed when editing (e.g. for edit shortcodes).
1732
+ 'allow_dirty_scripts' => is_customize_preview(), // Scripts are always needed to inject changeset UUID.
1733
+ 'user_can_validate' => AMP_Validation_Manager::has_cap(),
1734
+ 'stream_fragment' => $stream_fragment,
 
 
 
 
 
 
 
1735
  ),
1736
+ $args,
1737
+ compact( 'enable_response_caching' )
1738
  );
1739
 
1740
  $current_url = amp_get_current_url();
1741
  $non_amp_url = amp_remove_endpoint( $current_url );
1742
 
 
 
 
 
 
 
 
1743
  /*
1744
  * Set response cache hash, the data values dictates whether a new hash key should be generated or not.
1745
  * This is also used as the ETag.
includes/embeds/class-amp-core-block-handler.php CHANGED
@@ -20,6 +20,7 @@ class AMP_Core_Block_Handler extends AMP_Base_Embed_Handler {
20
  protected $block_ampify_methods = array(
21
  'core/categories' => 'ampify_categories_block',
22
  'core/archives' => 'ampify_archives_block',
 
23
  );
24
 
25
  /**
@@ -50,7 +51,8 @@ class AMP_Core_Block_Handler extends AMP_Base_Embed_Handler {
50
  if ( isset( $this->block_ampify_methods[ $block['blockName'] ] ) ) {
51
  $block_content = call_user_func(
52
  array( $this, $this->block_ampify_methods[ $block['blockName'] ] ),
53
- $block_content
 
54
  );
55
  } elseif ( 'core/image' === $block['blockName'] || 'core/audio' === $block['blockName'] ) {
56
  /*
@@ -128,4 +130,32 @@ class AMP_Core_Block_Handler extends AMP_Base_Embed_Handler {
128
  return $block_content;
129
  }
130
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  }
20
  protected $block_ampify_methods = array(
21
  'core/categories' => 'ampify_categories_block',
22
  'core/archives' => 'ampify_archives_block',
23
+ 'core/video' => 'ampify_video_block',
24
  );
25
 
26
  /**
51
  if ( isset( $this->block_ampify_methods[ $block['blockName'] ] ) ) {
52
  $block_content = call_user_func(
53
  array( $this, $this->block_ampify_methods[ $block['blockName'] ] ),
54
+ $block_content,
55
+ $block
56
  );
57
  } elseif ( 'core/image' === $block['blockName'] || 'core/audio' === $block['blockName'] ) {
58
  /*
130
  return $block_content;
131
  }
132
 
133
+ /**
134
+ * Ampify video block.
135
+ *
136
+ * Inject the video attachment's dimensions if available. This prevents having to try to look up the attachment
137
+ * post by the video URL in `\AMP_Video_Sanitizer::filter_video_dimensions()`.
138
+ *
139
+ * @see \AMP_Video_Sanitizer::filter_video_dimensions()
140
+ *
141
+ * @param string $block_content The block content about to be appended.
142
+ * @param array $block The full block, including name and attributes.
143
+ * @return string Filtered block content.
144
+ */
145
+ public function ampify_video_block( $block_content, $block ) {
146
+ if ( empty( $block['attrs']['id'] ) || 'attachment' !== get_post_type( $block['attrs']['id'] ) ) {
147
+ return $block_content;
148
+ }
149
+
150
+ $meta_data = wp_get_attachment_metadata( $block['attrs']['id'] );
151
+ if ( isset( $meta_data['width'] ) && isset( $meta_data['height'] ) ) {
152
+ $block_content = preg_replace(
153
+ '/(?<=<video\s)/',
154
+ sprintf( 'width="%d" height="%d" ', $meta_data['width'], $meta_data['height'] ),
155
+ $block_content
156
+ );
157
+ }
158
+
159
+ return $block_content;
160
+ }
161
  }
includes/sanitizers/class-amp-base-sanitizer.php CHANGED
@@ -220,10 +220,10 @@ abstract class AMP_Base_Sanitizer {
220
  /**
221
  * Sanitizes a CSS dimension specifier while being sensitive to dimension context.
222
  *
223
- * @param string $value A valid CSS dimension specifier; e.g. 50, 50px, 50%.
224
- * @param string $dimension 'width' or ignored. 'width' only affects $values ending in '%'.
225
  *
226
- * @return float|int|string Returns a numeric dimension value, or an empty string.
227
  */
228
  public function sanitize_dimension( $value, $dimension ) {
229
 
@@ -232,6 +232,11 @@ abstract class AMP_Base_Sanitizer {
232
  return '';
233
  }
234
 
 
 
 
 
 
235
  // Accepts both integers and floats & prevents negative values.
236
  if ( is_numeric( $value ) ) {
237
  return max( 0, floatval( $value ) );
220
  /**
221
  * Sanitizes a CSS dimension specifier while being sensitive to dimension context.
222
  *
223
+ * @param string $value A valid CSS dimension specifier; e.g. 50, 50px, 50%. Can be 'auto' for width.
224
+ * @param string $dimension Dimension, either 'width' or 'height'.
225
  *
226
+ * @return float|int|string Returns a numeric dimension value, 'auto', or an empty string.
227
  */
228
  public function sanitize_dimension( $value, $dimension ) {
229
 
232
  return '';
233
  }
234
 
235
+ // Allow special 'auto' value for fixed-height layout.
236
+ if ( 'width' === $dimension && 'auto' === $value ) {
237
+ return $value;
238
+ }
239
+
240
  // Accepts both integers and floats & prevents negative values.
241
  if ( is_numeric( $value ) ) {
242
  return max( 0, floatval( $value ) );
includes/sanitizers/class-amp-comments-sanitizer.php CHANGED
@@ -147,7 +147,7 @@ class AMP_Comments_Sanitizer extends AMP_Base_Sanitizer {
147
  $script = $this->dom->createElement( 'script' );
148
  $script->setAttribute( 'type', 'application/json' );
149
  $amp_state->appendChild( $script );
150
- $script->appendChild( $this->dom->createTextNode( wp_json_encode( $form_state ) ) );
151
  $comment_form->insertBefore( $amp_state, $comment_form->firstChild );
152
 
153
  // Update state when submitting form.
@@ -172,7 +172,7 @@ class AMP_Comments_Sanitizer extends AMP_Base_Sanitizer {
172
  sprintf(
173
  'submit-success:AMP.setState( { %s: %s } )',
174
  $state_id,
175
- wp_json_encode( $form_reset_state )
176
  ),
177
  );
178
  $comment_form->setAttribute( 'on', implode( ';', $on ) );
147
  $script = $this->dom->createElement( 'script' );
148
  $script->setAttribute( 'type', 'application/json' );
149
  $amp_state->appendChild( $script );
150
+ $script->appendChild( $this->dom->createTextNode( wp_json_encode( $form_state, JSON_UNESCAPED_UNICODE ) ) );
151
  $comment_form->insertBefore( $amp_state, $comment_form->firstChild );
152
 
153
  // Update state when submitting form.
172
  sprintf(
173
  'submit-success:AMP.setState( { %s: %s } )',
174
  $state_id,
175
+ wp_json_encode( $form_reset_state, JSON_UNESCAPED_UNICODE )
176
  ),
177
  );
178
  $comment_form->setAttribute( 'on', implode( ';', $on ) );
includes/sanitizers/class-amp-iframe-sanitizer.php CHANGED
@@ -13,15 +13,6 @@
13
  class AMP_Iframe_Sanitizer extends AMP_Base_Sanitizer {
14
  use AMP_Noscript_Fallback;
15
 
16
- /**
17
- * Value used for height attribute when $attributes['height'] is empty.
18
- *
19
- * @since 0.2
20
- *
21
- * @const int
22
- */
23
- const FALLBACK_HEIGHT = 400;
24
-
25
  /**
26
  * Default values for sandboxing IFrame.
27
  *
13
  class AMP_Iframe_Sanitizer extends AMP_Base_Sanitizer {
14
  use AMP_Noscript_Fallback;
15
 
 
 
 
 
 
 
 
 
 
16
  /**
17
  * Default values for sandboxing IFrame.
18
  *
includes/sanitizers/class-amp-img-sanitizer.php CHANGED
@@ -111,8 +111,28 @@ class AMP_Img_Sanitizer extends AMP_Base_Sanitizer {
111
  continue;
112
  }
113
 
 
 
 
 
 
 
 
 
 
 
 
114
  // Determine which images need their dimensions determined/extracted.
115
- if ( ! is_numeric( $node->getAttribute( 'width' ) ) || ! is_numeric( $node->getAttribute( 'height' ) ) ) {
 
 
 
 
 
 
 
 
 
116
  $need_dimensions[ $node->getAttribute( 'src' ) ][] = $node;
117
  } else {
118
  $this->adjust_and_replace_node( $node );
@@ -300,6 +320,33 @@ class AMP_Img_Sanitizer extends AMP_Base_Sanitizer {
300
  $img_node = AMP_DOM_Utils::create_node( $this->dom, $new_tag, $new_attributes );
301
  $node->parentNode->replaceChild( $img_node, $node );
302
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
303
  $can_include_noscript = (
304
  $this->args['add_noscript_fallback']
305
  &&
111
  continue;
112
  }
113
 
114
+ if ( $node->hasAttribute( 'data-amp-layout' ) ) {
115
+ $layout = $node->getAttribute( 'data-amp-layout' );
116
+ } elseif ( $node->hasAttribute( 'layout' ) ) {
117
+ $layout = $node->getAttribute( 'layout' );
118
+ } else {
119
+ $layout = 'intrinsic';
120
+ }
121
+
122
+ $has_width = is_numeric( $node->getAttribute( 'width' ) );
123
+ $has_height = is_numeric( $node->getAttribute( 'height' ) );
124
+
125
  // Determine which images need their dimensions determined/extracted.
126
+ $missing_dimensions = (
127
+ ( ! $has_height && 'fixed-height' === $layout )
128
+ ||
129
+ (
130
+ ( ! $has_width || ! $has_height )
131
+ &&
132
+ in_array( $layout, array( 'fixed', 'responsive', 'intrinsic' ), true )
133
+ )
134
+ );
135
+ if ( $missing_dimensions ) {
136
  $need_dimensions[ $node->getAttribute( 'src' ) ][] = $node;
137
  } else {
138
  $this->adjust_and_replace_node( $node );
320
  $img_node = AMP_DOM_Utils::create_node( $this->dom, $new_tag, $new_attributes );
321
  $node->parentNode->replaceChild( $img_node, $node );
322
 
323
+ /*
324
+ * Prevent inline style on an image from rendering the amp-img invisible or conflicting with the required display.
325
+ * This could eventually be expanded to fixup inline styles for elements other than images, but the reality
326
+ * is that this is not going to completely solve the problem for images as well, since it will not handle the
327
+ * case where an image gets a display:inline style via a style rule.
328
+ * See <https://github.com/ampproject/amp-wp/issues/1803>.
329
+ */
330
+ if ( $img_node->hasAttribute( 'style' ) ) {
331
+ $layout = $img_node->getAttribute( 'layout' );
332
+ if ( in_array( $layout, array( 'fixed-height', 'responsive', 'fill', 'flex-item' ), true ) ) {
333
+ $required_display = 'block';
334
+ } elseif ( 'nodisplay' === $layout ) {
335
+ $required_display = 'none';
336
+ } else {
337
+ // This is also the default for any AMP element (.i-amphtml-element).
338
+ $required_display = 'inline-block';
339
+ }
340
+ $img_node->setAttribute(
341
+ 'style',
342
+ preg_replace(
343
+ '/\bdisplay\s*:\s*[a-z\-]+\b/',
344
+ "display:$required_display",
345
+ $img_node->getAttribute( 'style' )
346
+ )
347
+ );
348
+ }
349
+
350
  $can_include_noscript = (
351
  $this->args['add_noscript_fallback']
352
  &&
includes/sanitizers/class-amp-style-sanitizer.php CHANGED
@@ -1157,7 +1157,7 @@ class AMP_Style_Sanitizer extends AMP_Base_Sanitizer {
1157
  private function process_stylesheet( $stylesheet, $options = array() ) {
1158
  $parsed = null;
1159
  $cache_key = null;
1160
- $cache_group = 'amp-parsed-stylesheet-v17'; // This should be bumped whenever the PHP-CSS-Parser is updated or parsed format is updated.
1161
 
1162
  $cache_impacting_options = array_merge(
1163
  wp_array_slice_assoc(
@@ -1512,8 +1512,8 @@ class AMP_Style_Sanitizer extends AMP_Base_Sanitizer {
1512
  foreach ( $selectors as $selector ) {
1513
  $selectors_parsed[ $selector ] = array();
1514
 
1515
- // Remove :not() and pseudo selectors to eliminate false negatives, such as with `body:not(.title-tagline-hidden) .site-branding-text`.
1516
- $reduced_selector = preg_replace( '/::?[a-zA-Z0-9_-]+(\(.+?\))?/', '', $selector );
1517
 
1518
  // Ignore any selector terms that occur under a dynamic selector.
1519
  if ( $dynamic_selector_pattern ) {
@@ -1535,9 +1535,9 @@ class AMP_Style_Sanitizer extends AMP_Base_Sanitizer {
1535
 
1536
  // Extract class names.
1537
  $reduced_selector = preg_replace_callback(
1538
- '/\.([a-zA-Z0-9_-]+)/',
1539
  function( $matches ) use ( $selector, &$selectors_parsed ) {
1540
- $selectors_parsed[ $selector ][ self::SELECTOR_EXTRACTED_CLASSES ][] = $matches[1];
1541
  return '';
1542
  },
1543
  $reduced_selector
1157
  private function process_stylesheet( $stylesheet, $options = array() ) {
1158
  $parsed = null;
1159
  $cache_key = null;
1160
+ $cache_group = 'amp-parsed-stylesheet-v18'; // This should be bumped whenever the PHP-CSS-Parser is updated or parsed format is updated.
1161
 
1162
  $cache_impacting_options = array_merge(
1163
  wp_array_slice_assoc(
1512
  foreach ( $selectors as $selector ) {
1513
  $selectors_parsed[ $selector ] = array();
1514
 
1515
+ // Remove :not() and pseudo selectors to eliminate false negatives, such as with `body:not(.title-tagline-hidden) .site-branding-text` (but not after escape character).
1516
+ $reduced_selector = preg_replace( '/(?<!\\\\)::?[a-zA-Z0-9_-]+(\(.+?\))?/', '', $selector );
1517
 
1518
  // Ignore any selector terms that occur under a dynamic selector.
1519
  if ( $dynamic_selector_pattern ) {
1535
 
1536
  // Extract class names.
1537
  $reduced_selector = preg_replace_callback(
1538
+ '/\.((?:[a-zA-Z0-9_-]+|\\\\.)+)/', // The `\\\\.` will allow any char via escaping, like the colon in `.lg\:w-full`.
1539
  function( $matches ) use ( $selector, &$selectors_parsed ) {
1540
+ $selectors_parsed[ $selector ][ self::SELECTOR_EXTRACTED_CLASSES ][] = stripslashes( $matches[1] );
1541
  return '';
1542
  },
1543
  $reduced_selector
includes/sanitizers/class-amp-video-sanitizer.php CHANGED
@@ -15,15 +15,6 @@
15
  class AMP_Video_Sanitizer extends AMP_Base_Sanitizer {
16
  use AMP_Noscript_Fallback;
17
 
18
- /**
19
- * Value used for height attribute when $attributes['height'] is empty.
20
- *
21
- * @since 0.2
22
- *
23
- * @const int
24
- */
25
- const FALLBACK_HEIGHT = 400;
26
-
27
  /**
28
  * Tag.
29
  *
@@ -188,6 +179,10 @@ class AMP_Video_Sanitizer extends AMP_Base_Sanitizer {
188
  /**
189
  * Filter video dimensions, try to get width and height from original file if missing.
190
  *
 
 
 
 
191
  * @param array $new_attributes Attributes.
192
  * @param string $src Video URL.
193
  * @return array Modified attributes.
15
  class AMP_Video_Sanitizer extends AMP_Base_Sanitizer {
16
  use AMP_Noscript_Fallback;
17
 
 
 
 
 
 
 
 
 
 
18
  /**
19
  * Tag.
20
  *
179
  /**
180
  * Filter video dimensions, try to get width and height from original file if missing.
181
  *
182
+ * The video block will automatically have the width/height supplied for attachments.
183
+ *
184
+ * @see \AMP_Core_Block_Handler::ampify_video_block()
185
+ *
186
  * @param array $new_attributes Attributes.
187
  * @param string $src Video URL.
188
  * @return array Modified attributes.
includes/validation/class-amp-validation-manager.php CHANGED
@@ -190,7 +190,7 @@ class AMP_Validation_Manager {
190
  }
191
  );
192
 
193
- add_action( 'admin_bar_menu', array( __CLASS__, 'add_admin_bar_menu_items' ), 100 );
194
 
195
  // Add filter to auto-accept tree shaking validation error.
196
  if ( AMP_Options_Manager::get_option( 'accept_tree_shaking' ) || AMP_Options_Manager::get_option( 'auto_accept_sanitization' ) ) {
@@ -259,6 +259,7 @@ class AMP_Validation_Manager {
259
  * - Parent admin and first submenu item: link to validate the URL.
260
  *
261
  * @see AMP_Validation_Manager::finalize_validation() Where the emoji is updated.
 
262
  *
263
  * @param WP_Admin_Bar $wp_admin_bar Admin bar.
264
  */
@@ -326,23 +327,37 @@ class AMP_Validation_Manager {
326
  // @todo The amp_validated_url post should probably only be accessible to users who can manage_options, or limit access to a post if the user has the cap to edit the queried object?
327
  $validate_url = AMP_Validated_URL_Post_Type::get_recheck_url( $amp_validated_url_post ? $amp_validated_url_post : $amp_url );
328
 
 
329
  if ( is_amp_endpoint() ) {
330
  $icon = '&#x2705;'; // WHITE HEAVY CHECK MARK. This will get overridden in AMP_Validation_Manager::finalize_validation() if there are unaccepted errors.
 
331
  } elseif ( $error_count > 0 ) {
332
  $icon = '&#x274C;'; // CROSS MARK.
 
333
  } else {
334
  $icon = '&#x1F517;'; // LINK SYMBOL.
 
335
  }
 
 
 
 
 
 
 
 
 
336
 
 
337
  $validate_item = array(
338
  'parent' => 'amp',
339
  'id' => 'amp-validity',
340
  'href' => esc_url( $validate_url ),
341
  );
342
  if ( $error_count <= 0 ) {
343
- $validate_item['item'] = esc_html__( 'Re-validate', 'amp' );
344
  } else {
345
- $validate_item['item'] = esc_html(
346
  sprintf(
347
  /* translators: %s is count of validation errors */
348
  _n(
@@ -356,75 +371,37 @@ class AMP_Validation_Manager {
356
  );
357
  }
358
 
359
- $parent = array(
360
- 'id' => 'amp',
361
- 'title' => sprintf(
362
- '<span id="amp-admin-bar-item-status-icon">%s</span> %s',
363
- $icon,
364
- esc_html( is_amp_endpoint() ? __( 'AMP', 'amp' ) : __( 'View AMP', 'amp' ) )
365
- ),
366
  );
367
 
368
- $first_item_is_validate = (
 
369
  amp_is_canonical()
370
  ||
371
  ( ! is_amp_endpoint() && $error_count > 0 )
372
  );
373
- if ( $first_item_is_validate ) {
374
- $title = __( 'Validate AMP', 'amp' );
375
- $parent['href'] = esc_url( $validate_url );
376
- } elseif ( is_amp_endpoint() ) {
377
- $title = __( 'AMP', 'amp' );
378
- $parent['href'] = esc_url( $non_amp_url );
379
- } else {
380
- $title = __( 'View AMP', 'amp' );
381
- $parent['href'] = esc_url( $amp_url );
382
- }
383
- $parent['title'] = sprintf(
384
- '<span id="amp-admin-bar-item-status-icon">%s</span> %s',
385
- $icon,
386
- esc_html( $title )
387
- );
388
 
389
- $wp_admin_bar->add_menu( $parent );
 
390
 
391
- // Add admin bar item to switch between AMP and non-AMP if parent node is also an AMP link.
392
- if ( ! $first_item_is_validate ) {
393
- $wp_admin_bar->add_menu(
394
- array(
395
- 'parent' => 'amp',
396
- 'id' => 'amp-view',
397
- 'title' => esc_html( is_amp_endpoint() ? __( 'View non-AMP version', 'amp' ) : __( 'View AMP version', 'amp' ) ),
398
- 'href' => esc_url( is_amp_endpoint() ? $non_amp_url : $amp_url ),
399
- )
400
- );
401
- }
402
-
403
- // Validate admin bar item.
404
- if ( $error_count <= 0 ) {
405
- $title = esc_html__( 'Re-validate', 'amp' );
406
  } else {
407
- $title = esc_html(
408
- sprintf(
409
- /* translators: %s is count of validation errors */
410
- _n(
411
- 'Re-validate (%s validation error)',
412
- 'Re-validate (%s validation errors)',
413
- $error_count,
414
- 'amp'
415
- ),
416
- number_format_i18n( $error_count )
417
- )
418
- );
419
  }
420
- $wp_admin_bar->add_menu(
421
- array(
422
- 'parent' => 'amp',
423
- 'id' => 'amp-validity',
424
- 'title' => esc_html( $title ),
425
- 'href' => esc_url( $validate_url ),
426
- )
427
- );
428
 
429
  // Scrub the query var from the URL.
430
  if ( ! is_amp_endpoint() && isset( $_GET[ self::VALIDATION_ERRORS_QUERY_VAR ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
190
  }
191
  );
192
 
193
+ add_action( 'admin_bar_menu', array( __CLASS__, 'add_admin_bar_menu_items' ), 101 );
194
 
195
  // Add filter to auto-accept tree shaking validation error.
196
  if ( AMP_Options_Manager::get_option( 'accept_tree_shaking' ) || AMP_Options_Manager::get_option( 'auto_accept_sanitization' ) ) {
259
  * - Parent admin and first submenu item: link to validate the URL.
260
  *
261
  * @see AMP_Validation_Manager::finalize_validation() Where the emoji is updated.
262
+ * @see amp_add_admin_bar_view_link() Where an admin bar item may have been added already for Reader/Transitional modes.
263
  *
264
  * @param WP_Admin_Bar $wp_admin_bar Admin bar.
265
  */
327
  // @todo The amp_validated_url post should probably only be accessible to users who can manage_options, or limit access to a post if the user has the cap to edit the queried object?
328
  $validate_url = AMP_Validated_URL_Post_Type::get_recheck_url( $amp_validated_url_post ? $amp_validated_url_post : $amp_url );
329
 
330
+ // Construct the parent admin bar item.
331
  if ( is_amp_endpoint() ) {
332
  $icon = '&#x2705;'; // WHITE HEAVY CHECK MARK. This will get overridden in AMP_Validation_Manager::finalize_validation() if there are unaccepted errors.
333
+ $href = $validate_url;
334
  } elseif ( $error_count > 0 ) {
335
  $icon = '&#x274C;'; // CROSS MARK.
336
+ $href = $validate_url;
337
  } else {
338
  $icon = '&#x1F517;'; // LINK SYMBOL.
339
+ $href = $amp_url;
340
  }
341
+ $parent = array(
342
+ 'id' => 'amp',
343
+ 'title' => sprintf(
344
+ '<span id="amp-admin-bar-item-status-icon">%s</span> %s',
345
+ $icon,
346
+ esc_html__( 'AMP', 'amp' )
347
+ ),
348
+ 'href' => esc_url( $href ),
349
+ );
350
 
351
+ // Construct admin bar item for validation.
352
  $validate_item = array(
353
  'parent' => 'amp',
354
  'id' => 'amp-validity',
355
  'href' => esc_url( $validate_url ),
356
  );
357
  if ( $error_count <= 0 ) {
358
+ $validate_item['title'] = esc_html__( 'Re-validate', 'amp' );
359
  } else {
360
+ $validate_item['title'] = esc_html(
361
  sprintf(
362
  /* translators: %s is count of validation errors */
363
  _n(
371
  );
372
  }
373
 
374
+ // Construct admin bar item to link to AMP version or non-AMP version.
375
+ $link_item = array(
376
+ 'parent' => 'amp',
377
+ 'id' => 'amp-view',
378
+ 'title' => esc_html( is_amp_endpoint() ? __( 'View non-AMP version', 'amp' ) : __( 'View AMP version', 'amp' ) ),
379
+ 'href' => esc_url( is_amp_endpoint() ? $non_amp_url : $amp_url ),
 
380
  );
381
 
382
+ // Add admin bar item to switch between AMP and non-AMP if parent node is also an AMP link.
383
+ $is_single_version_available = (
384
  amp_is_canonical()
385
  ||
386
  ( ! is_amp_endpoint() && $error_count > 0 )
387
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
388
 
389
+ // Add top-level menu item. Note that this will correctly merge/amend any existing AMP nav menu item added in amp_add_admin_bar_view_link().
390
+ $wp_admin_bar->add_node( $parent );
391
 
392
+ /*
393
+ * Add submenu items based on whether viewing AMP or not, and whether or not AMP is available.
394
+ * When
395
+ */
396
+ if ( $is_single_version_available ) {
397
+ $wp_admin_bar->add_node( $validate_item );
398
+ } elseif ( ! is_amp_endpoint() ) {
399
+ $wp_admin_bar->add_node( $link_item );
400
+ $wp_admin_bar->add_node( $validate_item );
 
 
 
 
 
 
401
  } else {
402
+ $wp_admin_bar->add_node( $validate_item );
403
+ $wp_admin_bar->add_node( $link_item );
 
 
 
 
 
 
 
 
 
 
404
  }
 
 
 
 
 
 
 
 
405
 
406
  // Scrub the query var from the URL.
407
  if ( ! is_amp_endpoint() && isset( $_GET[ self::VALIDATION_ERRORS_QUERY_VAR ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: automattic, xwp, google, westonruter, ryankienstra, batmoo, stubgo
3
  Tags: amp, mobile
4
  Requires at least: 4.9
5
  Tested up to: 5.2
6
- Stable tag: 1.1.1
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
  Requires PHP: 5.4
3
  Tags: amp, mobile
4
  Requires at least: 4.9
5
  Tested up to: 5.2
6
+ Stable tag: 1.1.2
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
  Requires PHP: 5.4
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit827e61deccfa9f79cdf08e64e91986f6::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInitc72c5a5bf4d2f7ed46b9f193c7cebf78::getLoader();
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit827e61deccfa9f79cdf08e64e91986f6
6
  {
7
  private static $loader;
8
 
@@ -19,15 +19,15 @@ class ComposerAutoloaderInit827e61deccfa9f79cdf08e64e91986f6
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit827e61deccfa9f79cdf08e64e91986f6', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit827e61deccfa9f79cdf08e64e91986f6', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
- call_user_func(\Composer\Autoload\ComposerStaticInit827e61deccfa9f79cdf08e64e91986f6::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInitc72c5a5bf4d2f7ed46b9f193c7cebf78
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInitc72c5a5bf4d2f7ed46b9f193c7cebf78', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInitc72c5a5bf4d2f7ed46b9f193c7cebf78', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
+ call_user_func(\Composer\Autoload\ComposerStaticInitc72c5a5bf4d2f7ed46b9f193c7cebf78::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInit827e61deccfa9f79cdf08e64e91986f6
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'c' =>
@@ -56,10 +56,10 @@ class ComposerStaticInit827e61deccfa9f79cdf08e64e91986f6
56
  public static function getInitializer(ClassLoader $loader)
57
  {
58
  return \Closure::bind(function () use ($loader) {
59
- $loader->prefixLengthsPsr4 = ComposerStaticInit827e61deccfa9f79cdf08e64e91986f6::$prefixLengthsPsr4;
60
- $loader->prefixDirsPsr4 = ComposerStaticInit827e61deccfa9f79cdf08e64e91986f6::$prefixDirsPsr4;
61
- $loader->prefixesPsr0 = ComposerStaticInit827e61deccfa9f79cdf08e64e91986f6::$prefixesPsr0;
62
- $loader->classMap = ComposerStaticInit827e61deccfa9f79cdf08e64e91986f6::$classMap;
63
 
64
  }, null, ClassLoader::class);
65
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInitc72c5a5bf4d2f7ed46b9f193c7cebf78
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'c' =>
56
  public static function getInitializer(ClassLoader $loader)
57
  {
58
  return \Closure::bind(function () use ($loader) {
59
+ $loader->prefixLengthsPsr4 = ComposerStaticInitc72c5a5bf4d2f7ed46b9f193c7cebf78::$prefixLengthsPsr4;
60
+ $loader->prefixDirsPsr4 = ComposerStaticInitc72c5a5bf4d2f7ed46b9f193c7cebf78::$prefixDirsPsr4;
61
+ $loader->prefixesPsr0 = ComposerStaticInitc72c5a5bf4d2f7ed46b9f193c7cebf78::$prefixesPsr0;
62
+ $loader->classMap = ComposerStaticInitc72c5a5bf4d2f7ed46b9f193c7cebf78::$classMap;
63
 
64
  }, null, ClassLoader::class);
65
  }
vendor/composer/installed.json CHANGED
@@ -1,17 +1,17 @@
1
  [
2
  {
3
  "name": "cweagans/composer-patches",
4
- "version": "1.6.5",
5
- "version_normalized": "1.6.5.0",
6
  "source": {
7
  "type": "git",
8
  "url": "https://github.com/cweagans/composer-patches.git",
9
- "reference": "2ec4f00ff5fb64de584c8c4aea53bf9053ecb0b3"
10
  },
11
  "dist": {
12
  "type": "zip",
13
- "url": "https://api.github.com/repos/cweagans/composer-patches/zipball/2ec4f00ff5fb64de584c8c4aea53bf9053ecb0b3",
14
- "reference": "2ec4f00ff5fb64de584c8c4aea53bf9053ecb0b3",
15
  "shasum": ""
16
  },
17
  "require": {
@@ -22,12 +22,12 @@
22
  "composer/composer": "~1.0",
23
  "phpunit/phpunit": "~4.6"
24
  },
25
- "time": "2018-05-11T18:00:16+00:00",
26
  "type": "composer-plugin",
27
  "extra": {
28
  "class": "cweagans\\Composer\\Patches"
29
  },
30
- "installation-source": "dist",
31
  "autoload": {
32
  "psr-4": {
33
  "cweagans\\Composer\\": "src"
@@ -115,17 +115,17 @@
115
  },
116
  {
117
  "name": "fasterimage/fasterimage",
118
- "version": "v1.4.0",
119
- "version_normalized": "1.4.0.0",
120
  "source": {
121
  "type": "git",
122
  "url": "https://github.com/willwashburn/fasterimage.git",
123
- "reference": "2a85079bef8090c2820bcad5c649cdc41f7b53ab"
124
  },
125
  "dist": {
126
  "type": "zip",
127
- "url": "https://api.github.com/repos/willwashburn/fasterimage/zipball/2a85079bef8090c2820bcad5c649cdc41f7b53ab",
128
- "reference": "2a85079bef8090c2820bcad5c649cdc41f7b53ab",
129
  "shasum": ""
130
  },
131
  "require": {
@@ -133,12 +133,13 @@
133
  "willwashburn/stream": ">=1.0"
134
  },
135
  "require-dev": {
136
- "mockery/mockery": "~0.9",
137
- "phpunit/phpunit": "~4.0"
 
138
  },
139
- "time": "2019-03-07T05:20:21+00:00",
140
  "type": "library",
141
- "installation-source": "dist",
142
  "autoload": {
143
  "classmap": [
144
  "src"
@@ -152,6 +153,9 @@
152
  {
153
  "name": "Will Washburn",
154
  "email": "will@tailwindapp.com"
 
 
 
155
  }
156
  ],
157
  "description": "FasterImage finds the size or type of a set of images given their uris by fetching as little as needed, in parallel. Originally ported by Tom Moor.",
@@ -197,7 +201,7 @@
197
  },
198
  "time": "2018-12-30T23:16:27+00:00",
199
  "type": "phpcodesniffer-standard",
200
- "installation-source": "dist",
201
  "notification-url": "https://packagist.org/downloads/",
202
  "license": [
203
  "LGPL-3.0-or-later"
@@ -355,7 +359,7 @@
355
  },
356
  "time": "2016-03-15T10:54:35+00:00",
357
  "type": "library",
358
- "installation-source": "dist",
359
  "autoload": {
360
  "psr-4": {
361
  "WillWashburn\\": "src/"
@@ -382,17 +386,17 @@
382
  },
383
  {
384
  "name": "wp-coding-standards/wpcs",
385
- "version": "2.1.0",
386
- "version_normalized": "2.1.0.0",
387
  "source": {
388
  "type": "git",
389
  "url": "https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards.git",
390
- "reference": "8c7a2e7682de9ef5955251874b639deda51ef470"
391
  },
392
  "dist": {
393
  "type": "zip",
394
- "url": "https://api.github.com/repos/WordPress-Coding-Standards/WordPress-Coding-Standards/zipball/8c7a2e7682de9ef5955251874b639deda51ef470",
395
- "reference": "8c7a2e7682de9ef5955251874b639deda51ef470",
396
  "shasum": ""
397
  },
398
  "require": {
@@ -407,7 +411,7 @@
407
  "suggest": {
408
  "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically."
409
  },
410
- "time": "2019-04-08T10:53:57+00:00",
411
  "type": "phpcodesniffer-standard",
412
  "installation-source": "source",
413
  "notification-url": "https://packagist.org/downloads/",
@@ -444,7 +448,7 @@
444
  },
445
  "time": "2019-04-06T06:37:44+00:00",
446
  "type": "library",
447
- "installation-source": "dist",
448
  "notification-url": "https://packagist.org/downloads/",
449
  "license": [
450
  "MIT"
1
  [
2
  {
3
  "name": "cweagans/composer-patches",
4
+ "version": "1.6.6",
5
+ "version_normalized": "1.6.6.0",
6
  "source": {
7
  "type": "git",
8
  "url": "https://github.com/cweagans/composer-patches.git",
9
+ "reference": "1d89dcc730e7f42426c434b88261fcfb3bce651e"
10
  },
11
  "dist": {
12
  "type": "zip",
13
+ "url": "https://api.github.com/repos/cweagans/composer-patches/zipball/1d89dcc730e7f42426c434b88261fcfb3bce651e",
14
+ "reference": "1d89dcc730e7f42426c434b88261fcfb3bce651e",
15
  "shasum": ""
16
  },
17
  "require": {
22
  "composer/composer": "~1.0",
23
  "phpunit/phpunit": "~4.6"
24
  },
25
+ "time": "2018-10-24T15:51:16+00:00",
26
  "type": "composer-plugin",
27
  "extra": {
28
  "class": "cweagans\\Composer\\Patches"
29
  },
30
+ "installation-source": "source",
31
  "autoload": {
32
  "psr-4": {
33
  "cweagans\\Composer\\": "src"
115
  },
116
  {
117
  "name": "fasterimage/fasterimage",
118
+ "version": "v1.5.0",
119
+ "version_normalized": "1.5.0.0",
120
  "source": {
121
  "type": "git",
122
  "url": "https://github.com/willwashburn/fasterimage.git",
123
+ "reference": "42d125a15dc124520aff2157bbed9a4b2d4f310a"
124
  },
125
  "dist": {
126
  "type": "zip",
127
+ "url": "https://api.github.com/repos/willwashburn/fasterimage/zipball/42d125a15dc124520aff2157bbed9a4b2d4f310a",
128
+ "reference": "42d125a15dc124520aff2157bbed9a4b2d4f310a",
129
  "shasum": ""
130
  },
131
  "require": {
133
  "willwashburn/stream": ">=1.0"
134
  },
135
  "require-dev": {
136
+ "php-coveralls/php-coveralls": "^2.1",
137
+ "php-mock/php-mock-phpunit": "^2.3",
138
+ "phpunit/phpunit": "~6.0"
139
  },
140
+ "time": "2019-05-25T14:33:33+00:00",
141
  "type": "library",
142
+ "installation-source": "source",
143
  "autoload": {
144
  "classmap": [
145
  "src"
153
  {
154
  "name": "Will Washburn",
155
  "email": "will@tailwindapp.com"
156
+ },
157
+ {
158
+ "name": "Weston Ruter"
159
  }
160
  ],
161
  "description": "FasterImage finds the size or type of a set of images given their uris by fetching as little as needed, in parallel. Originally ported by Tom Moor.",
201
  },
202
  "time": "2018-12-30T23:16:27+00:00",
203
  "type": "phpcodesniffer-standard",
204
+ "installation-source": "source",
205
  "notification-url": "https://packagist.org/downloads/",
206
  "license": [
207
  "LGPL-3.0-or-later"
359
  },
360
  "time": "2016-03-15T10:54:35+00:00",
361
  "type": "library",
362
+ "installation-source": "source",
363
  "autoload": {
364
  "psr-4": {
365
  "WillWashburn\\": "src/"
386
  },
387
  {
388
  "name": "wp-coding-standards/wpcs",
389
+ "version": "2.1.1",
390
+ "version_normalized": "2.1.1.0",
391
  "source": {
392
  "type": "git",
393
  "url": "https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards.git",
394
+ "reference": "bd9c33152115e6741e3510ff7189605b35167908"
395
  },
396
  "dist": {
397
  "type": "zip",
398
+ "url": "https://api.github.com/repos/WordPress-Coding-Standards/WordPress-Coding-Standards/zipball/bd9c33152115e6741e3510ff7189605b35167908",
399
+ "reference": "bd9c33152115e6741e3510ff7189605b35167908",
400
  "shasum": ""
401
  },
402
  "require": {
411
  "suggest": {
412
  "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically."
413
  },
414
+ "time": "2019-05-21T02:50:00+00:00",
415
  "type": "phpcodesniffer-standard",
416
  "installation-source": "source",
417
  "notification-url": "https://packagist.org/downloads/",
448
  },
449
  "time": "2019-04-06T06:37:44+00:00",
450
  "type": "library",
451
+ "installation-source": "source",
452
  "notification-url": "https://packagist.org/downloads/",
453
  "license": [
454
  "MIT"
vendor/fasterimage/fasterimage/src/FasterImage/FasterImage.php CHANGED
@@ -61,13 +61,41 @@ class FasterImage
61
  /**
62
  * Get the size of each of the urls in a list
63
  *
64
- * @param array $urls
65
  *
66
- * @return array
67
- * @throws \Exception
68
  */
69
  public function batch(array $urls)
70
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
 
72
  $multi = curl_multi_init();
73
  $results = array();
@@ -112,6 +140,34 @@ class FasterImage
112
  return $results;
113
  }
114
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  /**
116
  * @param int $seconds
117
  */
@@ -271,7 +327,7 @@ class FasterImage
271
  */
272
  //
273
  // hey curl! this is an error. But really we just are stopping cause
274
- // we already have what we wwant
275
  return -1;
276
  });
277
 
61
  /**
62
  * Get the size of each of the urls in a list
63
  *
64
+ * @param string[] $urls URLs to fetch.
65
  *
66
+ * @return array Results.
67
+ * @throws \Exception When the cURL write callback fails to amend the $results.
68
  */
69
  public function batch(array $urls)
70
  {
71
+ // @codeCoverageIgnoreStart
72
+ /**
73
+ * It turns out that even when cURL is installed, the `curl_multi_init()
74
+ * function may be disabled on some hosts who are seeking to guard against
75
+ * DDoS attacks.
76
+ *
77
+ * @see https://github.com/ampproject/amp-wp/pull/2183#issuecomment-491506514
78
+ *
79
+ * If it is disabled, we will batch these synchronously (with a significant
80
+ * performance hit).
81
+ */
82
+ $has_curl_multi = (
83
+ function_exists( 'curl_multi_init' )
84
+ &&
85
+ function_exists( 'curl_multi_exec' )
86
+ &&
87
+ function_exists( 'curl_multi_add_handle' )
88
+ &&
89
+ function_exists( 'curl_multi_select' )
90
+ &&
91
+ defined( 'CURLM_OK' )
92
+ &&
93
+ defined( 'CURLM_CALL_MULTI_PERFORM' )
94
+ );
95
+ if ( ! $has_curl_multi ) {
96
+ return $this->batchSynchronously($urls);
97
+ }
98
+ // @codeCoverageIgnoreEnd
99
 
100
  $multi = curl_multi_init();
101
  $results = array();
140
  return $results;
141
  }
142
 
143
+ /**
144
+ * Get the size of each of the urls in a list, using synchronous method
145
+ *
146
+ * @param string[] $urls URLs to fetch.
147
+ *
148
+ * @return array Results.
149
+ * @throws \Exception When the cURL write callback fails to amend the $results.
150
+ * @codeCoverageIgnore
151
+ */
152
+ protected function batchSynchronously(array $urls) {
153
+ $results = [];
154
+ foreach ( array_values($urls) as $count => $uri ) {
155
+ $results[$uri] = [];
156
+
157
+ $ch = $this->handle($uri, $results[$uri]);
158
+
159
+ curl_exec($ch);
160
+
161
+ // We can't check return value because the buffer size is too small and curl_error() will always be "Failed writing body".
162
+ if ( empty($results[$uri]) ) {
163
+ throw new \Exception("Curl handle for $uri could not be executed");
164
+ }
165
+
166
+ curl_close($ch);
167
+ }
168
+ return $results;
169
+ }
170
+
171
  /**
172
  * @param int $seconds
173
  */
327
  */
328
  //
329
  // hey curl! this is an error. But really we just are stopping cause
330
+ // we already have what we want
331
  return -1;
332
  });
333