AMP for WordPress - Version 1.4.2

Version Description

Download this release

Release Info

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

Code changes from version 1.4.1 to 1.4.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.4.1
9
  * Text Domain: amp
10
  * Domain Path: /languages/
11
  * License: GPLv2 or later
@@ -15,7 +15,7 @@
15
 
16
  define( 'AMP__FILE__', __FILE__ );
17
  define( 'AMP__DIR__', dirname( __FILE__ ) );
18
- define( 'AMP__VERSION', '1.4.1' );
19
 
20
  /**
21
  * Errors encountered while loading the plugin.
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.4.2
9
  * Text Domain: amp
10
  * Domain Path: /languages/
11
  * License: GPLv2 or later
15
 
16
  define( 'AMP__FILE__', __FILE__ );
17
  define( 'AMP__DIR__', dirname( __FILE__ ) );
18
+ define( 'AMP__VERSION', '1.4.2' );
19
 
20
  /**
21
  * Errors encountered while loading the plugin.
assets/css/amp-validation-single-error-url-rtl.css CHANGED
@@ -63,6 +63,10 @@ table.striped > tbody > tr.even {
63
  font-weight: 600;
64
  }
65
 
 
 
 
 
66
  .column-status select {
67
  vertical-align: top;
68
  }
63
  font-weight: 600;
64
  }
65
 
66
+ .detailed pre {
67
+ white-space: pre-wrap;
68
+ }
69
+
70
  .column-status select {
71
  vertical-align: top;
72
  }
assets/css/amp-validation-single-error-url.css CHANGED
@@ -63,6 +63,10 @@ table.striped > tbody > tr.even {
63
  font-weight: 600;
64
  }
65
 
 
 
 
 
66
  .column-status select {
67
  vertical-align: top;
68
  }
63
  font-weight: 600;
64
  }
65
 
66
+ .detailed pre {
67
+ white-space: pre-wrap;
68
+ }
69
+
70
  .column-status select {
71
  vertical-align: top;
72
  }
assets/fonts/genericons.woff ADDED
Binary file
assets/fonts/nonbreakingspaceoverride.woff ADDED
Binary file
assets/fonts/nonbreakingspaceoverride.woff2 ADDED
Binary file
includes/class-amp-story-post-type.php CHANGED
@@ -684,10 +684,14 @@ class AMP_Story_Post_Type {
684
  /**
685
  * Filter the allowed tags for KSES to allow for amp-story children.
686
  *
687
- * @param array $allowed_tags Allowed tags.
688
- * @return array Allowed tags.
689
  */
690
  public static function filter_kses_allowed_html( $allowed_tags ) {
 
 
 
 
691
  $story_components = [
692
  'amp-story-page',
693
  'amp-story-grid-layer',
684
  /**
685
  * Filter the allowed tags for KSES to allow for amp-story children.
686
  *
687
+ * @param array|string $allowed_tags Allowed tags.
688
+ * @return array|string Allowed tags.
689
  */
690
  public static function filter_kses_allowed_html( $allowed_tags ) {
691
+ if ( ! is_array( $allowed_tags ) ) {
692
+ return $allowed_tags;
693
+ }
694
+
695
  $story_components = [
696
  'amp-story-page',
697
  'amp-story-grid-layer',
includes/class-amp-theme-support.php CHANGED
@@ -1468,6 +1468,57 @@ class AMP_Theme_Support {
1468
  return false;
1469
  }
1470
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1471
  /**
1472
  * Add data-ampdevmode attribute to any enqueued style that depends on the admin-bar.
1473
  *
@@ -1478,30 +1529,11 @@ class AMP_Theme_Support {
1478
  * @return string Tag.
1479
  */
1480
  public static function filter_admin_bar_style_loader_tag( $tag, $handle ) {
1481
- if ( 'dashicons' === $handle ) {
1482
- // Conditionally include Dashicons in dev mode only if was included because it is a dependency of admin-bar.
1483
- $needs_dev_mode = true;
1484
- foreach ( wp_styles()->queue as $queued_handle ) {
1485
- if (
1486
- // If a theme or plugin directly enqueued dashicons, then it is not added via admin-bar dependency and it is not part of dev mode.
1487
- 'dashicons' === $queued_handle
1488
- ||
1489
- // If a stylesheet has dashicons as a dependency without also having admin-bar as a dependency, then no dev mode.
1490
- (
1491
- self::has_dependency( wp_styles(), $queued_handle, 'dashicons' )
1492
- &&
1493
- ! self::has_dependency( wp_styles(), $queued_handle, 'admin-bar' )
1494
- )
1495
- ) {
1496
- $needs_dev_mode = false;
1497
- break;
1498
- }
1499
- }
1500
- } else {
1501
- $needs_dev_mode = self::has_dependency( wp_styles(), $handle, 'admin-bar' );
1502
- }
1503
-
1504
- if ( $needs_dev_mode ) {
1505
  $tag = preg_replace( '/(?<=<link)(?=\s|>)/i', ' ' . AMP_Rule_Spec::DEV_MODE_ATTRIBUTE, $tag );
1506
  }
1507
  return $tag;
@@ -1517,7 +1549,11 @@ class AMP_Theme_Support {
1517
  * @return string Tag.
1518
  */
1519
  public static function filter_admin_bar_script_loader_tag( $tag, $handle ) {
1520
- if ( self::has_dependency( wp_scripts(), $handle, 'admin-bar' ) ) {
 
 
 
 
1521
  $tag = preg_replace( '/(?<=<script)(?=\s|>)/i', ' ' . AMP_Rule_Spec::DEV_MODE_ATTRIBUTE, $tag );
1522
  }
1523
  return $tag;
1468
  return false;
1469
  }
1470
 
1471
+ /**
1472
+ * Check if a handle is exclusively a dependency of another handle.
1473
+ *
1474
+ * For example, check if dashicons is being added exclusively because it is a dependency of admin-bar, as opposed
1475
+ * to being added because it was directly enqueued by a theme or a dependency of some other style.
1476
+ *
1477
+ * @since 1.4.2
1478
+ *
1479
+ * @param WP_Dependencies $dependencies Dependencies.
1480
+ * @param string $dependency_handle Dependency handle.
1481
+ * @param string $dependent_handle Dependent handle.
1482
+ * @return bool Whether the $handle is exclusively a handle of the $exclusive_dependency handle.
1483
+ */
1484
+ protected static function is_exclusively_dependent( WP_Dependencies $dependencies, $dependency_handle, $dependent_handle ) {
1485
+
1486
+ // If a dependency handle is the same as the dependent handle, then this self-referential relationship is exclusive.
1487
+ if ( $dependency_handle === $dependent_handle ) {
1488
+ return true;
1489
+ }
1490
+
1491
+ // Short-circuit if there is no dependency relationship up front.
1492
+ if ( ! self::has_dependency( $dependencies, $dependent_handle, $dependency_handle ) ) {
1493
+ return false;
1494
+ }
1495
+
1496
+ // Check whether any enqueued handle depends on the dependency.
1497
+ foreach ( $dependencies->queue as $queued_handle ) {
1498
+ // Skip considering the dependent handle.
1499
+ if ( $dependent_handle === $queued_handle ) {
1500
+ continue;
1501
+ }
1502
+
1503
+ // If the dependency handle was directly enqueued, then it is not exclusively dependent.
1504
+ if ( $dependency_handle === $queued_handle ) {
1505
+ return false;
1506
+ }
1507
+
1508
+ // Otherwise, if the dependency handle is depended on by the queued handle while at the same time the queued
1509
+ // handle _does_ have a dependency on the supplied dependent handle, then the dependency handle is not
1510
+ // exclusively dependent on the dependent handle.
1511
+ if (
1512
+ self::has_dependency( $dependencies, $queued_handle, $dependency_handle )
1513
+ &&
1514
+ ! self::has_dependency( $dependencies, $queued_handle, $dependent_handle )
1515
+ ) {
1516
+ return false;
1517
+ }
1518
+ }
1519
+ return true;
1520
+ }
1521
+
1522
  /**
1523
  * Add data-ampdevmode attribute to any enqueued style that depends on the admin-bar.
1524
  *
1529
  * @return string Tag.
1530
  */
1531
  public static function filter_admin_bar_style_loader_tag( $tag, $handle ) {
1532
+ if (
1533
+ in_array( $handle, wp_styles()->registered['admin-bar']->deps, true ) ?
1534
+ self::is_exclusively_dependent( wp_styles(), $handle, 'admin-bar' ) :
1535
+ self::has_dependency( wp_styles(), $handle, 'admin-bar' )
1536
+ ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1537
  $tag = preg_replace( '/(?<=<link)(?=\s|>)/i', ' ' . AMP_Rule_Spec::DEV_MODE_ATTRIBUTE, $tag );
1538
  }
1539
  return $tag;
1549
  * @return string Tag.
1550
  */
1551
  public static function filter_admin_bar_script_loader_tag( $tag, $handle ) {
1552
+ if (
1553
+ in_array( $handle, wp_scripts()->registered['admin-bar']->deps, true ) ?
1554
+ self::is_exclusively_dependent( wp_scripts(), $handle, 'admin-bar' ) :
1555
+ self::has_dependency( wp_scripts(), $handle, 'admin-bar' )
1556
+ ) {
1557
  $tag = preg_replace( '/(?<=<script)(?=\s|>)/i', ' ' . AMP_Rule_Spec::DEV_MODE_ATTRIBUTE, $tag );
1558
  }
1559
  return $tag;
includes/options/class-amp-options-manager.php CHANGED
@@ -718,23 +718,9 @@ class AMP_Options_Manager {
718
  $validation = AMP_Validation_Manager::validate_url( $url );
719
 
720
  if ( is_wp_error( $validation ) ) {
721
- $review_messages[] = esc_html(
722
- sprintf(
723
- /* translators: 1: error message. 2: error code. */
724
- __( 'However, there was an error when checking the AMP validity for your site.', 'amp' ),
725
- $validation->get_error_message(),
726
- $validation->get_error_code()
727
- )
728
- );
729
-
730
- $error_message = $validation->get_error_message();
731
- if ( $error_message ) {
732
- $review_messages[] = $error_message;
733
- } else {
734
- /* translators: %s is the error code */
735
- $review_messages[] = esc_html( sprintf( __( 'Error code: %s.', 'amp' ), $validation->get_error_code() ) );
736
- }
737
- $notice_type = 'error';
738
  } elseif ( is_array( $validation ) ) {
739
  $new_errors = 0;
740
  $rejected_errors = 0;
@@ -757,7 +743,7 @@ class AMP_Options_Manager {
757
  if ( $rejected_errors > 0 ) {
758
  $notice_type = 'error';
759
 
760
- $message = wp_kses_post(
761
  sprintf(
762
  /* translators: %s is count of rejected errors */
763
  _n(
@@ -772,43 +758,37 @@ class AMP_Options_Manager {
772
  );
773
 
774
  if ( $invalid_url_screen_url ) {
775
- $message .= ' ' . wp_kses_post(
776
- sprintf(
777
- /* translators: %s is URL to review issues */
778
- _n(
779
- '<a href="%s">Review Issue</a>.',
780
- '<a href="%s">Review Issues</a>.',
781
- $rejected_errors,
782
- 'amp'
783
- ),
784
- esc_url( $invalid_url_screen_url )
785
- )
786
  );
787
  }
788
 
789
  $review_messages[] = $message;
790
  } else {
791
- $message = wp_kses_post(
792
- sprintf(
793
- /* translators: %s is an AMP URL */
794
- __( 'View an <a href="%s">AMP version of your site</a>.', 'amp' ),
795
- esc_url( $url )
796
- )
797
  );
798
 
799
  if ( $new_errors > 0 && $invalid_url_screen_url ) {
800
- $message .= ' ' . wp_kses_post(
801
- sprintf(
802
- /* translators: 1: URL to review issues. 2: count of new errors. */
803
- _n(
804
- 'Please also <a href="%1$s">review %2$s issue</a> which may need to be fixed (for one URL at least).',
805
- 'Please also <a href="%1$s">review %2$s issues</a> which may need to be fixed (for one URL at least).',
806
- $new_errors,
807
- 'amp'
808
- ),
809
- esc_url( $invalid_url_screen_url ),
810
- number_format_i18n( $new_errors )
811
- )
812
  );
813
  }
814
 
@@ -831,18 +811,16 @@ class AMP_Options_Manager {
831
  }
832
  break;
833
  case AMP_Theme_Support::READER_MODE_SLUG:
834
- $message = wp_kses_post(
835
- sprintf(
836
- /* translators: %s is an AMP URL */
837
- __( 'Reader mode activated! View the <a href="%s">AMP version of a recent post</a>. It is recommended that you upgrade to Standard or Transitional mode.', 'amp' ),
838
- esc_url( $url )
839
- )
840
  );
841
  break;
842
  }
843
 
844
  if ( isset( $message ) ) {
845
- add_settings_error( self::OPTION_NAME, 'template_mode_updated', $message, $notice_type );
846
  }
847
  }
848
  }
718
  $validation = AMP_Validation_Manager::validate_url( $url );
719
 
720
  if ( is_wp_error( $validation ) ) {
721
+ $review_messages[] = esc_html__( 'However, there was an error when checking the AMP validity for your site.', 'amp' );
722
+ $review_messages[] = AMP_Validation_Manager::get_validate_url_error_message( $validation->get_error_code(), $validation->get_error_message() );
723
+ $notice_type = 'error';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
724
  } elseif ( is_array( $validation ) ) {
725
  $new_errors = 0;
726
  $rejected_errors = 0;
743
  if ( $rejected_errors > 0 ) {
744
  $notice_type = 'error';
745
 
746
+ $message = esc_html(
747
  sprintf(
748
  /* translators: %s is count of rejected errors */
749
  _n(
758
  );
759
 
760
  if ( $invalid_url_screen_url ) {
761
+ $message .= ' ' . sprintf(
762
+ /* translators: %s is URL to review issues */
763
+ _n(
764
+ '<a href="%s">Review Issue</a>.',
765
+ '<a href="%s">Review Issues</a>.',
766
+ $rejected_errors,
767
+ 'amp'
768
+ ),
769
+ esc_url( $invalid_url_screen_url )
 
 
770
  );
771
  }
772
 
773
  $review_messages[] = $message;
774
  } else {
775
+ $message = sprintf(
776
+ /* translators: %s is an AMP URL */
777
+ __( 'View an <a href="%s">AMP version of your site</a>.', 'amp' ),
778
+ esc_url( $url )
 
 
779
  );
780
 
781
  if ( $new_errors > 0 && $invalid_url_screen_url ) {
782
+ $message .= ' ' . sprintf(
783
+ /* translators: 1: URL to review issues. 2: count of new errors. */
784
+ _n(
785
+ 'Please also <a href="%1$s">review %2$s issue</a> which may need to be fixed (for one URL at least).',
786
+ 'Please also <a href="%1$s">review %2$s issues</a> which may need to be fixed (for one URL at least).',
787
+ $new_errors,
788
+ 'amp'
789
+ ),
790
+ esc_url( $invalid_url_screen_url ),
791
+ number_format_i18n( $new_errors )
 
 
792
  );
793
  }
794
 
811
  }
812
  break;
813
  case AMP_Theme_Support::READER_MODE_SLUG:
814
+ $message = sprintf(
815
+ /* translators: %s is an AMP URL */
816
+ __( 'Reader mode activated! View the <a href="%s">AMP version of a recent post</a>. It is recommended that you upgrade to Standard or Transitional mode.', 'amp' ),
817
+ esc_url( $url )
 
 
818
  );
819
  break;
820
  }
821
 
822
  if ( isset( $message ) ) {
823
+ add_settings_error( self::OPTION_NAME, 'template_mode_updated', wp_kses_post( $message ), $notice_type );
824
  }
825
  }
826
  }
includes/sanitizers/class-amp-core-theme-sanitizer.php CHANGED
@@ -45,161 +45,204 @@ class AMP_Core_Theme_Sanitizer extends AMP_Base_Sanitizer {
45
  protected $xpath;
46
 
47
  /**
48
- * Config for features needed by themes.
49
  *
50
- * @since 1.0
51
  * @var array
52
  */
53
- protected static $theme_features = [
54
- // Twenty Twenty.
55
- 'twentytwenty' => [
56
- 'dequeue_scripts' => [
57
- 'twentytwenty-js',
58
- ],
59
- 'remove_actions' => [
60
- 'wp_head' => [
61
- 'twentytwenty_no_js_class', // AMP is essentially no-js, with any interactivity added explicitly via amp-bind.
62
- ],
63
- 'wp_print_footer_scripts' => [
64
- 'twentytwenty_skip_link_focus_fix', // See <https://github.com/WordPress/twentynineteen/pull/47>.
65
- ],
66
- ],
67
- 'add_smooth_scrolling' => [
68
- // @todo Only replaces twentytwenty.smoothscroll.scrollToAnchor, but not twentytwenty.smoothscroll.scrollToElement
69
- '//a[ starts-with( @href, "#" ) and not( @href = "#" )and not( @href = "#0" ) and not( contains( @class, "do-not-scroll" ) ) and not( contains( @class, "skip-link" ) ) ]',
70
- ],
71
- 'add_twentytwenty_modals' => [],
72
- 'add_twentytwenty_toggles' => [],
73
- 'add_nav_menu_styles' => [],
74
- 'add_twentytwenty_masthead_styles' => [],
75
- 'add_twentytwenty_current_page_awareness' => [],
76
- ],
77
-
78
- // Twenty Nineteen.
79
- 'twentynineteen' => [
80
- 'dequeue_scripts' => [
81
- 'twentynineteen-skip-link-focus-fix', // This is part of AMP. See <https://github.com/ampproject/amphtml/issues/18671>.
82
- 'twentynineteen-priority-menu',
83
- 'twentynineteen-touch-navigation', // @todo There could be an AMP implementation of this, similar to what is implemented on ampproject.org.
84
- ],
85
- 'remove_actions' => [
86
- 'wp_print_footer_scripts' => [
87
- 'twentynineteen_skip_link_focus_fix', // See <https://github.com/WordPress/twentynineteen/pull/47>.
88
- ],
89
- ],
90
- 'add_twentynineteen_masthead_styles' => [],
91
- 'adjust_twentynineteen_images' => [],
92
- ],
93
-
94
- // Twenty Seventeen.
95
- 'twentyseventeen' => [
96
- // @todo Try to implement belowEntryMetaClass().
97
- 'dequeue_scripts' => [
98
- 'twentyseventeen-html5', // Only relevant for IE<9.
99
- 'twentyseventeen-global', // There are somethings not yet implemented in AMP. See todos below.
100
- 'jquery-scrollto', // Implemented via add_smooth_scrolling().
101
- 'twentyseventeen-navigation', // Handled by add_nav_menu_styles, add_nav_menu_toggle, add_nav_sub_menu_buttons.
102
- 'twentyseventeen-skip-link-focus-fix', // Unnecessary since part of the AMP runtime.
103
- ],
104
- 'remove_actions' => [
105
- 'wp_head' => [
106
- 'twentyseventeen_javascript_detection', // AMP is essentially no-js, with any interactivity added explicitly via amp-bind.
107
- ],
108
- ],
109
- 'force_fixed_background_support' => [],
110
- 'add_twentyseventeen_masthead_styles' => [],
111
- 'add_twentyseventeen_image_styles' => [],
112
- 'add_twentyseventeen_sticky_nav_menu' => [],
113
- 'add_has_header_video_body_class' => [],
114
- 'add_nav_menu_styles' => [
115
- 'sub_menu_button_toggle_class' => 'toggled-on',
116
- 'no_js_submenu_visible' => true,
117
- ],
118
- 'add_smooth_scrolling' => [
119
- '//header[@id = "masthead"]//a[ contains( @class, "menu-scroll-down" ) ]',
120
- ],
121
- 'set_twentyseventeen_quotes_icon' => [],
122
- 'add_twentyseventeen_attachment_image_attributes' => [],
123
- ],
124
-
125
- // Twenty Sixteen.
126
- 'twentysixteen' => [
127
- // @todo Figure out an AMP solution for onResizeARIA().
128
- // @todo Try to implement belowEntryMetaClass().
129
- 'dequeue_scripts' => [
130
- 'twentysixteen-script',
131
- 'twentysixteen-html5', // Only relevant for IE<9.
132
- 'twentysixteen-keyboard-image-navigation', // AMP does not yet allow for listening to keydown events.
133
- 'twentysixteen-skip-link-focus-fix', // Unnecessary since part of the AMP runtime.
134
- ],
135
- 'remove_actions' => [
136
- 'wp_head' => [
137
- 'twentysixteen_javascript_detection', // AMP is essentially no-js, with any interactivity added explicitly via amp-bind.
138
- ],
139
- ],
140
- 'add_nav_menu_styles' => [
141
- 'sub_menu_button_toggle_class' => 'toggled-on',
142
- 'no_js_submenu_visible' => true,
143
- ],
144
- ],
145
-
146
- // Twenty Fifteen.
147
- 'twentyfifteen' => [
148
- // @todo Figure out an AMP solution for onResizeARIA().
149
- 'dequeue_scripts' => [
150
- 'twentyfifteen-script',
151
- 'twentyfifteen-keyboard-image-navigation', // AMP does not yet allow for listening to keydown events.
152
- 'twentyfifteen-skip-link-focus-fix', // Unnecessary since part of the AMP runtime.
153
- ],
154
- 'remove_actions' => [
155
- 'wp_head' => [
156
- 'twentyfifteen_javascript_detection', // AMP is essentially no-js, with any interactivity added explicitly via amp-bind.
157
- ],
158
- ],
159
- 'add_nav_menu_styles' => [
160
- 'sub_menu_button_toggle_class' => 'toggle-on',
161
- 'no_js_submenu_visible' => true,
162
- ],
163
- ],
164
-
165
- // Twenty Fourteen.
166
- 'twentyfourteen' => [
167
- // @todo Figure out an AMP solution for onResizeARIA().
168
- 'dequeue_scripts' => [
169
- 'twentyfourteen-script',
170
- 'twentyfourteen-keyboard-image-navigation', // AMP does not yet allow for listening to keydown events.
171
- 'jquery-masonry', // Masonry style layout is not supported in AMP.
172
- 'twentyfourteen-slider',
173
- ],
174
- 'add_nav_menu_styles' => [],
175
- 'add_twentyfourteen_masthead_styles' => [],
176
- 'add_twentyfourteen_slider_carousel' => [],
177
- 'add_twentyfourteen_search' => [],
178
- ],
179
-
180
- // Twenty Thirteen.
181
- 'twentythirteen' => [
182
- 'dequeue_scripts' => [
183
- 'jquery-masonry', // Masonry style layout is not supported in AMP.
184
- 'twentythirteen-script',
185
- ],
186
- 'add_nav_menu_toggle' => [],
187
- 'add_nav_sub_menu_buttons' => [],
188
- 'add_nav_menu_styles' => [],
189
- ],
190
-
191
- // Twenty Twelve.
192
- 'twentytwelve' => [
193
- 'dequeue_scripts' => [
194
- 'twentytwelve-navigation',
195
- ],
196
- 'add_nav_menu_styles' => [],
197
- ],
198
-
199
- 'twentyeleven' => [],
200
- 'twentyten' => [],
201
  ];
202
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
  /**
204
  * Get list of supported core themes.
205
  *
@@ -208,7 +251,7 @@ class AMP_Core_Theme_Sanitizer extends AMP_Base_Sanitizer {
208
  * @return string[] Slugs for supported themes.
209
  */
210
  public static function get_supported_themes() {
211
- return array_keys( self::$theme_features );
212
  }
213
 
214
  /**
@@ -220,7 +263,7 @@ class AMP_Core_Theme_Sanitizer extends AMP_Base_Sanitizer {
220
  * @return array Acceptable errors.
221
  */
222
  public static function get_acceptable_errors( $template ) {
223
- if ( isset( self::$theme_features[ $template ] ) ) {
224
  return [
225
  'illegal_css_at_rule' => [
226
  [
@@ -399,8 +442,8 @@ class AMP_Core_Theme_Sanitizer extends AMP_Base_Sanitizer {
399
  $theme_features = [];
400
  $theme_candidates = wp_array_slice_assoc( $args, [ 'stylesheet', 'template' ] );
401
  foreach ( $theme_candidates as $theme_candidate ) {
402
- if ( isset( self::$theme_features[ $theme_candidate ] ) ) {
403
- $theme_features = self::$theme_features[ $theme_candidate ];
404
  break;
405
  }
406
  }
@@ -1030,6 +1073,12 @@ class AMP_Core_Theme_Sanitizer extends AMP_Base_Sanitizer {
1030
  }
1031
  }
1032
 
 
 
 
 
 
 
1033
  }
1034
  <?php elseif ( 'twentyseventeen' === get_template() ) : ?>
1035
  /* Show the button*/
45
  protected $xpath;
46
 
47
  /**
48
+ * Array of themes that are supported.
49
  *
 
50
  * @var array
51
  */
52
+ protected static $supported_themes = [
53
+ 'twentytwenty',
54
+ 'twentynineteen',
55
+ 'twentyseventeen',
56
+ 'twentysixteen',
57
+ 'twentyfifteen',
58
+ 'twentyfourteen',
59
+ 'twentythirteen',
60
+ 'twentytwelve',
61
+ 'twentyeleven',
62
+ 'twentyten',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  ];
64
 
65
+ /**
66
+ * Retrieve the config for features needed by a theme.
67
+ *
68
+ * @since 1.0
69
+ * @since 1.5.0 Converted `theme_features` variable into `get_theme_config` function.
70
+ *
71
+ * @param string $theme_slug Theme slug.
72
+ * @return array|null Array comprising of the theme config if its slug is found, null if it is not.
73
+ */
74
+ protected static function get_theme_features_config( $theme_slug ) {
75
+ switch ( $theme_slug ) {
76
+ // Twenty Twenty.
77
+ case 'twentytwenty':
78
+ $config = [
79
+ 'dequeue_scripts' => [
80
+ 'twentytwenty-js',
81
+ ],
82
+ 'remove_actions' => [
83
+ 'wp_head' => [
84
+ 'twentytwenty_no_js_class', // AMP is essentially no-js, with any interactivity added explicitly via amp-bind.
85
+ ],
86
+ 'wp_print_footer_scripts' => [
87
+ 'twentytwenty_skip_link_focus_fix', // See <https://github.com/WordPress/twentynineteen/pull/47>.
88
+ ],
89
+ ],
90
+ 'add_twentytwenty_modals' => [],
91
+ 'add_twentytwenty_toggles' => [],
92
+ 'add_nav_menu_styles' => [],
93
+ 'add_twentytwenty_masthead_styles' => [],
94
+ 'add_twentytwenty_current_page_awareness' => [],
95
+ ];
96
+
97
+ $theme = wp_get_theme( 'twentytwenty' );
98
+
99
+ if ( $theme->exists() && version_compare( $theme->get( 'Version' ), '1.0.0', '<=' ) ) {
100
+ $config['add_smooth_scrolling'] = [
101
+ '//a[ starts-with( @href, "#" ) and not( @href = "#" )and not( @href = "#0" ) and not( contains( @class, "do-not-scroll" ) ) and not( contains( @class, "skip-link" ) ) ]',
102
+ ];
103
+ }
104
+
105
+ return $config;
106
+
107
+ // Twenty Nineteen.
108
+ case 'twentynineteen':
109
+ return [
110
+ 'dequeue_scripts' => [
111
+ 'twentynineteen-skip-link-focus-fix', // This is part of AMP. See <https://github.com/ampproject/amphtml/issues/18671>.
112
+ 'twentynineteen-priority-menu',
113
+ 'twentynineteen-touch-navigation', // @todo There could be an AMP implementation of this, similar to what is implemented on ampproject.org.
114
+ ],
115
+ 'remove_actions' => [
116
+ 'wp_print_footer_scripts' => [
117
+ 'twentynineteen_skip_link_focus_fix', // See <https://github.com/WordPress/twentynineteen/pull/47>.
118
+ ],
119
+ ],
120
+ 'add_twentynineteen_masthead_styles' => [],
121
+ 'adjust_twentynineteen_images' => [],
122
+ ];
123
+
124
+ // Twenty Seventeen.
125
+ case 'twentyseventeen':
126
+ return [
127
+ // @todo Try to implement belowEntryMetaClass().
128
+ 'dequeue_scripts' => [
129
+ 'twentyseventeen-html5', // Only relevant for IE<9.
130
+ 'twentyseventeen-global', // There are somethings not yet implemented in AMP. See todos below.
131
+ 'jquery-scrollto', // Implemented via add_smooth_scrolling().
132
+ 'twentyseventeen-navigation', // Handled by add_nav_menu_styles, add_nav_menu_toggle, add_nav_sub_menu_buttons.
133
+ 'twentyseventeen-skip-link-focus-fix', // Unnecessary since part of the AMP runtime.
134
+ ],
135
+ 'remove_actions' => [
136
+ 'wp_head' => [
137
+ 'twentyseventeen_javascript_detection', // AMP is essentially no-js, with any interactivity added explicitly via amp-bind.
138
+ ],
139
+ ],
140
+ 'force_fixed_background_support' => [],
141
+ 'add_twentyseventeen_masthead_styles' => [],
142
+ 'add_twentyseventeen_image_styles' => [],
143
+ 'add_twentyseventeen_sticky_nav_menu' => [],
144
+ 'add_has_header_video_body_class' => [],
145
+ 'add_nav_menu_styles' => [
146
+ 'sub_menu_button_toggle_class' => 'toggled-on',
147
+ 'no_js_submenu_visible' => true,
148
+ ],
149
+ 'add_smooth_scrolling' => [
150
+ '//header[@id = "masthead"]//a[ contains( @class, "menu-scroll-down" ) ]',
151
+ ],
152
+ 'set_twentyseventeen_quotes_icon' => [],
153
+ 'add_twentyseventeen_attachment_image_attributes' => [],
154
+ ];
155
+
156
+ // Twenty Sixteen.
157
+ case 'twentysixteen':
158
+ return [
159
+ // @todo Figure out an AMP solution for onResizeARIA().
160
+ // @todo Try to implement belowEntryMetaClass().
161
+ 'dequeue_scripts' => [
162
+ 'twentysixteen-script',
163
+ 'twentysixteen-html5', // Only relevant for IE<9.
164
+ 'twentysixteen-keyboard-image-navigation', // AMP does not yet allow for listening to keydown events.
165
+ 'twentysixteen-skip-link-focus-fix', // Unnecessary since part of the AMP runtime.
166
+ ],
167
+ 'remove_actions' => [
168
+ 'wp_head' => [
169
+ 'twentysixteen_javascript_detection', // AMP is essentially no-js, with any interactivity added explicitly via amp-bind.
170
+ ],
171
+ ],
172
+ 'add_nav_menu_styles' => [
173
+ 'sub_menu_button_toggle_class' => 'toggled-on',
174
+ 'no_js_submenu_visible' => true,
175
+ ],
176
+ ];
177
+
178
+ // Twenty Fifteen.
179
+ case 'twentyfifteen':
180
+ return [
181
+ // @todo Figure out an AMP solution for onResizeARIA().
182
+ 'dequeue_scripts' => [
183
+ 'twentyfifteen-script',
184
+ 'twentyfifteen-keyboard-image-navigation', // AMP does not yet allow for listening to keydown events.
185
+ 'twentyfifteen-skip-link-focus-fix', // Unnecessary since part of the AMP runtime.
186
+ ],
187
+ 'remove_actions' => [
188
+ 'wp_head' => [
189
+ 'twentyfifteen_javascript_detection', // AMP is essentially no-js, with any interactivity added explicitly via amp-bind.
190
+ ],
191
+ ],
192
+ 'add_nav_menu_styles' => [
193
+ 'sub_menu_button_toggle_class' => 'toggle-on',
194
+ 'no_js_submenu_visible' => true,
195
+ ],
196
+ ];
197
+
198
+ // Twenty Fourteen.
199
+ case 'twentyfourteen':
200
+ return [
201
+ // @todo Figure out an AMP solution for onResizeARIA().
202
+ 'dequeue_scripts' => [
203
+ 'twentyfourteen-script',
204
+ 'twentyfourteen-keyboard-image-navigation', // AMP does not yet allow for listening to keydown events.
205
+ 'jquery-masonry', // Masonry style layout is not supported in AMP.
206
+ 'twentyfourteen-slider',
207
+ ],
208
+ 'add_nav_menu_styles' => [],
209
+ 'add_twentyfourteen_masthead_styles' => [],
210
+ 'add_twentyfourteen_slider_carousel' => [],
211
+ 'add_twentyfourteen_search' => [],
212
+ ];
213
+
214
+ // Twenty Thirteen.
215
+ case 'twentythirteen':
216
+ return [
217
+ 'dequeue_scripts' => [
218
+ 'jquery-masonry', // Masonry style layout is not supported in AMP.
219
+ 'twentythirteen-script',
220
+ ],
221
+ 'add_nav_menu_toggle' => [],
222
+ 'add_nav_sub_menu_buttons' => [],
223
+ 'add_nav_menu_styles' => [],
224
+ ];
225
+
226
+ // Twenty Twelve.
227
+ case 'twentytwelve':
228
+ return [
229
+ 'dequeue_scripts' => [
230
+ 'twentytwelve-navigation',
231
+ ],
232
+ 'add_nav_menu_styles' => [],
233
+ ];
234
+
235
+ // Twenty Eleven.
236
+ case 'twentyeleven':
237
+ // Twenty Ten.
238
+ case 'twentyten':
239
+ return [];
240
+
241
+ default:
242
+ return null;
243
+ }
244
+ }
245
+
246
  /**
247
  * Get list of supported core themes.
248
  *
251
  * @return string[] Slugs for supported themes.
252
  */
253
  public static function get_supported_themes() {
254
+ return self::$supported_themes;
255
  }
256
 
257
  /**
263
  * @return array Acceptable errors.
264
  */
265
  public static function get_acceptable_errors( $template ) {
266
+ if ( in_array( $template, self::$supported_themes, true ) ) {
267
  return [
268
  'illegal_css_at_rule' => [
269
  [
442
  $theme_features = [];
443
  $theme_candidates = wp_array_slice_assoc( $args, [ 'stylesheet', 'template' ] );
444
  foreach ( $theme_candidates as $theme_candidate ) {
445
+ if ( in_array( $theme_candidate, self::$supported_themes, true ) ) {
446
+ $theme_features = self::get_theme_features_config( $theme_candidate );
447
  break;
448
  }
449
  }
1073
  }
1074
  }
1075
 
1076
+ @media (max-width: 999px) {
1077
+ amp-lightbox.cover-modal.show-modal {
1078
+ display: unset;
1079
+ }
1080
+ }
1081
+
1082
  }
1083
  <?php elseif ( 'twentyseventeen' === get_template() ) : ?>
1084
  /* Show the button*/
includes/sanitizers/class-amp-style-sanitizer.php CHANGED
@@ -1393,7 +1393,7 @@ class AMP_Style_Sanitizer extends AMP_Base_Sanitizer {
1393
  private function process_stylesheet( $stylesheet, $options = [] ) {
1394
  $parsed = null;
1395
  $cache_key = null;
1396
- $cache_group = 'amp-parsed-stylesheet-v21'; // This should be bumped whenever the PHP-CSS-Parser is updated or parsed format is updated.
1397
 
1398
  $cache_impacting_options = array_merge(
1399
  wp_array_slice_assoc(
@@ -2268,9 +2268,21 @@ class AMP_Style_Sanitizer extends AMP_Base_Sanitizer {
2268
  if ( ! is_wp_error( $path ) ) {
2269
  $data_url->getURL()->setString( $guessed_url );
2270
  $converted_count++;
2271
- break;
2272
  }
2273
  }
 
 
 
 
 
 
 
 
 
 
 
 
2274
  } // End foreach $source_data_url_objects.
2275
  } // End foreach $src_properties.
2276
 
1393
  private function process_stylesheet( $stylesheet, $options = [] ) {
1394
  $parsed = null;
1395
  $cache_key = null;
1396
+ $cache_group = 'amp-parsed-stylesheet-v22'; // This should be bumped whenever the PHP-CSS-Parser is updated or parsed format is updated.
1397
 
1398
  $cache_impacting_options = array_merge(
1399
  wp_array_slice_assoc(
2268
  if ( ! is_wp_error( $path ) ) {
2269
  $data_url->getURL()->setString( $guessed_url );
2270
  $converted_count++;
2271
+ continue 2;
2272
  }
2273
  }
2274
+
2275
+ // As fallback, look for fonts bundled with the AMP plugin.
2276
+ $font_filename = sprintf( '%s.%s', strtolower( $font_basename ), $extension );
2277
+ $bundled_fonts = [
2278
+ 'nonbreakingspaceoverride.woff',
2279
+ 'nonbreakingspaceoverride.woff2',
2280
+ 'genericons.woff',
2281
+ ];
2282
+ if ( in_array( $font_filename, $bundled_fonts, true ) ) {
2283
+ $data_url->getURL()->setString( plugin_dir_url( AMP__FILE__ ) . "assets/fonts/$font_filename" );
2284
+ $converted_count++;
2285
+ }
2286
  } // End foreach $source_data_url_objects.
2287
  } // End foreach $src_properties.
2288
 
includes/sanitizers/class-amp-tag-and-attribute-sanitizer.php CHANGED
@@ -1695,18 +1695,16 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
1695
  * https://github.com/ampproject/amphtml/blob/1526498116488/extensions/amp-selector/validator-amp-selector.protoascii#L81-L91
1696
  */
1697
  $descendant_reference_points = [
1698
- 'amp-selector' => AMP_Allowed_Tags_Generated::get_reference_point_spec( 'AMP-SELECTOR option' ),
1699
- 'amp-story-grid-layer' => AMP_Allowed_Tags_Generated::get_reference_point_spec( 'AMP-STORY-GRID-LAYER default' ), // @todo Consider the more restrictive 'AMP-STORY-GRID-LAYER animate-in'.
1700
  ];
1701
- foreach ( $descendant_reference_points as $ancestor_name => $reference_point_spec ) {
 
 
 
 
1702
  if ( isset( $reference_point_spec[ AMP_Rule_Spec::ATTR_SPEC_LIST ][ $attr_name ] ) ) {
1703
- $parent = $attr_node->parentNode;
1704
- while ( $parent ) {
1705
- if ( $ancestor_name === $parent->nodeName ) {
1706
- return true;
1707
- }
1708
- $parent = $parent->parentNode;
1709
- }
1710
  }
1711
  }
1712
 
1695
  * https://github.com/ampproject/amphtml/blob/1526498116488/extensions/amp-selector/validator-amp-selector.protoascii#L81-L91
1696
  */
1697
  $descendant_reference_points = [
1698
+ 'amp-selector' => 'AMP-SELECTOR option',
1699
+ 'amp-story-grid-layer' => 'AMP-STORY-GRID-LAYER default', // @todo Consider the more restrictive 'AMP-STORY-GRID-LAYER animate-in'.
1700
  ];
1701
+ foreach ( $descendant_reference_points as $ancestor_name => $reference_point_spec_name ) {
1702
+ if ( empty( $this->open_elements[ $ancestor_name ] ) ) {
1703
+ continue;
1704
+ }
1705
+ $reference_point_spec = AMP_Allowed_Tags_Generated::get_reference_point_spec( $reference_point_spec_name );
1706
  if ( isset( $reference_point_spec[ AMP_Rule_Spec::ATTR_SPEC_LIST ][ $attr_name ] ) ) {
1707
+ return true;
 
 
 
 
 
 
1708
  }
1709
  }
1710
 
includes/validation/class-amp-validated-url-post-type.php CHANGED
@@ -631,17 +631,13 @@ class AMP_Validated_URL_Post_Type {
631
  /**
632
  * Normalize a URL for storage.
633
  *
634
- * This ensures that query vars like utm_* and the like will not cause duplicates.
635
  * The AMP query param is removed to facilitate switching between standard and transitional.
636
  * The URL scheme is also normalized to HTTPS to help with transition from HTTP to HTTPS.
637
  *
638
  * @param string $url URL.
639
  * @return string Normalized URL.
640
- * @global WP $wp
641
  */
642
  protected static function normalize_url_for_storage( $url ) {
643
- global $wp;
644
-
645
  // Only ever store the canonical version.
646
  $url = amp_remove_endpoint( $url );
647
 
@@ -651,12 +647,11 @@ class AMP_Validated_URL_Post_Type {
651
  // Normalize query args, removing all that are not recognized or which are removable.
652
  $url_parts = explode( '?', $url, 2 );
653
  if ( 2 === count( $url_parts ) ) {
654
- parse_str( $url_parts[1], $args );
655
  foreach ( wp_removable_query_args() as $removable_query_arg ) {
656
  unset( $args[ $removable_query_arg ] );
657
  }
658
- $args = wp_array_slice_assoc( $args, $wp->public_query_vars );
659
- $url = $url_parts[0];
660
  if ( ! empty( $args ) ) {
661
  $url = $url_parts[0] . '?' . build_query( $args );
662
  }
@@ -1231,7 +1226,7 @@ class AMP_Validated_URL_Post_Type {
1231
 
1232
  $validity = AMP_Validation_Manager::validate_url( $url );
1233
  if ( is_wp_error( $validity ) ) {
1234
- $errors[] = $validity->get_error_code();
1235
  continue;
1236
  }
1237
 
@@ -1259,13 +1254,13 @@ class AMP_Validated_URL_Post_Type {
1259
  self::URLS_TESTED => count( $items ),
1260
  ];
1261
  if ( ! empty( $errors ) ) {
1262
- $args['amp_validate_error'] = $errors;
1263
  } else {
1264
  $args[ self::REMAINING_ERRORS ] = count( $remaining_invalid_urls );
1265
  }
1266
 
1267
  $redirect = remove_query_arg( wp_removable_query_args(), $redirect );
1268
- return add_query_arg( $args, $redirect );
1269
  }
1270
 
1271
  /**
@@ -1278,14 +1273,23 @@ class AMP_Validated_URL_Post_Type {
1278
  return;
1279
  }
1280
 
1281
- if ( isset( $_GET['amp_validate_error'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1282
- $error_codes = array_unique( array_map( 'sanitize_key', (array) $_GET['amp_validate_error'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1283
- foreach ( $error_codes as $error_code ) {
1284
- printf(
1285
- '<div class="notice is-dismissible error"><p>%s</p><button type="button" class="notice-dismiss"><span class="screen-reader-text">%s</span></button></div>',
1286
- esc_html( AMP_Validation_Manager::get_validate_url_error_message( $error_code ) ),
1287
- esc_html__( 'Dismiss this notice.', 'amp' )
1288
- );
 
 
 
 
 
 
 
 
 
1289
  }
1290
  }
1291
 
@@ -1487,7 +1491,7 @@ class AMP_Validated_URL_Post_Type {
1487
 
1488
  $validity = AMP_Validation_Manager::validate_url( $url );
1489
  if ( is_wp_error( $validity ) ) {
1490
- throw new Exception( esc_html( $validity->get_error_code() ) );
1491
  }
1492
 
1493
  $errors = wp_list_pluck( $validity['results'], 'error' );
@@ -1502,7 +1506,7 @@ class AMP_Validated_URL_Post_Type {
1502
  )
1503
  );
1504
  if ( is_wp_error( $stored ) ) {
1505
- throw new Exception( esc_html( $stored->get_error_code() ) );
1506
  }
1507
  $redirect = get_edit_post_link( $stored, 'raw' );
1508
 
@@ -1518,7 +1522,9 @@ class AMP_Validated_URL_Post_Type {
1518
  $args[ self::URLS_TESTED ] = '1';
1519
  $args[ self::REMAINING_ERRORS ] = $error_count;
1520
  } catch ( Exception $e ) {
1521
- $args['amp_validate_error'] = $e->getMessage();
 
 
1522
  $args[ self::URLS_TESTED ] = '0';
1523
 
1524
  if ( $post && self::POST_TYPE_SLUG === $post->post_type ) {
@@ -1533,7 +1539,7 @@ class AMP_Validated_URL_Post_Type {
1533
  }
1534
  }
1535
 
1536
- wp_safe_redirect( add_query_arg( $args, $redirect ) );
1537
  exit();
1538
  }
1539
 
@@ -2073,7 +2079,7 @@ class AMP_Validated_URL_Post_Type {
2073
  }
2074
 
2075
  return wp_nonce_url(
2076
- add_query_arg( $args, admin_url() ),
2077
  self::NONCE_ACTION
2078
  );
2079
  }
631
  /**
632
  * Normalize a URL for storage.
633
  *
 
634
  * The AMP query param is removed to facilitate switching between standard and transitional.
635
  * The URL scheme is also normalized to HTTPS to help with transition from HTTP to HTTPS.
636
  *
637
  * @param string $url URL.
638
  * @return string Normalized URL.
 
639
  */
640
  protected static function normalize_url_for_storage( $url ) {
 
 
641
  // Only ever store the canonical version.
642
  $url = amp_remove_endpoint( $url );
643
 
647
  // Normalize query args, removing all that are not recognized or which are removable.
648
  $url_parts = explode( '?', $url, 2 );
649
  if ( 2 === count( $url_parts ) ) {
650
+ $args = wp_parse_args( $url_parts[1] );
651
  foreach ( wp_removable_query_args() as $removable_query_arg ) {
652
  unset( $args[ $removable_query_arg ] );
653
  }
654
+ $url = $url_parts[0];
 
655
  if ( ! empty( $args ) ) {
656
  $url = $url_parts[0] . '?' . build_query( $args );
657
  }
1226
 
1227
  $validity = AMP_Validation_Manager::validate_url( $url );
1228
  if ( is_wp_error( $validity ) ) {
1229
+ $errors[] = AMP_Validation_Manager::get_validate_url_error_message( $validity->get_error_code(), $validity->get_error_message() );
1230
  continue;
1231
  }
1232
 
1254
  self::URLS_TESTED => count( $items ),
1255
  ];
1256
  if ( ! empty( $errors ) ) {
1257
+ $args['amp_validate_error'] = AMP_Validation_Manager::serialize_validation_error_messages( $errors );
1258
  } else {
1259
  $args[ self::REMAINING_ERRORS ] = count( $remaining_invalid_urls );
1260
  }
1261
 
1262
  $redirect = remove_query_arg( wp_removable_query_args(), $redirect );
1263
+ return add_query_arg( rawurlencode_deep( $args ), $redirect );
1264
  }
1265
 
1266
  /**
1273
  return;
1274
  }
1275
 
1276
+ if ( isset( $_GET['amp_validate_error'] ) && is_string( $_GET['amp_validate_error'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1277
+ // Note: The input var is validated by the unserialize_validation_error_messages method.
1278
+ $errors = AMP_Validation_Manager::unserialize_validation_error_messages( wp_unslash( $_GET['amp_validate_error'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1279
+ if ( $errors ) {
1280
+ foreach ( array_unique( $errors ) as $error_message ) {
1281
+ printf(
1282
+ '<div class="notice is-dismissible error"><p>%s</p><button type="button" class="notice-dismiss"><span class="screen-reader-text">%s</span></button></div>',
1283
+ wp_kses(
1284
+ $error_message,
1285
+ [
1286
+ 'a' => array_fill_keys( [ 'href', 'target' ], true ),
1287
+ 'code' => [],
1288
+ ]
1289
+ ),
1290
+ esc_html__( 'Dismiss this notice.', 'amp' )
1291
+ );
1292
+ }
1293
  }
1294
  }
1295
 
1491
 
1492
  $validity = AMP_Validation_Manager::validate_url( $url );
1493
  if ( is_wp_error( $validity ) ) {
1494
+ throw new Exception( AMP_Validation_Manager::get_validate_url_error_message( $validity->get_error_code(), $validity->get_error_message() ) );
1495
  }
1496
 
1497
  $errors = wp_list_pluck( $validity['results'], 'error' );
1506
  )
1507
  );
1508
  if ( is_wp_error( $stored ) ) {
1509
+ throw new Exception( AMP_Validation_Manager::get_validate_url_error_message( $stored->get_error_code(), $stored->get_error_message() ) );
1510
  }
1511
  $redirect = get_edit_post_link( $stored, 'raw' );
1512
 
1522
  $args[ self::URLS_TESTED ] = '1';
1523
  $args[ self::REMAINING_ERRORS ] = $error_count;
1524
  } catch ( Exception $e ) {
1525
+ $args['amp_validate_error'] = AMP_Validation_Manager::serialize_validation_error_messages(
1526
+ [ $e->getMessage() ]
1527
+ );
1528
  $args[ self::URLS_TESTED ] = '0';
1529
 
1530
  if ( $post && self::POST_TYPE_SLUG === $post->post_type ) {
1539
  }
1540
  }
1541
 
1542
+ wp_safe_redirect( add_query_arg( rawurlencode_deep( $args ), $redirect ) );
1543
  exit();
1544
  }
1545
 
2079
  }
2080
 
2081
  return wp_nonce_url(
2082
+ add_query_arg( rawurlencode_deep( $args ), admin_url() ),
2083
  self::NONCE_ACTION
2084
  );
2085
  }
includes/validation/class-amp-validation-manager.php CHANGED
@@ -1874,17 +1874,14 @@ class AMP_Validation_Manager {
1874
 
1875
  $response = wp_remote_retrieve_body( $r );
1876
  if ( trim( $response ) === '' ) {
1877
- $error_code = 'white_screen_of_death';
1878
- return new WP_Error( $error_code, self::get_validate_url_error_message( $error_code ) );
1879
  }
1880
  if ( ! preg_match( '#</body>.*?<!--\s*AMP_VALIDATION\s*:\s*(\{.*?\})\s*-->#s', $response, $matches ) ) {
1881
- $error_code = 'response_comment_absent';
1882
- return new WP_Error( $error_code, self::get_validate_url_error_message( $error_code ) );
1883
  }
1884
  $validation = json_decode( $matches[1], true );
1885
  if ( json_last_error() || ! isset( $validation['results'] ) || ! is_array( $validation['results'] ) ) {
1886
- $error_code = 'malformed_json_validation_errors';
1887
- return new WP_Error( $error_code, self::get_validate_url_error_message( $error_code ) );
1888
  }
1889
 
1890
  return array_merge(
@@ -1893,38 +1890,105 @@ class AMP_Validation_Manager {
1893
  );
1894
  }
1895
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1896
  /**
1897
  * Get error message for a validate URL failure.
1898
  *
1899
- * @param string $error_code Error code.
1900
- * @return string Error message.
 
1901
  */
1902
- public static function get_validate_url_error_message( $error_code ) {
1903
- $check_error_log = __( 'Please check your server\'s PHP error logs; to do this you may need to enable WP_DEBUG_LOG.', 'amp' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1904
  switch ( $error_code ) {
1905
  case 'http_request_failed':
1906
- return __( 'Failed to fetch URL(s) to validate. This may be due to a request timeout.', 'amp' ) . ' ' . $check_error_log;
1907
  case 'white_screen_of_death':
1908
- return __( 'Unable to validate URL. Encountered a white screen of death likely due to a fatal error.', 'amp' ) . ' ' . $check_error_log;
1909
  case '404':
1910
- return __( 'The fetched URL was not found. It may have been deleted. If so, you can trash this.', 'amp' );
1911
  case '500':
1912
- return __( 'An internal server error occurred when fetching the URL for validation.', 'amp' ) . ' ' . $check_error_log;
1913
  case 'response_comment_absent':
1914
  return sprintf(
1915
- /* translators: %s: AMP_VALIDATION */
1916
- __( 'URL validation failed to due to the absence of the expected JSON-containing %s comment after the body. This is often due to a PHP fatal error occurring.', 'amp' ),
1917
- 'AMP_VALIDATION'
1918
- ) . ' ' . $check_error_log;
 
1919
  case 'malformed_json_validation_errors':
1920
  return sprintf(
1921
- /* translators: %s: AMP_VALIDATION */
1922
- __( 'URL validation failed to due to unexpected JSON in the %s comment after the body.', 'amp' ),
1923
- 'AMP_VALIDATION'
1924
- );
 
1925
  default:
1926
  /* translators: %s is error code */
1927
- return sprintf( __( 'URL validation failed. Error code: %s.', 'amp' ), $error_code ); // Note that $error_code has been sanitized with sanitize_key(); will be escaped below as well.
1928
  }
1929
  }
1930
 
1874
 
1875
  $response = wp_remote_retrieve_body( $r );
1876
  if ( trim( $response ) === '' ) {
1877
+ return new WP_Error( 'white_screen_of_death' );
 
1878
  }
1879
  if ( ! preg_match( '#</body>.*?<!--\s*AMP_VALIDATION\s*:\s*(\{.*?\})\s*-->#s', $response, $matches ) ) {
1880
+ return new WP_Error( 'response_comment_absent' );
 
1881
  }
1882
  $validation = json_decode( $matches[1], true );
1883
  if ( json_last_error() || ! isset( $validation['results'] ) || ! is_array( $validation['results'] ) ) {
1884
+ return new WP_Error( 'malformed_json_validation_errors' );
 
1885
  }
1886
 
1887
  return array_merge(
1890
  );
1891
  }
1892
 
1893
+ /**
1894
+ * Serialize validation error messages.
1895
+ *
1896
+ * In order to safely pass validation error messages through redirects with query parameters, they must be serialized
1897
+ * with a HMAC for security. The messages contain markup so the HMAC prevents tampering.
1898
+ *
1899
+ * @since 1.4.2
1900
+ * @see AMP_Validation_Manager::unserialize_validation_error_messages()
1901
+ *
1902
+ * @param string[] $messages Messages.
1903
+ * @return string Serialized.
1904
+ */
1905
+ public static function serialize_validation_error_messages( $messages ) {
1906
+ $encoded_messages = base64_encode( wp_json_encode( array_unique( $messages ) ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
1907
+ return wp_hash( $encoded_messages ) . ':' . $encoded_messages;
1908
+ }
1909
+
1910
+ /**
1911
+ * Unserialize validation error messages.
1912
+ *
1913
+ * @since 1.4.2
1914
+ * @see AMP_Validation_Manager::serialize_validation_error_messages()
1915
+ *
1916
+ * @param string $serialized Serialized messages.
1917
+ * @return string[]|null
1918
+ */
1919
+ public static function unserialize_validation_error_messages( $serialized ) {
1920
+ $parts = explode( ':', $serialized, 2 );
1921
+ if ( count( $parts ) !== 2 || wp_hash( $parts[1] ) !== $parts[0] ) {
1922
+ return null;
1923
+ }
1924
+ return json_decode( base64_decode( $parts[1] ), true ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
1925
+ }
1926
+
1927
  /**
1928
  * Get error message for a validate URL failure.
1929
  *
1930
+ * @param string $error_code Error code.
1931
+ * @param string $error_message Error message, typically technical such as from HTTP status text or cURL error message.
1932
+ * @return string Error message with HTML markup.
1933
  */
1934
+ public static function get_validate_url_error_message( $error_code, $error_message = '' ) {
1935
+ $check_error_log = sprintf(
1936
+ /* translators: %s is link to Debugging in WordPress */
1937
+ ' ' . __( 'Please check your server PHP error logs; to do this you may need to <a href="%s" target="_blank">enable</a> <code>WP_DEBUG_LOG</code>.', 'amp' ),
1938
+ esc_url( 'https://wordpress.org/support/article/debugging-in-wordpress/' )
1939
+ );
1940
+
1941
+ if ( $error_message ) {
1942
+ $error_message = ' ' . rtrim( $error_message, '.' ) . '.';
1943
+ }
1944
+
1945
+ $support_forum_message = ' ' . sprintf(
1946
+ /* translators: %1$s: Link to support forum. %2$s: Link to new topic form in support forum. */
1947
+ __( 'If you are stuck, please search the <a href="%1$s">support forum</a> for possible related topics, or otherwise start a <a href="%2$s">new support topic</a> including the error message, the URL to your site, and your active theme/plugins.', 'amp' ),
1948
+ esc_url( 'https://wordpress.org/support/plugin/amp/' ),
1949
+ esc_url( 'https://wordpress.org/support/plugin/amp/#new-topic-0' )
1950
+ );
1951
+
1952
+ $site_health_message = '';
1953
+ if ( version_compare( get_bloginfo( 'version' ), '5.2', '>=' ) ) {
1954
+ $site_health_message .= ' ' . sprintf(
1955
+ /* translators: %s is link to Site Health */
1956
+ __( 'Please check your <a href="%s">Site Health</a> to verify it can perform loopback requests.', 'amp' ),
1957
+ esc_url( admin_url( 'site-health.php' ) )
1958
+ );
1959
+ $support_forum_message .= ' ' . sprintf(
1960
+ /* translators: %s is the URL to Site Health Info. */
1961
+ __( 'Please include your <a href="%s">Site Health Info</a>.', 'amp' ),
1962
+ esc_url( admin_url( 'site-health.php?tab=debug' ) )
1963
+ );
1964
+ }
1965
+
1966
  switch ( $error_code ) {
1967
  case 'http_request_failed':
1968
+ return __( 'Failed to fetch URL to validate.', 'amp' ) . $error_message . $site_health_message . $support_forum_message;
1969
  case 'white_screen_of_death':
1970
+ return __( 'Unable to validate URL. Encountered a white screen of death likely due to a PHP fatal error.', 'amp' ) . $error_message . $check_error_log . $support_forum_message;
1971
  case '404':
1972
+ return __( 'The fetched URL was not found. It may have been deleted. If so, you can trash this.', 'amp' ) . $error_message . $support_forum_message;
1973
  case '500':
1974
+ return __( 'An internal server error occurred when fetching the URL for validation.', 'amp' ) . $error_message . $check_error_log . $support_forum_message;
1975
  case 'response_comment_absent':
1976
  return sprintf(
1977
+ /* translators: %1$s: AMP_VALIDATION, %2$s: </body> */
1978
+ __( 'URL validation failed to due to the absence of the expected JSON-containing %1$s HTML comment after %2$s. This is often due to a PHP fatal error occurring.', 'amp' ),
1979
+ '<code>AMP_VALIDATION</code>',
1980
+ '<code>&lt;/body&gt;</code>'
1981
+ ) . $error_message . $check_error_log . $support_forum_message;
1982
  case 'malformed_json_validation_errors':
1983
  return sprintf(
1984
+ /* translators: %1$s: AMP_VALIDATION, %2$s: </body> */
1985
+ __( 'URL validation failed to due to unexpected JSON in the %1$s HTML comment after %2$s.', 'amp' ),
1986
+ '<code>AMP_VALIDATION</code>',
1987
+ '<code>&lt;/body&gt;</code>'
1988
+ ) . $error_message . $support_forum_message;
1989
  default:
1990
  /* translators: %s is error code */
1991
+ return sprintf( __( 'URL validation failed. Error code: %s.', 'amp' ), $error_code ) . $error_message . $support_forum_message;
1992
  }
1993
  }
1994
 
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: google, xwp, automattic, westonruter, swissspidy, miinasikk, ryankienstra, albertomedina, tweetythierry
3
  Tags: amp, stories, mobile, optimization, accelerated mobile pages, framework, components, blocks, performance, ux, seo, official
4
  Requires at least: 4.9
5
- Tested up to: 5.3
6
- Stable tag: 1.4.1
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
  Requires PHP: 5.4
@@ -26,6 +26,10 @@ The plugin can be configured to follow one of three different template modes: St
26
 
27
  With the official AMP plugin for WordPress, the WordPress ecosystem is provided with the capabilities and tools it needs to build world-class AMP experiences without deviating from its standard, flexible, and well-known content creation workflow.
28
 
 
 
 
 
29
  == Installation ==
30
 
31
  1. Upload the folder to the `/wp-content/plugins/` directory.
2
  Contributors: google, xwp, automattic, westonruter, swissspidy, miinasikk, ryankienstra, albertomedina, tweetythierry
3
  Tags: amp, stories, mobile, optimization, accelerated mobile pages, framework, components, blocks, performance, ux, seo, official
4
  Requires at least: 4.9
5
+ Tested up to: 5.3.2
6
+ Stable tag: 1.4.2
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
  Requires PHP: 5.4
26
 
27
  With the official AMP plugin for WordPress, the WordPress ecosystem is provided with the capabilities and tools it needs to build world-class AMP experiences without deviating from its standard, flexible, and well-known content creation workflow.
28
 
29
+ == Frequently Asked Questions ==
30
+
31
+ Please see the [FAQs on amp-wp.org](https://amp-wp.org/documentation/frequently-asked-questions/). Don't see an answer to your question? Please [search the support forum](https://wordpress.org/support/plugin/amp/) to see if someone has asked your question. Otherwise, please [open a new support topic](https://wordpress.org/support/plugin/amp/#new-post).
32
+
33
  == Installation ==
34
 
35
  1. Upload the folder to the `/wp-content/plugins/` directory.
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit84793736047579e77802f3dcb617545d::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInitcb388a4b6a7e40c8dc0a084811af68a2::getLoader();
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit84793736047579e77802f3dcb617545d
6
  {
7
  private static $loader;
8
 
@@ -19,15 +19,15 @@ class ComposerAutoloaderInit84793736047579e77802f3dcb617545d
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit84793736047579e77802f3dcb617545d', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit84793736047579e77802f3dcb617545d', '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\ComposerStaticInit84793736047579e77802f3dcb617545d::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 ComposerAutoloaderInitcb388a4b6a7e40c8dc0a084811af68a2
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInitcb388a4b6a7e40c8dc0a084811af68a2', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInitcb388a4b6a7e40c8dc0a084811af68a2', '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\ComposerStaticInitcb388a4b6a7e40c8dc0a084811af68a2::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 ComposerStaticInit84793736047579e77802f3dcb617545d
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'W' =>
@@ -80,10 +80,10 @@ class ComposerStaticInit84793736047579e77802f3dcb617545d
80
  public static function getInitializer(ClassLoader $loader)
81
  {
82
  return \Closure::bind(function () use ($loader) {
83
- $loader->prefixLengthsPsr4 = ComposerStaticInit84793736047579e77802f3dcb617545d::$prefixLengthsPsr4;
84
- $loader->prefixDirsPsr4 = ComposerStaticInit84793736047579e77802f3dcb617545d::$prefixDirsPsr4;
85
- $loader->prefixesPsr0 = ComposerStaticInit84793736047579e77802f3dcb617545d::$prefixesPsr0;
86
- $loader->classMap = ComposerStaticInit84793736047579e77802f3dcb617545d::$classMap;
87
 
88
  }, null, ClassLoader::class);
89
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInitcb388a4b6a7e40c8dc0a084811af68a2
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'W' =>
80
  public static function getInitializer(ClassLoader $loader)
81
  {
82
  return \Closure::bind(function () use ($loader) {
83
+ $loader->prefixLengthsPsr4 = ComposerStaticInitcb388a4b6a7e40c8dc0a084811af68a2::$prefixLengthsPsr4;
84
+ $loader->prefixDirsPsr4 = ComposerStaticInitcb388a4b6a7e40c8dc0a084811af68a2::$prefixDirsPsr4;
85
+ $loader->prefixesPsr0 = ComposerStaticInitcb388a4b6a7e40c8dc0a084811af68a2::$prefixesPsr0;
86
+ $loader->classMap = ComposerStaticInitcb388a4b6a7e40c8dc0a084811af68a2::$classMap;
87
 
88
  }, null, ClassLoader::class);
89
  }