Version Description
(2018-01-23) =
- Add support for the "page" post type. A new
page.php
is introduced with template parts factored out (html-start.php
,header.php
,footer.php
,html-end.php
) and re-used fromsingle.php
. Note that AMP URLs will end in?amp
instead of/amp/
. See #825. Props technosailor, ThierryA, westonruter. - Add AMP post preview button alongside non-AMP preview button. See #813. Props ThierryA, westonruter.
- Add ability to disable AMP on a per-post basis via toggle in publish metabox. See #813. Props ThierryA, westonruter.
- Add AMP settings admin screen for managing which post types have AMP support, eliminating the requirement to add
add_post_type_support()
calls in theme or plugin. See #811. Props ThierryA, westonruter. - Add generator meta tag for AMP. See #810. Props vaporwavre.
- Add code quality checking via phpcs, eslint, jscs, and jshint. See #795. Props westonruter.
- Add autoloader to reduce complexity. See #828. Props mikeschinkel, westonruter, ThierryA.
- Fix Polldaddy amd SoundCloud embeds. Add vanilla WordPress "embed" test page. A new
bin/create-embed-test-post.php
wp-cli script is introduced. See #829. Props kienstra, westonruter, ThierryA. - Merge AMP Customizer into main Customizer. See #819. Props kaitnyl, westonruter.
- Update AMP HTML tags and attributes. A new
bin/amphtml-update.sh
bash script is introduced. Fixes Playbuzz. See #823. Props kienstra, ThierryA, westonruter. - Remove erroneous hash from id on amp-wp-header. See #853. Props eshannon3.
See 0.6 milestone.
Download this release
Release Info
Developer | westonruter |
Plugin | AMP for WordPress |
Version | 0.6.0 |
Comparing to | |
See all releases |
Code changes from version 0.5.1 to 0.6.0
- amp.php +162 -52
- assets/css/amp-customizer.css +123 -0
- assets/css/amp-post-meta-box.css +61 -0
- assets/images/amp-icon.svg +7 -0
- assets/images/amp-white-icon.svg +9 -0
- assets/js/amp-customize-controls.js +351 -0
- assets/js/amp-customize-preview.js +26 -0
- assets/js/amp-customizer-design-preview.js +9 -0
- assets/js/amp-customizer-preview.js +0 -15
- assets/js/amp-post-meta-box.js +176 -0
- includes/admin/class-amp-customizer.php +197 -76
- includes/admin/class-amp-post-meta-box.php +239 -0
- includes/admin/functions.php +57 -27
- includes/amp-frontend-actions.php +17 -2
- includes/amp-helper-functions.php +92 -12
- includes/amp-post-template-actions.php +85 -16
- includes/class-amp-autoloader.php +134 -0
- includes/class-amp-post-type-support.php +99 -0
- includes/embeds/class-amp-base-embed-handler.php +10 -3
- includes/embeds/class-amp-dailymotion-embed.php +11 -4
- includes/embeds/class-amp-facebook-embed.php +9 -3
- includes/embeds/class-amp-gallery-embed.php +9 -3
- includes/embeds/class-amp-instagram-embed.php +11 -4
- includes/embeds/class-amp-pinterest-embed.php +8 -2
- includes/embeds/class-amp-soundcloud-embed.php +151 -32
- includes/embeds/class-amp-twitter-embed.php +11 -4
- includes/embeds/class-amp-vimeo-embed.php +11 -4
- includes/embeds/class-amp-vine-embed.php +9 -3
- includes/embeds/class-amp-youtube-embed.php +11 -4
- includes/lib/fasterimage/amp-fasterimage.php +19 -17
- includes/options/class-amp-analytics-options-submenu.php +13 -5
- includes/options/class-amp-options-manager.php +244 -0
- includes/options/class-amp-options-menu.php +103 -24
- includes/options/views/class-amp-analytics-options-submenu-page.php +29 -36
- includes/options/views/class-amp-options-manager.php +0 -84
- includes/options/views/class-amp-options-menu-page.php +0 -17
- includes/sanitizers/class-amp-allowed-tags-generated.php +2700 -767
- includes/sanitizers/class-amp-audio-sanitizer.php +102 -16
- includes/sanitizers/class-amp-base-sanitizer.php +154 -7
- includes/sanitizers/class-amp-blacklist-sanitizer.php +87 -26
- includes/sanitizers/class-amp-iframe-sanitizer.php +113 -16
- includes/sanitizers/class-amp-img-sanitizer.php +167 -59
- includes/sanitizers/class-amp-playbuzz-sanitizer.php +90 -20
- includes/sanitizers/class-amp-rule-spec.php +107 -0
- includes/sanitizers/class-amp-style-sanitizer.php +99 -18
- includes/sanitizers/class-amp-tag-and-attribute-sanitizer.php +649 -461
- includes/sanitizers/class-amp-video-sanitizer.php +108 -15
- includes/settings/class-amp-customizer-design-settings.php +160 -15
- includes/templates/class-amp-content-sanitizer.php +53 -0
- includes/{class-amp-content.php → templates/class-amp-content.php} +114 -45
- includes/{class-amp-post-template.php → templates/class-amp-post-template.php} +294 -132
- includes/utils/class-amp-dom-utils.php +205 -22
- includes/utils/class-amp-image-dimension-extractor.php +2 -4
- readme-assets/amp-options-analytics.png +0 -0
- readme-assets/analytics-option-entries.png +0 -0
- readme-assets/invalid-input.png +0 -0
- readme-assets/options-saved.png +0 -0
- readme.md +0 -684
- readme.txt +33 -32
- screenshot-1.png +0 -0
- screenshot-2.png +0 -0
- screenshot-3.png +0 -0
- screenshot-4.png +0 -0
- screenshot-5.png +0 -0
- templates/admin/amp-status.php +71 -0
- templates/footer.php +20 -2
- templates/header-bar.php +14 -4
- templates/header.php +14 -0
- templates/html-end.php +18 -0
- templates/html-start.php +26 -0
- templates/page.php +34 -0
- templates/single.php +21 -23
- templates/style.php +14 -5
- wpcom-helper.php +171 -0
- wpcom/class-amp-polldaddy-embed.php +101 -0
- wpcom/shortcodes.php +20 -0
amp.php
CHANGED
@@ -5,24 +5,28 @@
|
|
5 |
* Plugin URI: https://github.com/automattic/amp-wp
|
6 |
* Author: Automattic
|
7 |
* Author URI: https://automattic.com
|
8 |
-
* Version: 0.
|
9 |
* Text Domain: amp
|
10 |
* Domain Path: /languages/
|
11 |
* License: GPLv2 or later
|
|
|
|
|
12 |
*/
|
13 |
|
14 |
define( 'AMP__FILE__', __FILE__ );
|
15 |
define( 'AMP__DIR__', dirname( __FILE__ ) );
|
16 |
-
define( 'AMP__VERSION', '0.
|
|
|
|
|
|
|
17 |
|
18 |
-
require_once
|
19 |
-
require_once
|
20 |
-
require_once
|
21 |
-
require_once( AMP__DIR__ . '/includes/settings/class-amp-customizer-settings.php' );
|
22 |
-
require_once( AMP__DIR__ . '/includes/settings/class-amp-customizer-design-settings.php' );
|
23 |
|
24 |
register_activation_hook( __FILE__, 'amp_activate' );
|
25 |
function amp_activate() {
|
|
|
26 |
if ( ! did_action( 'amp_init' ) ) {
|
27 |
amp_init();
|
28 |
}
|
@@ -43,20 +47,56 @@ function amp_deactivate() {
|
|
43 |
flush_rewrite_rules();
|
44 |
}
|
45 |
|
46 |
-
|
47 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
if ( false === apply_filters( 'amp_is_enabled', true ) ) {
|
49 |
return;
|
50 |
}
|
51 |
|
52 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
|
|
|
|
|
|
|
|
|
|
|
54 |
do_action( 'amp_init' );
|
55 |
|
56 |
load_plugin_textdomain( 'amp', false, plugin_basename( AMP__DIR__ ) . '/languages' );
|
57 |
|
58 |
add_rewrite_endpoint( AMP_QUERY_VAR, EP_PERMALINK );
|
59 |
-
add_post_type_support( 'post', AMP_QUERY_VAR );
|
60 |
|
61 |
add_filter( 'request', 'amp_force_query_var_value' );
|
62 |
add_action( 'wp', 'amp_maybe_add_actions' );
|
@@ -78,22 +118,69 @@ function amp_force_query_var_value( $query_vars ) {
|
|
78 |
return $query_vars;
|
79 |
}
|
80 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
81 |
function amp_maybe_add_actions() {
|
82 |
-
|
|
|
83 |
return;
|
84 |
}
|
85 |
-
|
86 |
$is_amp_endpoint = is_amp_endpoint();
|
87 |
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
if ( ! $
|
95 |
if ( $is_amp_endpoint ) {
|
96 |
-
wp_safe_redirect( get_permalink( $post->ID ) );
|
97 |
exit;
|
98 |
}
|
99 |
return;
|
@@ -107,16 +194,16 @@ function amp_maybe_add_actions() {
|
|
107 |
}
|
108 |
|
109 |
function amp_load_classes() {
|
110 |
-
|
111 |
}
|
112 |
|
113 |
function amp_add_frontend_actions() {
|
114 |
-
require_once
|
115 |
}
|
116 |
|
117 |
function amp_add_post_template_actions() {
|
118 |
-
require_once
|
119 |
-
require_once
|
120 |
amp_post_template_init_hooks();
|
121 |
}
|
122 |
|
@@ -124,52 +211,75 @@ function amp_prepare_render() {
|
|
124 |
add_action( 'template_redirect', 'amp_render' );
|
125 |
}
|
126 |
|
|
|
|
|
|
|
|
|
|
|
127 |
function amp_render() {
|
128 |
-
|
129 |
-
|
130 |
-
|
|
|
|
|
|
|
131 |
}
|
132 |
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
137 |
}
|
|
|
138 |
|
139 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
140 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
141 |
do_action( 'pre_amp_render_post', $post_id );
|
142 |
|
143 |
amp_add_post_template_actions();
|
144 |
-
$template = new AMP_Post_Template( $
|
145 |
$template->load();
|
|
|
|
|
|
|
|
|
146 |
}
|
147 |
|
148 |
/**
|
149 |
* Bootstraps the AMP customizer.
|
150 |
*
|
151 |
-
* If the AMP customizer is enabled, initially drop the core widgets and menus panels. If the current
|
152 |
-
* preview page isn't flagged as an AMP template, the core panels will be re-added and the AMP panel
|
153 |
-
* hidden.
|
154 |
-
*
|
155 |
-
* @internal This callback must be hooked before priority 10 on 'plugins_loaded' to properly unhook
|
156 |
-
* the core panels.
|
157 |
-
*
|
158 |
* @since 0.4
|
159 |
*/
|
160 |
function _amp_bootstrap_customizer() {
|
161 |
-
|
162 |
-
* Filter whether to enable the AMP template customizer functionality.
|
163 |
-
*
|
164 |
-
* @param bool $enable Whether to enable the AMP customizer. Default true.
|
165 |
-
*/
|
166 |
-
$amp_customizer_enabled = apply_filters( 'amp_customizer_is_enabled', true );
|
167 |
-
|
168 |
-
if ( true === $amp_customizer_enabled ) {
|
169 |
-
amp_init_customizer();
|
170 |
-
}
|
171 |
}
|
172 |
-
add_action( 'plugins_loaded', '_amp_bootstrap_customizer', 9 );
|
173 |
|
174 |
/**
|
175 |
* Redirects the old AMP URL to the new AMP URL.
|
5 |
* Plugin URI: https://github.com/automattic/amp-wp
|
6 |
* Author: Automattic
|
7 |
* Author URI: https://automattic.com
|
8 |
+
* Version: 0.6.0
|
9 |
* Text Domain: amp
|
10 |
* Domain Path: /languages/
|
11 |
* License: GPLv2 or later
|
12 |
+
*
|
13 |
+
* @package AMP
|
14 |
*/
|
15 |
|
16 |
define( 'AMP__FILE__', __FILE__ );
|
17 |
define( 'AMP__DIR__', dirname( __FILE__ ) );
|
18 |
+
define( 'AMP__VERSION', '0.6.0' );
|
19 |
+
|
20 |
+
require_once AMP__DIR__ . '/includes/class-amp-autoloader.php';
|
21 |
+
AMP_Autoloader::register();
|
22 |
|
23 |
+
require_once AMP__DIR__ . '/back-compat/back-compat.php';
|
24 |
+
require_once AMP__DIR__ . '/includes/amp-helper-functions.php';
|
25 |
+
require_once AMP__DIR__ . '/includes/admin/functions.php';
|
|
|
|
|
26 |
|
27 |
register_activation_hook( __FILE__, 'amp_activate' );
|
28 |
function amp_activate() {
|
29 |
+
amp_after_setup_theme();
|
30 |
if ( ! did_action( 'amp_init' ) ) {
|
31 |
amp_init();
|
32 |
}
|
47 |
flush_rewrite_rules();
|
48 |
}
|
49 |
|
50 |
+
/**
|
51 |
+
* Set up AMP.
|
52 |
+
*
|
53 |
+
* This function must be invoked through the 'after_setup_theme' action to allow
|
54 |
+
* the AMP setting to declare the post types support earlier than plugins/theme.
|
55 |
+
*
|
56 |
+
* @since 0.6
|
57 |
+
*/
|
58 |
+
function amp_after_setup_theme() {
|
59 |
if ( false === apply_filters( 'amp_is_enabled', true ) ) {
|
60 |
return;
|
61 |
}
|
62 |
|
63 |
+
if ( ! defined( 'AMP_QUERY_VAR' ) ) {
|
64 |
+
/**
|
65 |
+
* Filter the AMP query variable.
|
66 |
+
*
|
67 |
+
* @since 0.3.2
|
68 |
+
* @param string $query_var The AMP query variable.
|
69 |
+
*/
|
70 |
+
define( 'AMP_QUERY_VAR', apply_filters( 'amp_query_var', 'amp' ) );
|
71 |
+
}
|
72 |
+
|
73 |
+
add_action( 'init', 'amp_init' );
|
74 |
+
add_action( 'admin_init', 'AMP_Options_Manager::register_settings' );
|
75 |
+
add_filter( 'amp_post_template_analytics', 'amp_add_custom_analytics' );
|
76 |
+
add_action( 'wp_loaded', 'amp_post_meta_box' );
|
77 |
+
add_action( 'wp_loaded', 'amp_add_options_menu' );
|
78 |
+
add_action( 'parse_query', 'amp_correct_query_when_is_front_page' );
|
79 |
+
AMP_Post_Type_Support::add_post_type_support();
|
80 |
+
}
|
81 |
+
add_action( 'after_setup_theme', 'amp_after_setup_theme', 5 );
|
82 |
+
|
83 |
+
/**
|
84 |
+
* Init AMP.
|
85 |
+
*
|
86 |
+
* @since 0.1
|
87 |
+
*/
|
88 |
+
function amp_init() {
|
89 |
|
90 |
+
/**
|
91 |
+
* Triggers on init when AMP plugin is active.
|
92 |
+
*
|
93 |
+
* @since 0.3
|
94 |
+
*/
|
95 |
do_action( 'amp_init' );
|
96 |
|
97 |
load_plugin_textdomain( 'amp', false, plugin_basename( AMP__DIR__ ) . '/languages' );
|
98 |
|
99 |
add_rewrite_endpoint( AMP_QUERY_VAR, EP_PERMALINK );
|
|
|
100 |
|
101 |
add_filter( 'request', 'amp_force_query_var_value' );
|
102 |
add_action( 'wp', 'amp_maybe_add_actions' );
|
118 |
return $query_vars;
|
119 |
}
|
120 |
|
121 |
+
/**
|
122 |
+
* Fix up WP_Query for front page when amp query var is present.
|
123 |
+
*
|
124 |
+
* Normally the front page would not get served if a query var is present other than preview, page, paged, and cpage.
|
125 |
+
*
|
126 |
+
* @since 0.6
|
127 |
+
* @see WP_Query::parse_query()
|
128 |
+
* @link https://github.com/WordPress/wordpress-develop/blob/0baa8ae85c670d338e78e408f8d6e301c6410c86/src/wp-includes/class-wp-query.php#L951-L971
|
129 |
+
*
|
130 |
+
* @param WP_Query $query Query.
|
131 |
+
*/
|
132 |
+
function amp_correct_query_when_is_front_page( WP_Query $query ) {
|
133 |
+
$is_front_page_query = (
|
134 |
+
$query->is_main_query()
|
135 |
+
&&
|
136 |
+
$query->is_home()
|
137 |
+
&&
|
138 |
+
// Is AMP endpoint.
|
139 |
+
false !== $query->get( AMP_QUERY_VAR, false )
|
140 |
+
&&
|
141 |
+
// Is query not yet fixed uo up to be front page.
|
142 |
+
! $query->is_front_page()
|
143 |
+
&&
|
144 |
+
// Is showing pages on front.
|
145 |
+
'page' === get_option( 'show_on_front' )
|
146 |
+
&&
|
147 |
+
// Has page on front set.
|
148 |
+
get_option( 'page_on_front' )
|
149 |
+
&&
|
150 |
+
// See line in WP_Query::parse_query() at <https://github.com/WordPress/wordpress-develop/blob/0baa8ae/src/wp-includes/class-wp-query.php#L961>.
|
151 |
+
0 === count( array_diff( array_keys( wp_parse_args( $query->query ) ), array( AMP_QUERY_VAR, 'preview', 'page', 'paged', 'cpage' ) ) )
|
152 |
+
);
|
153 |
+
if ( $is_front_page_query ) {
|
154 |
+
$query->is_home = false;
|
155 |
+
$query->is_page = true;
|
156 |
+
$query->is_singular = true;
|
157 |
+
$query->set( 'page_id', get_option( 'page_on_front' ) );
|
158 |
+
}
|
159 |
+
}
|
160 |
+
|
161 |
+
/**
|
162 |
+
* Add AMP actions when the request can be served as AMP.
|
163 |
+
*
|
164 |
+
* Actions will only be added if the request is for a singular post (including front page and page for posts), excluding feeds.
|
165 |
+
*
|
166 |
+
* @since 0.2
|
167 |
+
*/
|
168 |
function amp_maybe_add_actions() {
|
169 |
+
global $wp_query;
|
170 |
+
if ( ! ( is_singular() || $wp_query->is_posts_page ) || is_feed() ) {
|
171 |
return;
|
172 |
}
|
|
|
173 |
$is_amp_endpoint = is_amp_endpoint();
|
174 |
|
175 |
+
/**
|
176 |
+
* Queried post object.
|
177 |
+
*
|
178 |
+
* @var WP_Post $post
|
179 |
+
*/
|
180 |
+
$post = get_queried_object();
|
181 |
+
if ( ! post_supports_amp( $post ) ) {
|
182 |
if ( $is_amp_endpoint ) {
|
183 |
+
wp_safe_redirect( get_permalink( $post->ID ), 302 ); // Temporary redirect because AMP may be supported in future.
|
184 |
exit;
|
185 |
}
|
186 |
return;
|
194 |
}
|
195 |
|
196 |
function amp_load_classes() {
|
197 |
+
_deprecated_function( __FUNCTION__, '0.6' );
|
198 |
}
|
199 |
|
200 |
function amp_add_frontend_actions() {
|
201 |
+
require_once AMP__DIR__ . '/includes/amp-frontend-actions.php';
|
202 |
}
|
203 |
|
204 |
function amp_add_post_template_actions() {
|
205 |
+
require_once AMP__DIR__ . '/includes/amp-post-template-actions.php';
|
206 |
+
require_once AMP__DIR__ . '/includes/amp-post-template-functions.php';
|
207 |
amp_post_template_init_hooks();
|
208 |
}
|
209 |
|
211 |
add_action( 'template_redirect', 'amp_render' );
|
212 |
}
|
213 |
|
214 |
+
/**
|
215 |
+
* Render AMP for queried post.
|
216 |
+
*
|
217 |
+
* @since 0.1
|
218 |
+
*/
|
219 |
function amp_render() {
|
220 |
+
// Note that queried object is used instead of the ID so that the_preview for the queried post can apply.
|
221 |
+
$post = get_queried_object();
|
222 |
+
if ( $post instanceof WP_Post ) {
|
223 |
+
amp_render_post( $post );
|
224 |
+
exit;
|
225 |
+
}
|
226 |
}
|
227 |
|
228 |
+
/**
|
229 |
+
* Render AMP post template.
|
230 |
+
*
|
231 |
+
* @since 0.5
|
232 |
+
* @param WP_Post|int $post Post.
|
233 |
+
* @global WP_Query $wp_query
|
234 |
+
*/
|
235 |
+
function amp_render_post( $post ) {
|
236 |
+
global $wp_query;
|
237 |
+
|
238 |
+
if ( ! ( $post instanceof WP_Post ) ) {
|
239 |
+
$post = get_post( $post );
|
240 |
+
if ( ! $post ) {
|
241 |
+
return;
|
242 |
+
}
|
243 |
}
|
244 |
+
$post_id = $post->ID;
|
245 |
|
246 |
+
/*
|
247 |
+
* If amp_render_post is called directly outside of the standard endpoint, is_amp_endpoint() will return false,
|
248 |
+
* which is not ideal for any code that expects to run in an AMP context.
|
249 |
+
* Let's force the value to be true while we render AMP.
|
250 |
+
*/
|
251 |
+
$was_set = isset( $wp_query->query_vars[ AMP_QUERY_VAR ] );
|
252 |
+
if ( ! $was_set ) {
|
253 |
+
$wp_query->query_vars[ AMP_QUERY_VAR ] = true;
|
254 |
+
}
|
255 |
|
256 |
+
/**
|
257 |
+
* Fires before rendering a post in AMP.
|
258 |
+
*
|
259 |
+
* @since 0.2
|
260 |
+
*
|
261 |
+
* @param int $post_id Post ID.
|
262 |
+
*/
|
263 |
do_action( 'pre_amp_render_post', $post_id );
|
264 |
|
265 |
amp_add_post_template_actions();
|
266 |
+
$template = new AMP_Post_Template( $post );
|
267 |
$template->load();
|
268 |
+
|
269 |
+
if ( ! $was_set ) {
|
270 |
+
unset( $wp_query->query_vars[ AMP_QUERY_VAR ] );
|
271 |
+
}
|
272 |
}
|
273 |
|
274 |
/**
|
275 |
* Bootstraps the AMP customizer.
|
276 |
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
277 |
* @since 0.4
|
278 |
*/
|
279 |
function _amp_bootstrap_customizer() {
|
280 |
+
add_action( 'after_setup_theme', 'amp_init_customizer' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
281 |
}
|
282 |
+
add_action( 'plugins_loaded', '_amp_bootstrap_customizer', 9 ); // Should be hooked before priority 10 on 'plugins_loaded' to properly unhook core panels.
|
283 |
|
284 |
/**
|
285 |
* Redirects the old AMP URL to the new AMP URL.
|
assets/css/amp-customizer.css
ADDED
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.amp-toggle {
|
2 |
+
position: relative;
|
3 |
+
display: inline-block;
|
4 |
+
width: 30px;
|
5 |
+
height: 15px;
|
6 |
+
top: 15px;
|
7 |
+
left: 130px;
|
8 |
+
}
|
9 |
+
|
10 |
+
.amp-toggle input,
|
11 |
+
.amp-toggle input.disabled {
|
12 |
+
position: absolute;
|
13 |
+
top: 0;
|
14 |
+
left: 0;
|
15 |
+
width: 100%;
|
16 |
+
height: 100%;
|
17 |
+
opacity: 0;
|
18 |
+
margin: 0;
|
19 |
+
padding: 0;
|
20 |
+
z-index: 1;
|
21 |
+
}
|
22 |
+
|
23 |
+
.amp-toggle .slider {
|
24 |
+
position: absolute;
|
25 |
+
cursor: pointer;
|
26 |
+
top: 0;
|
27 |
+
left: 0;
|
28 |
+
right: 0;
|
29 |
+
bottom: 0;
|
30 |
+
border-radius: 34px;
|
31 |
+
background-color: #555D66;
|
32 |
+
-webkit-transition: .3s;
|
33 |
+
transition: .3s;
|
34 |
+
transition-property: background-color, transform, -webkit-transform, -ms-transform, opacity;
|
35 |
+
}
|
36 |
+
.amp-toggle input:focus,
|
37 |
+
.amp-toggle input:active {
|
38 |
+
outline: none;
|
39 |
+
}
|
40 |
+
.amp-toggle input:hover + .slider,
|
41 |
+
.amp-toggle input:focus + .slider,
|
42 |
+
.amp-toggle input:active + .slider {
|
43 |
+
box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8);
|
44 |
+
}
|
45 |
+
|
46 |
+
.amp-toggle .slider:before {
|
47 |
+
position: absolute;
|
48 |
+
content: "";
|
49 |
+
height: 13px;
|
50 |
+
width: 13px;
|
51 |
+
top: 1px;
|
52 |
+
left: 1px;
|
53 |
+
border-radius: 50%;
|
54 |
+
background-color: transparent;
|
55 |
+
background-image: url( '../images/amp-white-icon.svg' );
|
56 |
+
background-size: 13px 13px;
|
57 |
+
-webkit-transition: .3s;
|
58 |
+
transition: .3s;
|
59 |
+
}
|
60 |
+
|
61 |
+
.amp-toggle input:checked + .slider {
|
62 |
+
background-color: #0379C4;
|
63 |
+
}
|
64 |
+
|
65 |
+
.amp-toggle input:checked + .slider:before {
|
66 |
+
-webkit-transform: translateX( 15px );
|
67 |
+
-ms-transform: translateX( 15px );
|
68 |
+
transform: translateX( 15px );
|
69 |
+
}
|
70 |
+
|
71 |
+
.amp-toggle input.disabled + .slider {
|
72 |
+
opacity: 0.7;
|
73 |
+
}
|
74 |
+
|
75 |
+
.amp-toggle .tooltip {
|
76 |
+
position: absolute;
|
77 |
+
bottom: 25px;
|
78 |
+
left: -115px;
|
79 |
+
width: 230px;
|
80 |
+
font-size: 13px;
|
81 |
+
text-align: center;
|
82 |
+
color: #FFFFFF;
|
83 |
+
background: #191E23;
|
84 |
+
padding: 15px;
|
85 |
+
z-index: 1;
|
86 |
+
cursor: default;
|
87 |
+
display: none;
|
88 |
+
}
|
89 |
+
.amp-toggle .tooltip a {
|
90 |
+
color: #00a0d2;
|
91 |
+
}
|
92 |
+
.amp-toggle .tooltip a:hover,
|
93 |
+
.amp-toggle .tooltip a:focus,
|
94 |
+
.amp-toggle .tooltip a:active {
|
95 |
+
color: #54cbf1;
|
96 |
+
}
|
97 |
+
|
98 |
+
.amp-toggle .tooltip:before {
|
99 |
+
position: absolute;
|
100 |
+
bottom: -8px;
|
101 |
+
left: 120px;
|
102 |
+
content: "";
|
103 |
+
border: solid;
|
104 |
+
border-color: #191E23 transparent;
|
105 |
+
border-width: 8px 8px 0 8px;
|
106 |
+
}
|
107 |
+
|
108 |
+
.js .accordion-section-title:after {
|
109 |
+
z-index: 0;
|
110 |
+
}
|
111 |
+
|
112 |
+
#customize-footer-actions .collapse-sidebar-label {
|
113 |
+
font-size: 11px;
|
114 |
+
margin-left: -3px;
|
115 |
+
}
|
116 |
+
|
117 |
+
.devices-wrapper .preview-desktop {
|
118 |
+
border-left: 1px solid #DDDDDD !important;
|
119 |
+
}
|
120 |
+
|
121 |
+
.wp-full-overlay-footer .devices button:before {
|
122 |
+
vertical-align: initial;
|
123 |
+
}
|
assets/css/amp-post-meta-box.css
ADDED
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* 1.0 AMP preview.
|
3 |
+
*
|
4 |
+
* Submit box preview buttons.
|
5 |
+
*/
|
6 |
+
|
7 |
+
/* Core preview button */
|
8 |
+
.wp-core-ui #preview-action.has-amp-preview #post-preview {
|
9 |
+
border-top-right-radius: 0;
|
10 |
+
border-bottom-right-radius: 0;
|
11 |
+
float: none;
|
12 |
+
}
|
13 |
+
|
14 |
+
/* AMP preview button */
|
15 |
+
.wp-core-ui #amp-post-preview.preview {
|
16 |
+
border-top-left-radius: 0;
|
17 |
+
border-bottom-left-radius: 0;
|
18 |
+
text-indent: -9999px;
|
19 |
+
padding-right: 7px;
|
20 |
+
padding-left: 7px;
|
21 |
+
}
|
22 |
+
|
23 |
+
.wp-core-ui #amp-post-preview.preview::after {
|
24 |
+
content: "icon";
|
25 |
+
width: 14px;
|
26 |
+
float: left;
|
27 |
+
background: no-repeat center url( '../images/amp-icon.svg' );
|
28 |
+
background-size: 14px !important;
|
29 |
+
}
|
30 |
+
|
31 |
+
.wp-core-ui #amp-post-preview.preview.disabled::after {
|
32 |
+
opacity: 0.6;
|
33 |
+
}
|
34 |
+
|
35 |
+
/* AMP status */
|
36 |
+
.misc-amp-status .amp-icon {
|
37 |
+
float: left;
|
38 |
+
background: transparent url( '../images/amp-icon.svg' ) no-repeat left;
|
39 |
+
background-size: 17px;
|
40 |
+
width: 17px;
|
41 |
+
height: 17px;
|
42 |
+
margin: 0 8px 0 1px;
|
43 |
+
}
|
44 |
+
|
45 |
+
#amp-status-select fieldset {
|
46 |
+
margin: 7px 0 0 1px;
|
47 |
+
}
|
48 |
+
|
49 |
+
#amp-status-select .notice {
|
50 |
+
margin: 10px 0 -5px 3px;
|
51 |
+
}
|
52 |
+
|
53 |
+
.amp-status-actions {
|
54 |
+
margin-top: 10px;
|
55 |
+
}
|
56 |
+
|
57 |
+
@media screen and ( max-width: 782px ) {
|
58 |
+
#amp-status-select {
|
59 |
+
line-height: 280%;
|
60 |
+
}
|
61 |
+
}
|
assets/images/amp-icon.svg
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
2 |
+
<svg width="62px" height="62px" viewBox="0 0 62 62" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
3 |
+
<title>AMP-Icon</title>
|
4 |
+
<g id="AMP-Icon" fill="#82878c">
|
5 |
+
<path d="M41.6288667,28.1614333 L28.6243667,49.8035667 L26.2683667,49.8035667 L28.5975,35.7016667 L21.3838,35.7109667 C21.3838,35.7109667 21.3156,35.7130333 21.2835667,35.7130333 C20.6336,35.7130333 20.1076333,35.1870667 20.1076333,34.5371 C20.1076333,34.2581 20.367,33.7858667 20.367,33.7858667 L33.3291333,12.1695667 L35.7244,12.1799 L33.3363667,26.3035 L40.5872667,26.2942 C40.5872667,26.2942 40.6647667,26.2931667 40.7019667,26.2931667 C41.3519333,26.2931667 41.8779,26.8191333 41.8779,27.4691 C41.8779,27.7326 41.7745667,27.9640667 41.6278333,28.1604 L41.6288667,28.1614333 Z M31,0 C13.8787,0 0,13.8797333 0,31 C0,48.1213 13.8787,62 31,62 C48.1202667,62 62,48.1213 62,31 C62,13.8797333 48.1202667,0 31,0 L31,0 Z" id="Fill-1"></path>
|
6 |
+
</g>
|
7 |
+
</svg>
|
assets/images/amp-white-icon.svg
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
2 |
+
<svg width="62px" height="62px" viewBox="0 0 62 62" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
3 |
+
<title>AMP-White-Icon</title>
|
4 |
+
<g id="amp-logo-internal-site" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
5 |
+
<g id="AMP-Brand-White-Icon" fill="#FFFFFF">
|
6 |
+
<path d="M41.6288667,28.1614333 L28.6243667,49.8035667 L26.2683667,49.8035667 L28.5975,35.7016667 L21.3838,35.7109667 C21.3838,35.7109667 21.3156,35.7130333 21.2835667,35.7130333 C20.6336,35.7130333 20.1076333,35.1870667 20.1076333,34.5371 C20.1076333,34.2581 20.367,33.7858667 20.367,33.7858667 L33.3291333,12.1695667 L35.7244,12.1799 L33.3363667,26.3035 L40.5872667,26.2942 C40.5872667,26.2942 40.6647667,26.2931667 40.7019667,26.2931667 C41.3519333,26.2931667 41.8779,26.8191333 41.8779,27.4691 C41.8779,27.7326 41.7745667,27.9640667 41.6278333,28.1604 L41.6288667,28.1614333 Z M31,0 C13.8787,0 0,13.8797333 0,31 C0,48.1213 13.8787,62 31,62 C48.1202667,62 62,48.1213 62,31 C62,13.8797333 48.1202667,0 31,0 L31,0 Z" id="Fill-1"></path>
|
7 |
+
</g>
|
8 |
+
</g>
|
9 |
+
</svg>
|
assets/js/amp-customize-controls.js
ADDED
@@ -0,0 +1,351 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* exported ampCustomizeControls */
|
2 |
+
/* eslint no-magic-numbers: [ "error", { "ignore": [ 0, 1, 250] } ] */
|
3 |
+
|
4 |
+
var ampCustomizeControls = ( function( api, $ ) {
|
5 |
+
'use strict';
|
6 |
+
|
7 |
+
var component = {
|
8 |
+
data: {
|
9 |
+
queryVar: 'amp',
|
10 |
+
panelId: '',
|
11 |
+
ampUrl: '',
|
12 |
+
l10n: {
|
13 |
+
unavailableMessage: '',
|
14 |
+
unavailableLinkText: ''
|
15 |
+
}
|
16 |
+
},
|
17 |
+
tooltipTimeout: 5000,
|
18 |
+
tooltipVisible: new api.Value( false ),
|
19 |
+
tooltipFocused: new api.Value( 0 )
|
20 |
+
};
|
21 |
+
|
22 |
+
/**
|
23 |
+
* Boot using data sent inline.
|
24 |
+
*
|
25 |
+
* @param {Object} data Object data.
|
26 |
+
* @return {void}
|
27 |
+
*/
|
28 |
+
component.boot = function boot( data ) {
|
29 |
+
component.data = data;
|
30 |
+
|
31 |
+
function initPanel() {
|
32 |
+
api.panel( component.data.panelId, component.panelReady );
|
33 |
+
}
|
34 |
+
|
35 |
+
if ( api.state ) {
|
36 |
+
component.addState();
|
37 |
+
api.bind( 'ready', initPanel );
|
38 |
+
} else { // WP<4.9.
|
39 |
+
api.bind( 'ready', function() {
|
40 |
+
component.addState(); // Needed for WP<4.9.
|
41 |
+
initPanel();
|
42 |
+
} );
|
43 |
+
}
|
44 |
+
};
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Add state for AMP.
|
48 |
+
*
|
49 |
+
* @returns {void}
|
50 |
+
*/
|
51 |
+
component.addState = function addState() {
|
52 |
+
api.state.add( 'ampEnabled', new api.Value( false ) );
|
53 |
+
api.state.add( 'ampAvailable', new api.Value( false ) );
|
54 |
+
};
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Check if the URL is AMPified.
|
58 |
+
*
|
59 |
+
* @param {string} url URL.
|
60 |
+
* @return {boolean} whether it is an AMP URL.
|
61 |
+
*/
|
62 |
+
component.isAmpUrl = function isAmpUrl( url ) {
|
63 |
+
var urlParser = document.createElement( 'a' ),
|
64 |
+
regexEndpoint = new RegExp( '\\/' + component.data.queryVar + '\\/?$' );
|
65 |
+
|
66 |
+
urlParser.href = url;
|
67 |
+
if ( ! _.isUndefined( wp.customize.utils.parseQueryString( urlParser.search.substr( 1 ) )[ component.data.queryVar ] ) ) {
|
68 |
+
return true;
|
69 |
+
}
|
70 |
+
return regexEndpoint.test( urlParser.pathname );
|
71 |
+
};
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Create an non-AMP version of a URL.
|
75 |
+
*
|
76 |
+
* @param {string} url URL.
|
77 |
+
* @return {string} non-AMPified URL.
|
78 |
+
*/
|
79 |
+
component.unampifyUrl = function unampifyUrl( url ) {
|
80 |
+
var urlParser = document.createElement( 'a' ),
|
81 |
+
regexEndpoint = new RegExp( '\\/' + component.data.queryVar + '\\/?$' ),
|
82 |
+
params;
|
83 |
+
|
84 |
+
urlParser.href = url;
|
85 |
+
urlParser.pathname = urlParser.pathname.replace( regexEndpoint, '' );
|
86 |
+
|
87 |
+
if ( urlParser.search.length > 1 ) {
|
88 |
+
params = wp.customize.utils.parseQueryString( urlParser.search.substr( 1 ) );
|
89 |
+
delete params[ component.data.queryVar ];
|
90 |
+
urlParser.search = $.param( params );
|
91 |
+
}
|
92 |
+
|
93 |
+
return urlParser.href;
|
94 |
+
};
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Create an AMP version of a URL.
|
98 |
+
*
|
99 |
+
* @param {string} url URL.
|
100 |
+
* @return {string} AMPified URL.
|
101 |
+
*/
|
102 |
+
component.ampifyUrl = function ampifyUrl( url ) {
|
103 |
+
var urlParser = document.createElement( 'a' );
|
104 |
+
urlParser.href = component.unampifyUrl( url );
|
105 |
+
if ( urlParser.search.length ) {
|
106 |
+
urlParser.search += '&';
|
107 |
+
}
|
108 |
+
urlParser.search += component.data.queryVar + '=1';
|
109 |
+
return urlParser.href;
|
110 |
+
};
|
111 |
+
|
112 |
+
/**
|
113 |
+
* Try to close the tooltip after a given timeout.
|
114 |
+
*
|
115 |
+
* @returns {void}
|
116 |
+
*/
|
117 |
+
component.tryToCloseTooltip = function tryToCloseTooltip() {
|
118 |
+
clearTimeout( component.tooltipTimeoutId );
|
119 |
+
component.tooltipTimeoutId = setTimeout( function() {
|
120 |
+
if ( ! component.tooltipVisible.get() ) {
|
121 |
+
return;
|
122 |
+
}
|
123 |
+
if ( component.tooltipFocused.get() > 0 ) {
|
124 |
+
component.tryToCloseTooltip();
|
125 |
+
} else {
|
126 |
+
component.tooltipVisible.set( false );
|
127 |
+
}
|
128 |
+
}, component.tooltipTimeout );
|
129 |
+
};
|
130 |
+
|
131 |
+
/**
|
132 |
+
* Make current URL AMPified if toggle is on.
|
133 |
+
*
|
134 |
+
* @param {string} url URL.
|
135 |
+
* @return {string} AMPified URL.
|
136 |
+
*/
|
137 |
+
component.setCurrentAmpUrl = function setCurrentAmpUrl( url ) {
|
138 |
+
var enabled = api.state( 'ampEnabled' ).get();
|
139 |
+
if ( ! enabled && component.isAmpUrl( url ) ) {
|
140 |
+
return component.unampifyUrl( url );
|
141 |
+
} else if ( enabled && ! component.isAmpUrl( url ) ) {
|
142 |
+
return component.ampifyUrl( url );
|
143 |
+
}
|
144 |
+
return url;
|
145 |
+
};
|
146 |
+
|
147 |
+
/**
|
148 |
+
* Swap to AMP version of URL in preview.
|
149 |
+
*
|
150 |
+
* @return {void}
|
151 |
+
*/
|
152 |
+
component.updatePreviewUrl = function updatePreviewUrl() {
|
153 |
+
api.previewer.previewUrl.set( component.setCurrentAmpUrl( api.previewer.previewUrl.get() ) );
|
154 |
+
};
|
155 |
+
|
156 |
+
/**
|
157 |
+
* Enable AMP and navigate to the given URL.
|
158 |
+
*
|
159 |
+
* @param {string} url - URL.
|
160 |
+
* @returns {void}
|
161 |
+
*/
|
162 |
+
component.enableAndNavigateToUrl = function enableAndNavigateToUrl( url ) {
|
163 |
+
api.state( 'ampEnabled' ).set( true );
|
164 |
+
api.previewer.previewUrl.set( url );
|
165 |
+
};
|
166 |
+
|
167 |
+
/**
|
168 |
+
* Update panel notifications.
|
169 |
+
*
|
170 |
+
* @returns {void}
|
171 |
+
*/
|
172 |
+
component.updatePanelNotifications = function updatePanelNotifications() {
|
173 |
+
var panel = api.panel( component.data.panelId ), containers;
|
174 |
+
containers = panel.sections().concat( [ panel ] );
|
175 |
+
if ( api.state( 'ampAvailable' ).get() ) {
|
176 |
+
_.each( containers, function( container ) {
|
177 |
+
container.notifications.remove( 'amp_unavailable' );
|
178 |
+
} );
|
179 |
+
} else {
|
180 |
+
_.each( containers, function( container ) {
|
181 |
+
container.notifications.add( new api.Notification( 'amp_unavailable', {
|
182 |
+
message: component.data.l10n.unavailableMessage,
|
183 |
+
type: 'info',
|
184 |
+
linkText: component.data.l10n.unavailableLinkText,
|
185 |
+
url: component.data.ampUrl,
|
186 |
+
templateId: 'customize-amp-unavailable-notification',
|
187 |
+
render: function() {
|
188 |
+
var li = api.Notification.prototype.render.call( this );
|
189 |
+
li.find( 'a' ).on( 'click', function( event ) {
|
190 |
+
event.preventDefault();
|
191 |
+
component.enableAndNavigateToUrl( this.href );
|
192 |
+
} );
|
193 |
+
return li;
|
194 |
+
}
|
195 |
+
} ) );
|
196 |
+
} );
|
197 |
+
}
|
198 |
+
};
|
199 |
+
|
200 |
+
/**
|
201 |
+
* Hook up all AMP preview interactions once panel is ready.
|
202 |
+
*
|
203 |
+
* @param {wp.customize.Panel} panel The AMP panel.
|
204 |
+
* @return {void}
|
205 |
+
*/
|
206 |
+
component.panelReady = function panelReady( panel ) {
|
207 |
+
var ampToggleContainer, checkbox, tooltip, tooltipLink;
|
208 |
+
|
209 |
+
ampToggleContainer = $( wp.template( 'customize-amp-enabled-toggle' )( {
|
210 |
+
message: component.data.l10n.unavailableMessage,
|
211 |
+
linkText: component.data.l10n.unavailableLinkText,
|
212 |
+
url: component.data.ampUrl
|
213 |
+
} ) );
|
214 |
+
checkbox = ampToggleContainer.find( 'input[type=checkbox]' );
|
215 |
+
tooltip = ampToggleContainer.find( '.tooltip' );
|
216 |
+
tooltipLink = tooltip.find( 'a' );
|
217 |
+
|
218 |
+
// AMP panel triggers the input toggle for AMP preview.
|
219 |
+
panel.expanded.bind( function( expanded ) {
|
220 |
+
if ( ! expanded ) {
|
221 |
+
return;
|
222 |
+
}
|
223 |
+
if ( api.state( 'ampAvailable' ).get() ) {
|
224 |
+
api.state( 'ampEnabled' ).set( panel.expanded.get() );
|
225 |
+
} else if ( ! panel.notifications ) {
|
226 |
+
|
227 |
+
/*
|
228 |
+
* This is only done if panel notifications aren't supported.
|
229 |
+
* If they are (as of 4.9) then a notification will be shown
|
230 |
+
* in the panel and its sections when AMP is not available.
|
231 |
+
*/
|
232 |
+
setTimeout( function() {
|
233 |
+
component.tooltipVisible.set( true );
|
234 |
+
}, 250 );
|
235 |
+
}
|
236 |
+
} );
|
237 |
+
|
238 |
+
if ( panel.notifications ) {
|
239 |
+
api.state( 'ampAvailable' ).bind( component.updatePanelNotifications );
|
240 |
+
component.updatePanelNotifications();
|
241 |
+
api.section.bind( 'add', component.updatePanelNotifications );
|
242 |
+
}
|
243 |
+
|
244 |
+
// Enable AMP toggle if available and mobile device selected.
|
245 |
+
api.previewedDevice.bind( function( device ) {
|
246 |
+
if ( api.state( 'ampAvailable' ).get() ) {
|
247 |
+
api.state( 'ampEnabled' ).set( 'mobile' === device );
|
248 |
+
}
|
249 |
+
} );
|
250 |
+
|
251 |
+
// Message coming from previewer.
|
252 |
+
api.previewer.bind( 'amp-status', function( data ) {
|
253 |
+
api.state( 'ampAvailable' ).set( data.available );
|
254 |
+
} );
|
255 |
+
function setInitialAmpEnabledState( data ) {
|
256 |
+
api.state( 'ampEnabled' ).set( data.enabled );
|
257 |
+
api.previewer.unbind( 'amp-status', setInitialAmpEnabledState );
|
258 |
+
}
|
259 |
+
api.previewer.bind( 'amp-status', setInitialAmpEnabledState );
|
260 |
+
|
261 |
+
/*
|
262 |
+
* Persist the presence or lack of the amp=1 param when navigating in the preview,
|
263 |
+
* even if current page is not yet supported.
|
264 |
+
*/
|
265 |
+
api.previewer.previewUrl.validate = ( function( prevValidate ) {
|
266 |
+
return function( value ) {
|
267 |
+
var val = prevValidate.call( this, value );
|
268 |
+
if ( val ) {
|
269 |
+
val = component.setCurrentAmpUrl( val );
|
270 |
+
}
|
271 |
+
return val;
|
272 |
+
};
|
273 |
+
} )( api.previewer.previewUrl.validate );
|
274 |
+
|
275 |
+
// Listen for ampEnabled state changes.
|
276 |
+
api.state( 'ampEnabled' ).bind( function( enabled ) {
|
277 |
+
checkbox.prop( 'checked', enabled );
|
278 |
+
component.updatePreviewUrl();
|
279 |
+
} );
|
280 |
+
|
281 |
+
// Listen for ampAvailable state changes.
|
282 |
+
api.state( 'ampAvailable' ).bind( function( available ) {
|
283 |
+
checkbox.toggleClass( 'disabled', ! available );
|
284 |
+
|
285 |
+
// Show the unavailable tooltip if AMP is enabled.
|
286 |
+
if ( api.state( 'ampEnabled' ).get() ) {
|
287 |
+
component.tooltipVisible.set( ! available );
|
288 |
+
}
|
289 |
+
} );
|
290 |
+
|
291 |
+
// Adding checkbox toggle before device selection.
|
292 |
+
$( '.devices-wrapper' ).before( ampToggleContainer );
|
293 |
+
|
294 |
+
// User clicked link within tooltip, go to linked post in preview.
|
295 |
+
tooltipLink.on( 'click', function( event ) {
|
296 |
+
event.preventDefault();
|
297 |
+
component.enableAndNavigateToUrl( this.href );
|
298 |
+
} );
|
299 |
+
|
300 |
+
// Toggle visibility of tooltip based on tooltipVisible state.
|
301 |
+
component.tooltipVisible.bind( function( visible ) {
|
302 |
+
tooltip.attr( 'aria-hidden', visible ? 'false' : 'true' );
|
303 |
+
if ( visible ) {
|
304 |
+
$( document ).on( 'click.amp-toggle-outside', function( event ) {
|
305 |
+
if ( ! $.contains( ampToggleContainer[0], event.target ) ) {
|
306 |
+
component.tooltipVisible.set( false );
|
307 |
+
}
|
308 |
+
} );
|
309 |
+
tooltip.fadeIn();
|
310 |
+
component.tryToCloseTooltip();
|
311 |
+
} else {
|
312 |
+
tooltip.fadeOut();
|
313 |
+
component.tooltipFocused.set( 0 );
|
314 |
+
$( document ).off( 'click.amp-toggle-outside' );
|
315 |
+
}
|
316 |
+
} );
|
317 |
+
|
318 |
+
// Handle click on checkbox to either enable the AMP preview or show the tooltip.
|
319 |
+
checkbox.on( 'click', function() {
|
320 |
+
this.checked = ! this.checked; // Undo what we just did, since state is managed in ampAvailable change handler.
|
321 |
+
if ( api.state( 'ampAvailable' ).get() ) {
|
322 |
+
api.state( 'ampEnabled' ).set( ! api.state( 'ampEnabled' ).get() );
|
323 |
+
} else {
|
324 |
+
component.tooltipVisible.set( true );
|
325 |
+
}
|
326 |
+
} );
|
327 |
+
|
328 |
+
// Keep track of the user's state interacting with the tooltip.
|
329 |
+
tooltip.on( 'mouseenter', function() {
|
330 |
+
if ( ! api.state( 'ampAvailable' ).get() ) {
|
331 |
+
component.tooltipVisible.set( true );
|
332 |
+
}
|
333 |
+
component.tooltipFocused.set( component.tooltipFocused.get() + 1 );
|
334 |
+
} );
|
335 |
+
tooltip.on( 'mouseleave', function() {
|
336 |
+
component.tooltipFocused.set( component.tooltipFocused.get() - 1 );
|
337 |
+
} );
|
338 |
+
tooltipLink.on( 'focus', function() {
|
339 |
+
if ( ! api.state( 'ampAvailable' ).get() ) {
|
340 |
+
component.tooltipVisible.set( true );
|
341 |
+
}
|
342 |
+
component.tooltipFocused.set( component.tooltipFocused.get() + 1 );
|
343 |
+
} );
|
344 |
+
tooltipLink.on( 'blur', function() {
|
345 |
+
component.tooltipFocused.set( component.tooltipFocused.get() - 1 );
|
346 |
+
} );
|
347 |
+
};
|
348 |
+
|
349 |
+
return component;
|
350 |
+
|
351 |
+
} )( wp.customize, jQuery );
|
assets/js/amp-customize-preview.js
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* exported ampCustomizePreview */
|
2 |
+
|
3 |
+
var ampCustomizePreview = ( function( api ) {
|
4 |
+
'use strict';
|
5 |
+
|
6 |
+
var component = {};
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Boot using data sent inline.
|
10 |
+
*
|
11 |
+
* @param {Object} data - PHP exports.
|
12 |
+
* @param {boolean} data.available - Whether AMP is available.
|
13 |
+
* @param {boolean} data.enabled - Whether AMP is enabled.
|
14 |
+
* @return {void}
|
15 |
+
*/
|
16 |
+
component.boot = function boot( data ) {
|
17 |
+
api.bind( 'preview-ready', function() {
|
18 |
+
api.preview.bind( 'active', function() {
|
19 |
+
api.preview.send( 'amp-status', data );
|
20 |
+
} );
|
21 |
+
} );
|
22 |
+
};
|
23 |
+
|
24 |
+
return component;
|
25 |
+
|
26 |
+
} )( wp.customize );
|
assets/js/amp-customizer-design-preview.js
CHANGED
@@ -1,3 +1,5 @@
|
|
|
|
|
|
1 |
( function( $ ) {
|
2 |
'use strict';
|
3 |
|
@@ -37,4 +39,11 @@
|
|
37 |
} );
|
38 |
} );
|
39 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
} )( jQuery );
|
1 |
+
/* global amp_customizer_design, console */
|
2 |
+
|
3 |
( function( $ ) {
|
4 |
'use strict';
|
5 |
|
39 |
} );
|
40 |
} );
|
41 |
|
42 |
+
// Site title.
|
43 |
+
wp.customize( 'blogname', function( setting ) {
|
44 |
+
setting.bind( function( title ) {
|
45 |
+
$( '.amp-wp-header .amp-site-title, .amp-wp-footer h2' ).text( title );
|
46 |
+
} );
|
47 |
+
} );
|
48 |
+
|
49 |
} )( jQuery );
|
assets/js/amp-customizer-preview.js
DELETED
@@ -1,15 +0,0 @@
|
|
1 |
-
( function( $ ) {
|
2 |
-
'use strict';
|
3 |
-
|
4 |
-
// Don't allow navigation away from the AMP page in the preview.
|
5 |
-
// The Customizer breaks pretty spectacularly when that happens as it's only meant to work for AMP pages.
|
6 |
-
$( 'a' ).click( function( e ) {
|
7 |
-
var href = this.getAttribute( 'href' );
|
8 |
-
if ( href && href.indexOf( '#' ) === 0 ) {
|
9 |
-
return true;
|
10 |
-
}
|
11 |
-
|
12 |
-
return false;
|
13 |
-
} );
|
14 |
-
|
15 |
-
} )( jQuery );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assets/js/amp-post-meta-box.js
ADDED
@@ -0,0 +1,176 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* exported ampPostMetaBox */
|
2 |
+
|
3 |
+
/**
|
4 |
+
* AMP Post Meta Box.
|
5 |
+
*
|
6 |
+
* @todo Rename this to be just the ampEditPostScreen?
|
7 |
+
*
|
8 |
+
* @since 0.6
|
9 |
+
*/
|
10 |
+
var ampPostMetaBox = ( function( $ ) {
|
11 |
+
'use strict';
|
12 |
+
|
13 |
+
var component = {
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Holds data.
|
17 |
+
*
|
18 |
+
* @since 0.6
|
19 |
+
*/
|
20 |
+
data: {
|
21 |
+
previewLink: '',
|
22 |
+
enabled: true, // Overridden by post_supports_amp( $post ).
|
23 |
+
canSupport: true, // Overridden by count( AMP_Post_Type_Support::get_support_errors( $post ) ) === 0.
|
24 |
+
statusInputName: '',
|
25 |
+
l10n: {
|
26 |
+
ampPreviewBtnLabel: ''
|
27 |
+
}
|
28 |
+
},
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Toggle animation speed.
|
32 |
+
*
|
33 |
+
* @since 0.6
|
34 |
+
*/
|
35 |
+
toggleSpeed: 200,
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Core preview button selector.
|
39 |
+
*
|
40 |
+
* @since 0.6
|
41 |
+
*/
|
42 |
+
previewBtnSelector: '#post-preview',
|
43 |
+
|
44 |
+
/**
|
45 |
+
* AMP preview button selector.
|
46 |
+
*
|
47 |
+
* @since 0.6
|
48 |
+
*/
|
49 |
+
ampPreviewBtnSelector: '#amp-post-preview'
|
50 |
+
};
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Boot plugin.
|
54 |
+
*
|
55 |
+
* @since 0.6
|
56 |
+
* @param {Object} data Object data.
|
57 |
+
* @return {void}
|
58 |
+
*/
|
59 |
+
component.boot = function boot( data ) {
|
60 |
+
component.data = data;
|
61 |
+
$( document ).ready( function() {
|
62 |
+
component.statusRadioInputs = $( '[name="' + component.data.statusInputName + '"]' );
|
63 |
+
if ( component.data.enabled ) {
|
64 |
+
component.addPreviewButton();
|
65 |
+
}
|
66 |
+
component.listen();
|
67 |
+
} );
|
68 |
+
};
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Events listener.
|
72 |
+
*
|
73 |
+
* @since 0.6
|
74 |
+
* @return {void}
|
75 |
+
*/
|
76 |
+
component.listen = function listen() {
|
77 |
+
$( component.ampPreviewBtnSelector ).on( 'click.amp-post-preview', function( e ) {
|
78 |
+
e.preventDefault();
|
79 |
+
component.onAmpPreviewButtonClick();
|
80 |
+
} );
|
81 |
+
|
82 |
+
component.statusRadioInputs.prop( 'disabled', true ); // Prevent cementing setting default status as overridden status.
|
83 |
+
$( '.edit-amp-status, [href="#amp_status"]' ).click( function( e ) {
|
84 |
+
e.preventDefault();
|
85 |
+
component.statusRadioInputs.prop( 'disabled', false );
|
86 |
+
component.toggleAmpStatus( $( e.target ) );
|
87 |
+
} );
|
88 |
+
|
89 |
+
$( '#submitpost input[type="submit"]' ).on( 'click', function() {
|
90 |
+
$( component.ampPreviewBtnSelector ).addClass( 'disabled' );
|
91 |
+
} );
|
92 |
+
};
|
93 |
+
|
94 |
+
/**
|
95 |
+
* Add AMP Preview button.
|
96 |
+
*
|
97 |
+
* @since 0.6
|
98 |
+
* @return {void}
|
99 |
+
*/
|
100 |
+
component.addPreviewButton = function addPreviewButton() {
|
101 |
+
var previewBtn = $( component.previewBtnSelector );
|
102 |
+
previewBtn
|
103 |
+
.clone()
|
104 |
+
.insertAfter( previewBtn )
|
105 |
+
.prop( {
|
106 |
+
'href': component.data.previewLink,
|
107 |
+
'id': component.ampPreviewBtnSelector.replace( '#', '' )
|
108 |
+
} )
|
109 |
+
.text( component.data.l10n.ampPreviewBtnLabel )
|
110 |
+
.parent()
|
111 |
+
.addClass( 'has-amp-preview' );
|
112 |
+
};
|
113 |
+
|
114 |
+
/**
|
115 |
+
* AMP Preview button click handler.
|
116 |
+
*
|
117 |
+
* We trigger the Core preview link for events propagation purposes.
|
118 |
+
*
|
119 |
+
* @since 0.6
|
120 |
+
* @return {void}
|
121 |
+
*/
|
122 |
+
component.onAmpPreviewButtonClick = function onAmpPreviewButtonClick() {
|
123 |
+
var $input;
|
124 |
+
|
125 |
+
// Flag the AMP preview referer.
|
126 |
+
$input = $( '<input>' )
|
127 |
+
.prop( {
|
128 |
+
'type': 'hidden',
|
129 |
+
'name': 'amp-preview',
|
130 |
+
'value': 'do-preview'
|
131 |
+
} )
|
132 |
+
.insertAfter( component.ampPreviewBtnSelector );
|
133 |
+
|
134 |
+
// Trigger Core preview button and remove AMP flag.
|
135 |
+
$( component.previewBtnSelector ).click();
|
136 |
+
$input.remove();
|
137 |
+
};
|
138 |
+
|
139 |
+
/**
|
140 |
+
* Add AMP status toggle.
|
141 |
+
*
|
142 |
+
* @since 0.6
|
143 |
+
* @param {Object} $target Event target.
|
144 |
+
* @return {void}
|
145 |
+
*/
|
146 |
+
component.toggleAmpStatus = function toggleAmpStatus( $target ) {
|
147 |
+
var $container = $( '#amp-status-select' ),
|
148 |
+
status = $container.data( 'amp-status' ),
|
149 |
+
$checked,
|
150 |
+
editAmpStatus = $( '.edit-amp-status' );
|
151 |
+
|
152 |
+
// Don't modify status on cancel button click.
|
153 |
+
if ( ! $target.hasClass( 'button-cancel' ) ) {
|
154 |
+
status = component.statusRadioInputs.filter( ':checked' ).val();
|
155 |
+
}
|
156 |
+
|
157 |
+
$checked = $( '#amp-status-' + status );
|
158 |
+
|
159 |
+
// Toggle elements.
|
160 |
+
editAmpStatus.fadeToggle( component.toggleSpeed, function() {
|
161 |
+
if ( editAmpStatus.is( ':visible' ) ) {
|
162 |
+
editAmpStatus.focus();
|
163 |
+
}
|
164 |
+
} );
|
165 |
+
$container.slideToggle( component.toggleSpeed );
|
166 |
+
|
167 |
+
// Update status.
|
168 |
+
if ( component.data.canSupport ) {
|
169 |
+
$container.data( 'amp-status', status );
|
170 |
+
$checked.prop( 'checked', true );
|
171 |
+
$( '.amp-status-text' ).text( $checked.next().text() );
|
172 |
+
}
|
173 |
+
};
|
174 |
+
|
175 |
+
return component;
|
176 |
+
})( window.jQuery );
|
includes/admin/class-amp-customizer.php
CHANGED
@@ -8,6 +8,7 @@
|
|
8 |
* @since 0.4
|
9 |
*/
|
10 |
class AMP_Template_Customizer {
|
|
|
11 |
/**
|
12 |
* AMP template editor panel ID.
|
13 |
*
|
@@ -39,81 +40,63 @@ class AMP_Template_Customizer {
|
|
39 |
|
40 |
$self->wp_customize = $wp_customize;
|
41 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
do_action( 'amp_customizer_init', $self );
|
43 |
|
44 |
-
// Settings need to be registered for regular customize requests as well (since save is handled there)
|
45 |
$self->register_settings();
|
|
|
46 |
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
$wp_customize->set_preview_url( amp_admin_get_preview_permalink() );
|
51 |
-
}
|
52 |
-
|
53 |
-
$self->_unregister_core_ui();
|
54 |
-
$self->register_ui();
|
55 |
-
} elseif ( is_customize_preview() ) {
|
56 |
-
// Delay preview-specific actions until we're sure we're rendering an AMP page, since it's too early for `is_amp_endpoint()` here.
|
57 |
-
add_action( 'pre_amp_render_post', array( $self, 'init_preview' ) );
|
58 |
-
}
|
59 |
}
|
60 |
|
61 |
/**
|
62 |
-
*
|
63 |
*
|
64 |
* @since 0.4
|
65 |
-
* @
|
66 |
-
*
|
67 |
-
* @return array Array of core Customizer components to keep active.
|
68 |
*/
|
69 |
-
public static function _unregister_core_panels( $panels ) {
|
70 |
-
if ( self::is_amp_customizer() ) {
|
71 |
-
$panels = array();
|
72 |
-
}
|
73 |
-
return $panels;
|
74 |
-
}
|
75 |
-
|
76 |
-
/**
|
77 |
-
* Removes all non-AMP sections and panels.
|
78 |
-
*
|
79 |
-
* Provides a clean, standalone instance-like experience by removing all non-AMP registered panels and sections.
|
80 |
-
*
|
81 |
-
* @since 0.4
|
82 |
-
* @access private
|
83 |
-
*/
|
84 |
-
private function _unregister_core_ui() {
|
85 |
-
$panels = $this->wp_customize->panels();
|
86 |
-
$sections = $this->wp_customize->sections();
|
87 |
-
|
88 |
-
foreach ( $panels as $panel_id => $object ) {
|
89 |
-
$this->wp_customize->remove_panel( $panel_id );
|
90 |
-
}
|
91 |
-
|
92 |
-
foreach ( $sections as $section_id => $object ) {
|
93 |
-
$this->wp_customize->remove_section( $section_id );
|
94 |
-
}
|
95 |
-
}
|
96 |
-
|
97 |
public function init_preview() {
|
98 |
-
|
99 |
-
$this
|
|
|
100 |
|
101 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
}
|
103 |
|
104 |
/**
|
105 |
* Sets up the AMP Customizer preview.
|
106 |
*/
|
107 |
public function register_ui() {
|
108 |
-
add_action( 'customize_controls_enqueue_scripts', array( $this, 'add_customizer_scripts' ) );
|
109 |
-
add_filter( 'customize_previewable_devices', array( $this, 'force_mobile_preview' ) );
|
110 |
-
|
111 |
$this->wp_customize->add_panel( self::PANEL_ID, array(
|
112 |
-
'type'
|
113 |
-
'title'
|
|
|
114 |
'description' => sprintf( __( '<a href="%s" target="_blank">The AMP Project</a> is a Google-led initiative that dramatically improves loading speeds on phones and tablets. You can use the Customizer to preview changes to your AMP template before publishing them.', 'amp' ), 'https://ampproject.org' ),
|
115 |
) );
|
116 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
117 |
do_action( 'amp_customizer_register_ui', $this->wp_customize );
|
118 |
}
|
119 |
|
@@ -121,50 +104,188 @@ class AMP_Template_Customizer {
|
|
121 |
* Registers settings for customizing AMP templates.
|
122 |
*
|
123 |
* @since 0.4
|
124 |
-
* @access public
|
125 |
*/
|
126 |
public function register_settings() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
127 |
do_action( 'amp_customizer_register_settings', $this->wp_customize );
|
128 |
}
|
129 |
|
|
|
|
|
|
|
|
|
|
|
130 |
public function add_customizer_scripts() {
|
131 |
-
wp_enqueue_script(
|
132 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
133 |
}
|
134 |
|
135 |
/**
|
136 |
-
* Enqueues scripts
|
137 |
-
*
|
138 |
-
* This breaks AMP validation in the customizer but is necessary for the live preview.
|
139 |
*
|
140 |
-
* @since 0.
|
141 |
-
* @access public
|
142 |
*/
|
143 |
-
public function
|
|
|
|
|
|
|
|
|
|
|
|
|
144 |
wp_enqueue_script(
|
145 |
-
'amp-
|
146 |
-
amp_get_asset_url( 'js/amp-
|
147 |
-
array( 'jquery', 'customize-preview'
|
148 |
-
|
149 |
-
|
150 |
);
|
151 |
|
152 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
153 |
|
154 |
-
|
155 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
156 |
}
|
157 |
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
162 |
}
|
163 |
|
164 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
165 |
}
|
166 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
167 |
public static function is_amp_customizer() {
|
168 |
-
|
|
|
169 |
}
|
170 |
}
|
8 |
* @since 0.4
|
9 |
*/
|
10 |
class AMP_Template_Customizer {
|
11 |
+
|
12 |
/**
|
13 |
* AMP template editor panel ID.
|
14 |
*
|
40 |
|
41 |
$self->wp_customize = $wp_customize;
|
42 |
|
43 |
+
/**
|
44 |
+
* Fires when the AMP Template Customizer initializes.
|
45 |
+
*
|
46 |
+
* In practice the `customize_register` hook should be used instead.
|
47 |
+
*
|
48 |
+
* @since 0.4
|
49 |
+
* @param AMP_Template_Customizer $self Instance.
|
50 |
+
*/
|
51 |
do_action( 'amp_customizer_init', $self );
|
52 |
|
|
|
53 |
$self->register_settings();
|
54 |
+
$self->register_ui();
|
55 |
|
56 |
+
add_action( 'customize_controls_enqueue_scripts', array( $self, 'add_customizer_scripts' ) );
|
57 |
+
add_action( 'customize_controls_print_footer_scripts', array( $self, 'print_controls_templates' ) );
|
58 |
+
add_action( 'customize_preview_init', array( $self, 'init_preview' ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
}
|
60 |
|
61 |
/**
|
62 |
+
* Init Customizer preview.
|
63 |
*
|
64 |
* @since 0.4
|
65 |
+
* @global WP_Customize_Manager $wp_customize
|
|
|
|
|
66 |
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
public function init_preview() {
|
68 |
+
add_action( 'amp_post_template_head', 'wp_no_robots' );
|
69 |
+
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_preview_scripts' ) );
|
70 |
+
add_action( 'amp_customizer_enqueue_preview_scripts', array( $this, 'enqueue_preview_scripts' ) );
|
71 |
|
72 |
+
// Output scripts and styles which will break AMP validation only when preview is opened with controls for manipulation.
|
73 |
+
if ( $this->wp_customize->get_messenger_channel() ) {
|
74 |
+
add_action( 'amp_post_template_head', array( $this->wp_customize, 'customize_preview_loading_style' ) );
|
75 |
+
add_action( 'amp_post_template_css', array( $this, 'add_customize_preview_styles' ) );
|
76 |
+
add_action( 'amp_post_template_head', array( $this->wp_customize, 'remove_frameless_preview_messenger_channel' ) );
|
77 |
+
add_action( 'amp_post_template_footer', array( $this, 'add_preview_scripts' ) );
|
78 |
+
}
|
79 |
}
|
80 |
|
81 |
/**
|
82 |
* Sets up the AMP Customizer preview.
|
83 |
*/
|
84 |
public function register_ui() {
|
|
|
|
|
|
|
85 |
$this->wp_customize->add_panel( self::PANEL_ID, array(
|
86 |
+
'type' => 'amp',
|
87 |
+
'title' => __( 'AMP', 'amp' ),
|
88 |
+
/* translators: placeholder is URL to AMP project. */
|
89 |
'description' => sprintf( __( '<a href="%s" target="_blank">The AMP Project</a> is a Google-led initiative that dramatically improves loading speeds on phones and tablets. You can use the Customizer to preview changes to your AMP template before publishing them.', 'amp' ), 'https://ampproject.org' ),
|
90 |
) );
|
91 |
|
92 |
+
/**
|
93 |
+
* Fires after the AMP panel has been registered for plugins to add additional controls.
|
94 |
+
*
|
95 |
+
* In practice the `customize_register` hook should be used instead.
|
96 |
+
*
|
97 |
+
* @since 0.4
|
98 |
+
* @param WP_Customize_Manager $manager Manager.
|
99 |
+
*/
|
100 |
do_action( 'amp_customizer_register_ui', $this->wp_customize );
|
101 |
}
|
102 |
|
104 |
* Registers settings for customizing AMP templates.
|
105 |
*
|
106 |
* @since 0.4
|
|
|
107 |
*/
|
108 |
public function register_settings() {
|
109 |
+
|
110 |
+
/**
|
111 |
+
* Fires when plugins should register settings for AMP.
|
112 |
+
*
|
113 |
+
* In practice the `customize_register` hook should be used instead.
|
114 |
+
*
|
115 |
+
* @since 0.4
|
116 |
+
* @param WP_Customize_Manager $manager Manager.
|
117 |
+
*/
|
118 |
do_action( 'amp_customizer_register_settings', $this->wp_customize );
|
119 |
}
|
120 |
|
121 |
+
/**
|
122 |
+
* Load up AMP scripts needed for Customizer integrations.
|
123 |
+
*
|
124 |
+
* @since 0.6
|
125 |
+
*/
|
126 |
public function add_customizer_scripts() {
|
127 |
+
wp_enqueue_script(
|
128 |
+
'amp-customize-controls',
|
129 |
+
amp_get_asset_url( 'js/amp-customize-controls.js' ),
|
130 |
+
array( 'jquery', 'customize-controls' ),
|
131 |
+
AMP__VERSION,
|
132 |
+
true
|
133 |
+
);
|
134 |
+
|
135 |
+
wp_add_inline_script( 'amp-customize-controls', sprintf( 'ampCustomizeControls.boot( %s );',
|
136 |
+
wp_json_encode( array(
|
137 |
+
'queryVar' => AMP_QUERY_VAR,
|
138 |
+
'panelId' => self::PANEL_ID,
|
139 |
+
'ampUrl' => amp_admin_get_preview_permalink(),
|
140 |
+
'l10n' => array(
|
141 |
+
'unavailableMessage' => __( 'AMP is not available for the page currently being previewed.', 'amp' ),
|
142 |
+
'unavailableLinkText' => __( 'Navigate to an AMP compatible page', 'amp' ),
|
143 |
+
),
|
144 |
+
) )
|
145 |
+
) );
|
146 |
+
|
147 |
+
wp_enqueue_style(
|
148 |
+
'amp-customizer',
|
149 |
+
amp_get_asset_url( 'css/amp-customizer.css' )
|
150 |
+
);
|
151 |
+
|
152 |
+
/**
|
153 |
+
* Fires when plugins should register settings for AMP.
|
154 |
+
*
|
155 |
+
* In practice the `customize_controls_enqueue_scripts` hook should be used instead.
|
156 |
+
*
|
157 |
+
* @since 0.4
|
158 |
+
* @param WP_Customize_Manager $manager Manager.
|
159 |
+
*/
|
160 |
+
do_action( 'amp_customizer_enqueue_scripts', $this->wp_customize );
|
161 |
}
|
162 |
|
163 |
/**
|
164 |
+
* Enqueues scripts used in both the AMP and non-AMP Customizer preview.
|
|
|
|
|
165 |
*
|
166 |
+
* @since 0.6
|
|
|
167 |
*/
|
168 |
+
public function enqueue_preview_scripts() {
|
169 |
+
|
170 |
+
// Bail if user can't customize anyway.
|
171 |
+
if ( ! current_user_can( 'customize' ) ) {
|
172 |
+
return;
|
173 |
+
}
|
174 |
+
|
175 |
wp_enqueue_script(
|
176 |
+
'amp-customize-preview',
|
177 |
+
amp_get_asset_url( 'js/amp-customize-preview.js' ),
|
178 |
+
array( 'jquery', 'customize-preview' ),
|
179 |
+
AMP__VERSION,
|
180 |
+
true
|
181 |
);
|
182 |
|
183 |
+
wp_add_inline_script( 'amp-customize-preview', sprintf( 'ampCustomizePreview.boot( %s );',
|
184 |
+
wp_json_encode( array(
|
185 |
+
'available' => (bool) is_singular() && post_supports_amp( get_queried_object() ),
|
186 |
+
'enabled' => is_amp_endpoint(),
|
187 |
+
) )
|
188 |
+
) );
|
189 |
+
}
|
190 |
|
191 |
+
/**
|
192 |
+
* Add AMP Customizer preview styles.
|
193 |
+
*/
|
194 |
+
public function add_customize_preview_styles() {
|
195 |
+
?>
|
196 |
+
/* Text meant only for screen readers; this is needed for wp.a11y.speak() */
|
197 |
+
.screen-reader-text {
|
198 |
+
border: 0;
|
199 |
+
clip: rect(1px, 1px, 1px, 1px);
|
200 |
+
-webkit-clip-path: inset(50%);
|
201 |
+
clip-path: inset(50%);
|
202 |
+
height: 1px;
|
203 |
+
margin: -1px;
|
204 |
+
overflow: hidden;
|
205 |
+
padding: 0;
|
206 |
+
position: absolute;
|
207 |
+
width: 1px;
|
208 |
+
word-wrap: normal !important;
|
209 |
+
}
|
210 |
+
body.wp-customizer-unloading {
|
211 |
+
opacity: 0.25 !important; /* Because AMP sets body to opacity:1 once layout complete. */
|
212 |
+
}
|
213 |
+
<?php
|
214 |
}
|
215 |
|
216 |
+
/**
|
217 |
+
* Enqueues scripts and does wp_print_footer_scripts() so we can output customizer scripts.
|
218 |
+
*
|
219 |
+
* This breaks AMP validation in the customizer but is necessary for the live preview.
|
220 |
+
*
|
221 |
+
* @since 0.6
|
222 |
+
*/
|
223 |
+
public function add_preview_scripts() {
|
224 |
+
|
225 |
+
// Bail if user can't customize anyway.
|
226 |
+
if ( ! current_user_can( 'customize' ) ) {
|
227 |
+
return;
|
228 |
}
|
229 |
|
230 |
+
wp_enqueue_script( 'customize-selective-refresh' );
|
231 |
+
wp_enqueue_script( 'amp-customize-preview' );
|
232 |
+
|
233 |
+
/**
|
234 |
+
* Fires when plugins should enqueue their own scripts for the AMP Customizer preview.
|
235 |
+
*
|
236 |
+
* @since 0.4
|
237 |
+
* @param WP_Customize_Manager $wp_customize Manager.
|
238 |
+
*/
|
239 |
+
do_action( 'amp_customizer_enqueue_preview_scripts', $this->wp_customize );
|
240 |
+
|
241 |
+
$this->wp_customize->customize_preview_settings();
|
242 |
+
$this->wp_customize->selective_refresh->export_preview_data();
|
243 |
+
|
244 |
+
wp_print_footer_scripts();
|
245 |
}
|
246 |
|
247 |
+
/**
|
248 |
+
* Print templates needed for AMP in Customizer.
|
249 |
+
*
|
250 |
+
* @since 0.6
|
251 |
+
*/
|
252 |
+
public function print_controls_templates() {
|
253 |
+
?>
|
254 |
+
<script type="text/html" id="tmpl-customize-amp-enabled-toggle">
|
255 |
+
<div class="amp-toggle">
|
256 |
+
<# var elementIdPrefix = _.uniqueId( 'customize-amp-enabled-toggle' ); #>
|
257 |
+
<div id="{{ elementIdPrefix }}tooltip" aria-hidden="true" class="tooltip" role="tooltip">
|
258 |
+
{{ data.message }}
|
259 |
+
<# if ( data.url ) { #>
|
260 |
+
<a href="{{ data.url }}">{{ data.linkText }}</a>
|
261 |
+
<# } #>
|
262 |
+
</div>
|
263 |
+
<input id="{{ elementIdPrefix }}checkbox" type="checkbox" class="disabled" aria-describedby="{{ elementIdPrefix }}tooltip">
|
264 |
+
<span class="slider"></span>
|
265 |
+
<label for="{{ elementIdPrefix }}checkbox" class="screen-reader-text"><?php esc_html_e( 'AMP preview enabled', 'amp' ); ?></label>
|
266 |
+
</div>
|
267 |
+
</script>
|
268 |
+
<script type="text/html" id="tmpl-customize-amp-unavailable-notification">
|
269 |
+
<li class="notice notice-{{ data.type || 'info' }} {{ data.alt ? 'notice-alt' : '' }} {{ data.containerClasses || '' }}" data-code="{{ data.code }}" data-type="{{ data.type }}">
|
270 |
+
<div class="notification-message">
|
271 |
+
{{ data.message }}
|
272 |
+
<# if ( data.url ) { #>
|
273 |
+
<a href="{{ data.url }}">{{ data.linkText }}</a>
|
274 |
+
<# } #>
|
275 |
+
</div>
|
276 |
+
</li>
|
277 |
+
</script>
|
278 |
+
<?php
|
279 |
+
}
|
280 |
+
|
281 |
+
/**
|
282 |
+
* Whether the Customizer is AMP. This is always true since the AMP Customizer has been merged with the main Customizer.
|
283 |
+
*
|
284 |
+
* @deprecated 0.6
|
285 |
+
* @return bool
|
286 |
+
*/
|
287 |
public static function is_amp_customizer() {
|
288 |
+
_deprecated_function( __METHOD__, '0.6' );
|
289 |
+
return true;
|
290 |
}
|
291 |
}
|
includes/admin/class-amp-post-meta-box.php
ADDED
@@ -0,0 +1,239 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* AMP meta box settings.
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
* @since 0.6
|
7 |
+
*/
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Post meta box class.
|
11 |
+
*
|
12 |
+
* @since 0.6
|
13 |
+
*/
|
14 |
+
class AMP_Post_Meta_Box {
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Assets handle.
|
18 |
+
*
|
19 |
+
* @since 0.6
|
20 |
+
* @var string
|
21 |
+
*/
|
22 |
+
const ASSETS_HANDLE = 'amp-post-meta-box';
|
23 |
+
|
24 |
+
/**
|
25 |
+
* The enabled status post meta value.
|
26 |
+
*
|
27 |
+
* @since 0.6
|
28 |
+
* @var string
|
29 |
+
*/
|
30 |
+
const ENABLED_STATUS = 'enabled';
|
31 |
+
|
32 |
+
/**
|
33 |
+
* The disabled status post meta value.
|
34 |
+
*
|
35 |
+
* @since 0.6
|
36 |
+
* @var string
|
37 |
+
*/
|
38 |
+
const DISABLED_STATUS = 'disabled';
|
39 |
+
|
40 |
+
/**
|
41 |
+
* The status post meta key.
|
42 |
+
*
|
43 |
+
* @since 0.6
|
44 |
+
* @var string
|
45 |
+
*/
|
46 |
+
const STATUS_POST_META_KEY = 'amp_status';
|
47 |
+
|
48 |
+
/**
|
49 |
+
* The field name for the enabled/disabled radio buttons.
|
50 |
+
*
|
51 |
+
* @since 0.6
|
52 |
+
* @var string
|
53 |
+
*/
|
54 |
+
const STATUS_INPUT_NAME = 'amp_status';
|
55 |
+
|
56 |
+
/**
|
57 |
+
* The nonce name.
|
58 |
+
*
|
59 |
+
* @since 0.6
|
60 |
+
* @var string
|
61 |
+
*/
|
62 |
+
const NONCE_NAME = 'amp-status-nonce';
|
63 |
+
|
64 |
+
/**
|
65 |
+
* The nonce action.
|
66 |
+
*
|
67 |
+
* @since 0.6
|
68 |
+
* @var string
|
69 |
+
*/
|
70 |
+
const NONCE_ACTION = 'amp-update-status';
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Initialize.
|
74 |
+
*
|
75 |
+
* @since 0.6
|
76 |
+
*/
|
77 |
+
public function init() {
|
78 |
+
register_meta( 'post', self::STATUS_POST_META_KEY, array(
|
79 |
+
'sanitize_callback' => array( $this, 'sanitize_status' ),
|
80 |
+
'type' => 'string',
|
81 |
+
'description' => __( 'AMP status.', 'amp' ),
|
82 |
+
'show_in_rest' => true,
|
83 |
+
'single' => true,
|
84 |
+
) );
|
85 |
+
|
86 |
+
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_assets' ) );
|
87 |
+
add_action( 'post_submitbox_misc_actions', array( $this, 'render_status' ) );
|
88 |
+
add_action( 'save_post', array( $this, 'save_amp_status' ) );
|
89 |
+
add_filter( 'preview_post_link', array( $this, 'preview_post_link' ) );
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Sanitize status.
|
94 |
+
*
|
95 |
+
* @param string $status Status.
|
96 |
+
* @return string Sanitized status. Empty string when invalid.
|
97 |
+
*/
|
98 |
+
public function sanitize_status( $status ) {
|
99 |
+
$status = strtolower( trim( $status ) );
|
100 |
+
if ( ! in_array( $status, array( 'enabled', 'disabled' ), true ) ) {
|
101 |
+
/*
|
102 |
+
* In lieu of actual validation being available, clear the status entirely
|
103 |
+
* so that the underlying default status will be used instead.
|
104 |
+
* In the future it would be ideal if register_meta() accepted a
|
105 |
+
* validate_callback as well which the REST API could leverage.
|
106 |
+
*/
|
107 |
+
$status = '';
|
108 |
+
}
|
109 |
+
return $status;
|
110 |
+
}
|
111 |
+
|
112 |
+
/**
|
113 |
+
* Enqueue admin assets.
|
114 |
+
*
|
115 |
+
* @since 0.6
|
116 |
+
*/
|
117 |
+
public function enqueue_admin_assets() {
|
118 |
+
$post = get_post();
|
119 |
+
$screen = get_current_screen();
|
120 |
+
$validate = (
|
121 |
+
isset( $screen->base )
|
122 |
+
&&
|
123 |
+
'post' === $screen->base
|
124 |
+
);
|
125 |
+
if ( ! $validate ) {
|
126 |
+
return;
|
127 |
+
}
|
128 |
+
|
129 |
+
// Styles.
|
130 |
+
wp_enqueue_style(
|
131 |
+
self::ASSETS_HANDLE,
|
132 |
+
amp_get_asset_url( 'css/amp-post-meta-box.css' ),
|
133 |
+
false,
|
134 |
+
AMP__VERSION
|
135 |
+
);
|
136 |
+
|
137 |
+
// Scripts.
|
138 |
+
wp_enqueue_script(
|
139 |
+
self::ASSETS_HANDLE,
|
140 |
+
amp_get_asset_url( 'js/amp-post-meta-box.js' ),
|
141 |
+
array( 'jquery' ),
|
142 |
+
AMP__VERSION
|
143 |
+
);
|
144 |
+
wp_add_inline_script( self::ASSETS_HANDLE, sprintf( 'ampPostMetaBox.boot( %s );',
|
145 |
+
wp_json_encode( array(
|
146 |
+
'previewLink' => esc_url_raw( add_query_arg( AMP_QUERY_VAR, '', get_preview_post_link( $post ) ) ),
|
147 |
+
'enabled' => post_supports_amp( $post ),
|
148 |
+
'canSupport' => count( AMP_Post_Type_Support::get_support_errors( $post ) ) === 0,
|
149 |
+
'statusInputName' => self::STATUS_INPUT_NAME,
|
150 |
+
'l10n' => array(
|
151 |
+
'ampPreviewBtnLabel' => __( 'Preview changes in AMP (opens in new window)', 'amp' ),
|
152 |
+
),
|
153 |
+
) )
|
154 |
+
) );
|
155 |
+
}
|
156 |
+
|
157 |
+
/**
|
158 |
+
* Render AMP status.
|
159 |
+
*
|
160 |
+
* @since 0.6
|
161 |
+
* @param WP_Post $post Post.
|
162 |
+
*/
|
163 |
+
public function render_status( $post ) {
|
164 |
+
$verify = (
|
165 |
+
isset( $post->ID )
|
166 |
+
&&
|
167 |
+
current_user_can( 'edit_post', $post->ID )
|
168 |
+
);
|
169 |
+
|
170 |
+
if ( true !== $verify ) {
|
171 |
+
return;
|
172 |
+
}
|
173 |
+
|
174 |
+
$errors = AMP_Post_Type_Support::get_support_errors( $post );
|
175 |
+
$status = post_supports_amp( $post ) ? self::ENABLED_STATUS : self::DISABLED_STATUS;
|
176 |
+
$labels = array(
|
177 |
+
'enabled' => __( 'Enabled', 'amp' ),
|
178 |
+
'disabled' => __( 'Disabled', 'amp' ),
|
179 |
+
);
|
180 |
+
|
181 |
+
// The preceding variables are used inside the following amp-status.php template.
|
182 |
+
include_once AMP__DIR__ . '/templates/admin/amp-status.php';
|
183 |
+
}
|
184 |
+
|
185 |
+
/**
|
186 |
+
* Save AMP Status.
|
187 |
+
*
|
188 |
+
* @since 0.6
|
189 |
+
* @param int $post_id The Post ID.
|
190 |
+
*/
|
191 |
+
public function save_amp_status( $post_id ) {
|
192 |
+
$verify = (
|
193 |
+
isset( $_POST[ self::NONCE_NAME ] )
|
194 |
+
&&
|
195 |
+
isset( $_POST[ self::STATUS_INPUT_NAME ] )
|
196 |
+
&&
|
197 |
+
wp_verify_nonce( sanitize_key( wp_unslash( $_POST[ self::NONCE_NAME ] ) ), self::NONCE_ACTION )
|
198 |
+
&&
|
199 |
+
current_user_can( 'edit_post', $post_id )
|
200 |
+
&&
|
201 |
+
! wp_is_post_revision( $post_id )
|
202 |
+
&&
|
203 |
+
! wp_is_post_autosave( $post_id )
|
204 |
+
);
|
205 |
+
|
206 |
+
if ( true === $verify ) {
|
207 |
+
update_post_meta(
|
208 |
+
$post_id,
|
209 |
+
self::STATUS_POST_META_KEY,
|
210 |
+
$_POST[ self::STATUS_INPUT_NAME ] // Note: The sanitize_callback has been supplied in the register_meta() call above.
|
211 |
+
);
|
212 |
+
}
|
213 |
+
}
|
214 |
+
|
215 |
+
/**
|
216 |
+
* Modify post preview link.
|
217 |
+
*
|
218 |
+
* Add the AMP query var is the amp-preview flag is set.
|
219 |
+
*
|
220 |
+
* @since 0.6
|
221 |
+
*
|
222 |
+
* @param string $link The post preview link.
|
223 |
+
* @return string Preview URL.
|
224 |
+
*/
|
225 |
+
public function preview_post_link( $link ) {
|
226 |
+
$is_amp = (
|
227 |
+
isset( $_POST['amp-preview'] ) // WPCS: CSRF ok.
|
228 |
+
&&
|
229 |
+
'do-preview' === sanitize_key( wp_unslash( $_POST['amp-preview'] ) ) // WPCS: CSRF ok.
|
230 |
+
);
|
231 |
+
|
232 |
+
if ( $is_amp ) {
|
233 |
+
$link = add_query_arg( AMP_QUERY_VAR, true, $link );
|
234 |
+
}
|
235 |
+
|
236 |
+
return $link;
|
237 |
+
}
|
238 |
+
|
239 |
+
}
|
includes/admin/functions.php
CHANGED
@@ -1,30 +1,37 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
|
|
6 |
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
define( 'AMP_CUSTOMIZER_QUERY_VAR', 'customize_amp' );
|
8 |
|
9 |
/**
|
10 |
* Sets up the AMP template editor for the Customizer.
|
11 |
*/
|
12 |
function amp_init_customizer() {
|
13 |
-
|
14 |
-
|
15 |
-
// Drop core panels (menus, widgets) from the AMP customizer
|
16 |
-
add_filter( 'customize_loaded_components', array( 'AMP_Template_Customizer', '_unregister_core_panels' ) );
|
17 |
-
|
18 |
-
// Fire up the AMP Customizer
|
19 |
add_action( 'customize_register', array( 'AMP_Template_Customizer', 'init' ), 500 );
|
20 |
|
21 |
-
// Add some basic design settings + controls to the Customizer
|
22 |
add_action( 'amp_init', array( 'AMP_Customizer_Design_Settings', 'init' ) );
|
23 |
|
24 |
-
// Add a link to the Customizer
|
25 |
add_action( 'admin_menu', 'amp_add_customizer_link' );
|
26 |
}
|
27 |
|
|
|
|
|
|
|
|
|
|
|
28 |
function amp_admin_get_preview_permalink() {
|
29 |
/**
|
30 |
* Filter the post type to retrieve the latest for use in the AMP template customizer.
|
@@ -33,15 +40,16 @@ function amp_admin_get_preview_permalink() {
|
|
33 |
*/
|
34 |
$post_type = (string) apply_filters( 'amp_customizer_post_type', 'post' );
|
35 |
|
36 |
-
if ( ! post_type_supports( $post_type,
|
37 |
-
return;
|
38 |
}
|
39 |
|
40 |
$post_ids = get_posts( array(
|
41 |
-
'post_status'
|
42 |
-
'
|
43 |
-
'
|
44 |
-
'
|
|
|
45 |
) );
|
46 |
|
47 |
if ( empty( $post_ids ) ) {
|
@@ -57,11 +65,10 @@ function amp_admin_get_preview_permalink() {
|
|
57 |
* Registers a submenu page to access the AMP template editor panel in the Customizer.
|
58 |
*/
|
59 |
function amp_add_customizer_link() {
|
60 |
-
// Teensy little hack on menu_slug, but it works. No redirect!
|
61 |
$menu_slug = add_query_arg( array(
|
62 |
-
'autofocus[panel]'
|
63 |
-
'
|
64 |
-
|
65 |
), 'customize.php' );
|
66 |
|
67 |
// Add the theme page.
|
@@ -74,23 +81,35 @@ function amp_add_customizer_link() {
|
|
74 |
}
|
75 |
|
76 |
/**
|
77 |
-
* Registers
|
78 |
*/
|
79 |
function amp_add_options_menu() {
|
80 |
if ( ! is_admin() ) {
|
81 |
return;
|
82 |
}
|
83 |
|
84 |
-
|
85 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
86 |
return;
|
87 |
}
|
88 |
|
89 |
$amp_options = new AMP_Options_Menu();
|
90 |
$amp_options->init();
|
91 |
}
|
92 |
-
add_action( 'wp_loaded', 'amp_add_options_menu' );
|
93 |
|
|
|
|
|
|
|
|
|
|
|
|
|
94 |
function amp_add_custom_analytics( $analytics ) {
|
95 |
$analytics_entries = AMP_Options_Manager::get_option( 'analytics', array() );
|
96 |
|
@@ -108,4 +127,15 @@ function amp_add_custom_analytics( $analytics ) {
|
|
108 |
|
109 |
return $analytics;
|
110 |
}
|
111 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Callbacks for adding AMP-related things to the admin.
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
|
8 |
+
/**
|
9 |
+
* Obsolete constant for flagging when Customizer is opened for AMP.
|
10 |
+
*
|
11 |
+
* @deprecated
|
12 |
+
* @var string
|
13 |
+
*/
|
14 |
define( 'AMP_CUSTOMIZER_QUERY_VAR', 'customize_amp' );
|
15 |
|
16 |
/**
|
17 |
* Sets up the AMP template editor for the Customizer.
|
18 |
*/
|
19 |
function amp_init_customizer() {
|
20 |
+
// Fire up the AMP Customizer.
|
|
|
|
|
|
|
|
|
|
|
21 |
add_action( 'customize_register', array( 'AMP_Template_Customizer', 'init' ), 500 );
|
22 |
|
23 |
+
// Add some basic design settings + controls to the Customizer.
|
24 |
add_action( 'amp_init', array( 'AMP_Customizer_Design_Settings', 'init' ) );
|
25 |
|
26 |
+
// Add a link to the Customizer.
|
27 |
add_action( 'admin_menu', 'amp_add_customizer_link' );
|
28 |
}
|
29 |
|
30 |
+
/**
|
31 |
+
* Get permalink for the first AMP-eligible post.
|
32 |
+
*
|
33 |
+
* @return string|null
|
34 |
+
*/
|
35 |
function amp_admin_get_preview_permalink() {
|
36 |
/**
|
37 |
* Filter the post type to retrieve the latest for use in the AMP template customizer.
|
40 |
*/
|
41 |
$post_type = (string) apply_filters( 'amp_customizer_post_type', 'post' );
|
42 |
|
43 |
+
if ( ! post_type_supports( $post_type, AMP_QUERY_VAR ) ) {
|
44 |
+
return null;
|
45 |
}
|
46 |
|
47 |
$post_ids = get_posts( array(
|
48 |
+
'post_status' => 'publish',
|
49 |
+
'post_password' => '',
|
50 |
+
'post_type' => $post_type,
|
51 |
+
'posts_per_page' => 1,
|
52 |
+
'fields' => 'ids',
|
53 |
) );
|
54 |
|
55 |
if ( empty( $post_ids ) ) {
|
65 |
* Registers a submenu page to access the AMP template editor panel in the Customizer.
|
66 |
*/
|
67 |
function amp_add_customizer_link() {
|
|
|
68 |
$menu_slug = add_query_arg( array(
|
69 |
+
'autofocus[panel]' => AMP_Template_Customizer::PANEL_ID,
|
70 |
+
'url' => rawurlencode( amp_admin_get_preview_permalink() ),
|
71 |
+
'return' => rawurlencode( admin_url() ),
|
72 |
), 'customize.php' );
|
73 |
|
74 |
// Add the theme page.
|
81 |
}
|
82 |
|
83 |
/**
|
84 |
+
* Registers AMP settings.
|
85 |
*/
|
86 |
function amp_add_options_menu() {
|
87 |
if ( ! is_admin() ) {
|
88 |
return;
|
89 |
}
|
90 |
|
91 |
+
/**
|
92 |
+
* Filter whether to enable the AMP settings.
|
93 |
+
*
|
94 |
+
* @since 0.5
|
95 |
+
* @param bool $enable Whether to enable the AMP settings. Default true.
|
96 |
+
*/
|
97 |
+
$short_circuit = apply_filters( 'amp_options_menu_is_enabled', true );
|
98 |
+
|
99 |
+
if ( true !== $short_circuit ) {
|
100 |
return;
|
101 |
}
|
102 |
|
103 |
$amp_options = new AMP_Options_Menu();
|
104 |
$amp_options->init();
|
105 |
}
|
|
|
106 |
|
107 |
+
/**
|
108 |
+
* Add custom analytics.
|
109 |
+
*
|
110 |
+
* @param array $analytics Analytics.
|
111 |
+
* @return array Analytics.
|
112 |
+
*/
|
113 |
function amp_add_custom_analytics( $analytics ) {
|
114 |
$analytics_entries = AMP_Options_Manager::get_option( 'analytics', array() );
|
115 |
|
127 |
|
128 |
return $analytics;
|
129 |
}
|
130 |
+
|
131 |
+
/**
|
132 |
+
* Bootstrap AMP post meta box.
|
133 |
+
*
|
134 |
+
* This function must be invoked only once through the 'wp_loaded' action.
|
135 |
+
*
|
136 |
+
* @since 0.6
|
137 |
+
*/
|
138 |
+
function amp_post_meta_box() {
|
139 |
+
$post_meta_box = new AMP_Post_Meta_Box();
|
140 |
+
$post_meta_box->init();
|
141 |
+
}
|
includes/amp-frontend-actions.php
CHANGED
@@ -1,13 +1,28 @@
|
|
1 |
<?php
|
2 |
-
|
|
|
|
|
|
|
|
|
3 |
|
4 |
add_action( 'wp_head', 'amp_frontend_add_canonical' );
|
5 |
|
|
|
|
|
|
|
|
|
|
|
6 |
function amp_frontend_add_canonical() {
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
if ( false === apply_filters( 'amp_frontend_show_canonical', true ) ) {
|
8 |
return;
|
9 |
}
|
10 |
|
11 |
$amp_url = amp_get_permalink( get_queried_object_id() );
|
12 |
-
printf( '<link rel="amphtml" href="%s"
|
13 |
}
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Callbacks for adding AMP-related things to the main theme.
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
|
8 |
add_action( 'wp_head', 'amp_frontend_add_canonical' );
|
9 |
|
10 |
+
/**
|
11 |
+
* Add amphtml link to frontend.
|
12 |
+
*
|
13 |
+
* @since 0.2
|
14 |
+
*/
|
15 |
function amp_frontend_add_canonical() {
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Filters whether to show the amphtml link on the frontend.
|
19 |
+
*
|
20 |
+
* @since 0.2
|
21 |
+
*/
|
22 |
if ( false === apply_filters( 'amp_frontend_show_canonical', true ) ) {
|
23 |
return;
|
24 |
}
|
25 |
|
26 |
$amp_url = amp_get_permalink( get_queried_object_id() );
|
27 |
+
printf( '<link rel="amphtml" href="%s">', esc_url( $amp_url ) );
|
28 |
}
|
includes/amp-helper-functions.php
CHANGED
@@ -1,43 +1,117 @@
|
|
1 |
<?php
|
|
|
|
|
|
|
|
|
|
|
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
function amp_get_permalink( $post_id ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
$pre_url = apply_filters( 'amp_pre_get_permalink', false, $post_id );
|
5 |
|
6 |
if ( false !== $pre_url ) {
|
7 |
return $pre_url;
|
8 |
}
|
9 |
|
10 |
-
$
|
11 |
-
|
12 |
-
|
|
|
13 |
} else {
|
14 |
$amp_url = trailingslashit( get_permalink( $post_id ) ) . user_trailingslashit( AMP_QUERY_VAR, 'single_amp' );
|
15 |
}
|
16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
return apply_filters( 'amp_get_permalink', $amp_url, $post_id );
|
18 |
}
|
19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
function post_supports_amp( $post ) {
|
21 |
-
|
22 |
-
if ( ! post_type_supports( $post->post_type, AMP_QUERY_VAR ) ) {
|
23 |
-
return false;
|
24 |
-
}
|
25 |
|
26 |
-
|
|
|
27 |
return false;
|
28 |
}
|
29 |
|
30 |
-
|
31 |
-
|
32 |
-
|
|
|
|
|
|
|
33 |
|
34 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
}
|
36 |
|
37 |
/**
|
38 |
* Are we currently on an AMP URL?
|
39 |
*
|
40 |
* Note: will always return `false` if called before the `parse_query` hook.
|
|
|
|
|
41 |
*/
|
42 |
function is_amp_endpoint() {
|
43 |
if ( 0 === did_action( 'parse_query' ) ) {
|
@@ -47,6 +121,12 @@ function is_amp_endpoint() {
|
|
47 |
return false !== get_query_var( AMP_QUERY_VAR, false );
|
48 |
}
|
49 |
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
function amp_get_asset_url( $file ) {
|
51 |
return plugins_url( sprintf( 'assets/%s', $file ), AMP__FILE__ );
|
52 |
}
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* AMP Helper Functions
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
|
8 |
+
/**
|
9 |
+
* Retrieves the full AMP-specific permalink for the given post ID.
|
10 |
+
*
|
11 |
+
* @since 0.1
|
12 |
+
*
|
13 |
+
* @param int $post_id Post ID.
|
14 |
+
*
|
15 |
+
* @return string AMP permalink.
|
16 |
+
*/
|
17 |
function amp_get_permalink( $post_id ) {
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Filters the AMP permalink to short-circuit normal generation.
|
21 |
+
*
|
22 |
+
* Returning a non-false value in this filter will cause the `get_permalink()` to get called and the `amp_get_permalink` filter to not apply.
|
23 |
+
*
|
24 |
+
* @since 0.4
|
25 |
+
*
|
26 |
+
* @param false $url Short-circuited URL.
|
27 |
+
* @param int $post_id Post ID.
|
28 |
+
*/
|
29 |
$pre_url = apply_filters( 'amp_pre_get_permalink', false, $post_id );
|
30 |
|
31 |
if ( false !== $pre_url ) {
|
32 |
return $pre_url;
|
33 |
}
|
34 |
|
35 |
+
$parsed_url = wp_parse_url( get_permalink( $post_id ) );
|
36 |
+
$structure = get_option( 'permalink_structure' );
|
37 |
+
if ( empty( $structure ) || ! empty( $parsed_url['query'] ) || is_post_type_hierarchical( get_post_type( $post_id ) ) ) {
|
38 |
+
$amp_url = add_query_arg( AMP_QUERY_VAR, '', get_permalink( $post_id ) );
|
39 |
} else {
|
40 |
$amp_url = trailingslashit( get_permalink( $post_id ) ) . user_trailingslashit( AMP_QUERY_VAR, 'single_amp' );
|
41 |
}
|
42 |
|
43 |
+
/**
|
44 |
+
* Filters AMP permalink.
|
45 |
+
*
|
46 |
+
* @since 0.2
|
47 |
+
*
|
48 |
+
* @param false $amp_url AMP URL.
|
49 |
+
* @param int $post_id Post ID.
|
50 |
+
*/
|
51 |
return apply_filters( 'amp_get_permalink', $amp_url, $post_id );
|
52 |
}
|
53 |
|
54 |
+
/**
|
55 |
+
* Determine whether a given post supports AMP.
|
56 |
+
*
|
57 |
+
* @since 0.1
|
58 |
+
* @since 0.6 Returns false when post has meta to disable AMP.
|
59 |
+
* @see AMP_Post_Type_Support::get_support_errors()
|
60 |
+
*
|
61 |
+
* @param WP_Post $post Post.
|
62 |
+
*
|
63 |
+
* @return bool Whether the post supports AMP.
|
64 |
+
*/
|
65 |
function post_supports_amp( $post ) {
|
66 |
+
$errors = AMP_Post_Type_Support::get_support_errors( $post );
|
|
|
|
|
|
|
67 |
|
68 |
+
// Return false if an error is found.
|
69 |
+
if ( ! empty( $errors ) ) {
|
70 |
return false;
|
71 |
}
|
72 |
|
73 |
+
switch ( get_post_meta( $post->ID, AMP_Post_Meta_Box::STATUS_POST_META_KEY, true ) ) {
|
74 |
+
case AMP_Post_Meta_Box::ENABLED_STATUS:
|
75 |
+
return true;
|
76 |
+
|
77 |
+
case AMP_Post_Meta_Box::DISABLED_STATUS:
|
78 |
+
return false;
|
79 |
|
80 |
+
// Disabled by default for custom page templates, page on front and page for posts.
|
81 |
+
default:
|
82 |
+
$enabled = (
|
83 |
+
! (bool) get_page_template_slug( $post )
|
84 |
+
&&
|
85 |
+
! (
|
86 |
+
'page' === $post->post_type
|
87 |
+
&&
|
88 |
+
'page' === get_option( 'show_on_front' )
|
89 |
+
&&
|
90 |
+
in_array( (int) $post->ID, array(
|
91 |
+
(int) get_option( 'page_on_front' ),
|
92 |
+
(int) get_option( 'page_for_posts' ),
|
93 |
+
), true )
|
94 |
+
)
|
95 |
+
);
|
96 |
+
|
97 |
+
/**
|
98 |
+
* Filters whether default AMP status should be enabled or not.
|
99 |
+
*
|
100 |
+
* @since 0.6
|
101 |
+
*
|
102 |
+
* @param string $status Status.
|
103 |
+
* @param WP_Post $post Post.
|
104 |
+
*/
|
105 |
+
return apply_filters( 'amp_post_status_default_enabled', $enabled, $post );
|
106 |
+
}
|
107 |
}
|
108 |
|
109 |
/**
|
110 |
* Are we currently on an AMP URL?
|
111 |
*
|
112 |
* Note: will always return `false` if called before the `parse_query` hook.
|
113 |
+
*
|
114 |
+
* @return bool Whether it is the AMP endpoint.
|
115 |
*/
|
116 |
function is_amp_endpoint() {
|
117 |
if ( 0 === did_action( 'parse_query' ) ) {
|
121 |
return false !== get_query_var( AMP_QUERY_VAR, false );
|
122 |
}
|
123 |
|
124 |
+
/**
|
125 |
+
* Get AMP asset URL.
|
126 |
+
*
|
127 |
+
* @param string $file Relative path to file in assets directory.
|
128 |
+
* @return string URL.
|
129 |
+
*/
|
130 |
function amp_get_asset_url( $file ) {
|
131 |
return plugins_url( sprintf( 'assets/%s', $file ), AMP__FILE__ );
|
132 |
}
|
includes/amp-post-template-actions.php
CHANGED
@@ -1,6 +1,13 @@
|
|
1 |
<?php
|
2 |
-
|
|
|
|
|
|
|
|
|
3 |
|
|
|
|
|
|
|
4 |
function amp_post_template_init_hooks() {
|
5 |
add_action( 'amp_post_template_head', 'amp_post_template_add_title' );
|
6 |
add_action( 'amp_post_template_head', 'amp_post_template_add_canonical' );
|
@@ -8,46 +15,82 @@ function amp_post_template_init_hooks() {
|
|
8 |
add_action( 'amp_post_template_head', 'amp_post_template_add_fonts' );
|
9 |
add_action( 'amp_post_template_head', 'amp_post_template_add_boilerplate_css' );
|
10 |
add_action( 'amp_post_template_head', 'amp_post_template_add_schemaorg_metadata' );
|
|
|
11 |
add_action( 'amp_post_template_css', 'amp_post_template_add_styles', 99 );
|
12 |
add_action( 'amp_post_template_data', 'amp_post_template_add_analytics_script' );
|
13 |
add_action( 'amp_post_template_footer', 'amp_post_template_add_analytics_data' );
|
14 |
}
|
15 |
|
|
|
|
|
|
|
|
|
|
|
16 |
function amp_post_template_add_title( $amp_template ) {
|
17 |
?>
|
18 |
<title><?php echo esc_html( $amp_template->get( 'document_title' ) ); ?></title>
|
19 |
<?php
|
20 |
}
|
21 |
|
|
|
|
|
|
|
|
|
|
|
22 |
function amp_post_template_add_canonical( $amp_template ) {
|
23 |
?>
|
24 |
<link rel="canonical" href="<?php echo esc_url( $amp_template->get( 'canonical_url' ) ); ?>" />
|
25 |
<?php
|
26 |
}
|
27 |
|
|
|
|
|
|
|
|
|
|
|
28 |
function amp_post_template_add_scripts( $amp_template ) {
|
29 |
$scripts = $amp_template->get( 'amp_component_scripts', array() );
|
30 |
-
foreach ( $scripts as $element => $script )
|
31 |
-
$custom_type = (
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
}
|
37 |
|
|
|
|
|
|
|
|
|
|
|
38 |
function amp_post_template_add_fonts( $amp_template ) {
|
39 |
$font_urls = $amp_template->get( 'font_urls', array() );
|
40 |
-
foreach ( $font_urls as $slug => $url )
|
41 |
-
<link rel="stylesheet" href="
|
42 |
-
|
43 |
}
|
44 |
|
45 |
-
|
|
|
|
|
|
|
46 |
?>
|
47 |
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
|
48 |
<?php
|
49 |
}
|
50 |
|
|
|
|
|
|
|
|
|
|
|
51 |
function amp_post_template_add_schemaorg_metadata( $amp_template ) {
|
52 |
$metadata = $amp_template->get( 'metadata' );
|
53 |
if ( empty( $metadata ) ) {
|
@@ -58,17 +101,28 @@ function amp_post_template_add_schemaorg_metadata( $amp_template ) {
|
|
58 |
<?php
|
59 |
}
|
60 |
|
|
|
|
|
|
|
|
|
|
|
61 |
function amp_post_template_add_styles( $amp_template ) {
|
62 |
$styles = $amp_template->get( 'post_amp_styles' );
|
63 |
if ( ! empty( $styles ) ) {
|
64 |
-
echo '/* Inline styles */' . PHP_EOL;
|
65 |
foreach ( $styles as $selector => $declarations ) {
|
66 |
$declarations = implode( ';', $declarations ) . ';';
|
67 |
-
printf( '%1$s{%2$s}', $selector, $declarations );
|
68 |
}
|
69 |
}
|
70 |
}
|
71 |
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
function amp_post_template_add_analytics_script( $data ) {
|
73 |
if ( ! empty( $data['amp_analytics'] ) ) {
|
74 |
$data['amp_component_scripts']['amp-analytics'] = 'https://cdn.ampproject.org/v0/amp-analytics-0.1.js';
|
@@ -76,6 +130,11 @@ function amp_post_template_add_analytics_script( $data ) {
|
|
76 |
return $data;
|
77 |
}
|
78 |
|
|
|
|
|
|
|
|
|
|
|
79 |
function amp_post_template_add_analytics_data( $amp_template ) {
|
80 |
$analytics_entries = $amp_template->get( 'amp_analytics' );
|
81 |
if ( empty( $analytics_entries ) ) {
|
@@ -84,7 +143,8 @@ function amp_post_template_add_analytics_data( $amp_template ) {
|
|
84 |
|
85 |
foreach ( $analytics_entries as $id => $analytics_entry ) {
|
86 |
if ( ! isset( $analytics_entry['type'], $analytics_entry['attributes'], $analytics_entry['config_data'] ) ) {
|
87 |
-
|
|
|
88 |
continue;
|
89 |
}
|
90 |
$script_element = AMP_HTML_Utils::build_tag( 'script', array(
|
@@ -92,10 +152,19 @@ function amp_post_template_add_analytics_data( $amp_template ) {
|
|
92 |
), wp_json_encode( $analytics_entry['config_data'] ) );
|
93 |
|
94 |
$amp_analytics_attr = array_merge( array(
|
95 |
-
'id'
|
96 |
'type' => $analytics_entry['type'],
|
97 |
), $analytics_entry['attributes'] );
|
98 |
|
99 |
-
echo AMP_HTML_Utils::build_tag( 'amp-analytics', $amp_analytics_attr, $script_element );
|
100 |
}
|
101 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Callbacks for adding content to an AMP template.
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
|
8 |
+
/**
|
9 |
+
* Register hooks.
|
10 |
+
*/
|
11 |
function amp_post_template_init_hooks() {
|
12 |
add_action( 'amp_post_template_head', 'amp_post_template_add_title' );
|
13 |
add_action( 'amp_post_template_head', 'amp_post_template_add_canonical' );
|
15 |
add_action( 'amp_post_template_head', 'amp_post_template_add_fonts' );
|
16 |
add_action( 'amp_post_template_head', 'amp_post_template_add_boilerplate_css' );
|
17 |
add_action( 'amp_post_template_head', 'amp_post_template_add_schemaorg_metadata' );
|
18 |
+
add_action( 'amp_post_template_head', 'amp_add_generator_metadata' );
|
19 |
add_action( 'amp_post_template_css', 'amp_post_template_add_styles', 99 );
|
20 |
add_action( 'amp_post_template_data', 'amp_post_template_add_analytics_script' );
|
21 |
add_action( 'amp_post_template_footer', 'amp_post_template_add_analytics_data' );
|
22 |
}
|
23 |
|
24 |
+
/**
|
25 |
+
* Add title.
|
26 |
+
*
|
27 |
+
* @param AMP_Post_Template $amp_template template.
|
28 |
+
*/
|
29 |
function amp_post_template_add_title( $amp_template ) {
|
30 |
?>
|
31 |
<title><?php echo esc_html( $amp_template->get( 'document_title' ) ); ?></title>
|
32 |
<?php
|
33 |
}
|
34 |
|
35 |
+
/**
|
36 |
+
* Add canonical link.
|
37 |
+
*
|
38 |
+
* @param AMP_Post_Template $amp_template Template.
|
39 |
+
*/
|
40 |
function amp_post_template_add_canonical( $amp_template ) {
|
41 |
?>
|
42 |
<link rel="canonical" href="<?php echo esc_url( $amp_template->get( 'canonical_url' ) ); ?>" />
|
43 |
<?php
|
44 |
}
|
45 |
|
46 |
+
/**
|
47 |
+
* Print scripts.
|
48 |
+
*
|
49 |
+
* @param AMP_Post_Template $amp_template Template.
|
50 |
+
*/
|
51 |
function amp_post_template_add_scripts( $amp_template ) {
|
52 |
$scripts = $amp_template->get( 'amp_component_scripts', array() );
|
53 |
+
foreach ( $scripts as $element => $script ) {
|
54 |
+
$custom_type = ( 'amp-mustache' === $element ) ? 'template' : 'element';
|
55 |
+
printf(
|
56 |
+
'<script custom-%s="%s" src="%s" async></script>', // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript
|
57 |
+
esc_attr( $custom_type ),
|
58 |
+
esc_attr( $element ),
|
59 |
+
esc_url( $script )
|
60 |
+
);
|
61 |
+
}
|
62 |
+
printf(
|
63 |
+
'<script src="%s" async></script>', // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript
|
64 |
+
esc_url( $amp_template->get( 'amp_runtime_script' ) )
|
65 |
+
);
|
66 |
}
|
67 |
|
68 |
+
/**
|
69 |
+
* Print fonts.
|
70 |
+
*
|
71 |
+
* @param AMP_Post_Template $amp_template Template.
|
72 |
+
*/
|
73 |
function amp_post_template_add_fonts( $amp_template ) {
|
74 |
$font_urls = $amp_template->get( 'font_urls', array() );
|
75 |
+
foreach ( $font_urls as $slug => $url ) {
|
76 |
+
printf( '<link rel="stylesheet" href="%s">', esc_url( esc_url( $url ) ) ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet
|
77 |
+
}
|
78 |
}
|
79 |
|
80 |
+
/**
|
81 |
+
* Print boilerplate CSS.
|
82 |
+
*/
|
83 |
+
function amp_post_template_add_boilerplate_css() {
|
84 |
?>
|
85 |
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
|
86 |
<?php
|
87 |
}
|
88 |
|
89 |
+
/**
|
90 |
+
* Print Schema.org metadata.
|
91 |
+
*
|
92 |
+
* @param AMP_Post_Template $amp_template Template.
|
93 |
+
*/
|
94 |
function amp_post_template_add_schemaorg_metadata( $amp_template ) {
|
95 |
$metadata = $amp_template->get( 'metadata' );
|
96 |
if ( empty( $metadata ) ) {
|
101 |
<?php
|
102 |
}
|
103 |
|
104 |
+
/**
|
105 |
+
* Print styles.
|
106 |
+
*
|
107 |
+
* @param AMP_Post_Template $amp_template Template.
|
108 |
+
*/
|
109 |
function amp_post_template_add_styles( $amp_template ) {
|
110 |
$styles = $amp_template->get( 'post_amp_styles' );
|
111 |
if ( ! empty( $styles ) ) {
|
112 |
+
echo '/* Inline styles */' . PHP_EOL; // WPCS: XSS OK.
|
113 |
foreach ( $styles as $selector => $declarations ) {
|
114 |
$declarations = implode( ';', $declarations ) . ';';
|
115 |
+
printf( '%1$s{%2$s}', $selector, $declarations ); // WPCS: XSS OK.
|
116 |
}
|
117 |
}
|
118 |
}
|
119 |
|
120 |
+
/**
|
121 |
+
* Add analytics scripts.
|
122 |
+
*
|
123 |
+
* @param array $data Data.
|
124 |
+
* @return array Data.
|
125 |
+
*/
|
126 |
function amp_post_template_add_analytics_script( $data ) {
|
127 |
if ( ! empty( $data['amp_analytics'] ) ) {
|
128 |
$data['amp_component_scripts']['amp-analytics'] = 'https://cdn.ampproject.org/v0/amp-analytics-0.1.js';
|
130 |
return $data;
|
131 |
}
|
132 |
|
133 |
+
/**
|
134 |
+
* Print analytics data.
|
135 |
+
*
|
136 |
+
* @param AMP_Post_Template $amp_template Template.
|
137 |
+
*/
|
138 |
function amp_post_template_add_analytics_data( $amp_template ) {
|
139 |
$analytics_entries = $amp_template->get( 'amp_analytics' );
|
140 |
if ( empty( $analytics_entries ) ) {
|
143 |
|
144 |
foreach ( $analytics_entries as $id => $analytics_entry ) {
|
145 |
if ( ! isset( $analytics_entry['type'], $analytics_entry['attributes'], $analytics_entry['config_data'] ) ) {
|
146 |
+
/* translators: %1$s is analytics entry ID, %2$s is actual entry keys. */
|
147 |
+
_doing_it_wrong( __FUNCTION__, sprintf( esc_html__( 'Analytics entry for %1$s is missing one of the following keys: `type`, `attributes`, or `config_data` (array keys: %2$s)', 'amp' ), esc_html( $id ), esc_html( implode( ', ', array_keys( $analytics_entry ) ) ) ), '0.3.2' );
|
148 |
continue;
|
149 |
}
|
150 |
$script_element = AMP_HTML_Utils::build_tag( 'script', array(
|
152 |
), wp_json_encode( $analytics_entry['config_data'] ) );
|
153 |
|
154 |
$amp_analytics_attr = array_merge( array(
|
155 |
+
'id' => $id,
|
156 |
'type' => $analytics_entry['type'],
|
157 |
), $analytics_entry['attributes'] );
|
158 |
|
159 |
+
echo AMP_HTML_Utils::build_tag( 'amp-analytics', $amp_analytics_attr, $script_element ); // WPCS: XSS OK.
|
160 |
}
|
161 |
}
|
162 |
+
|
163 |
+
/**
|
164 |
+
* Add generator metadata.
|
165 |
+
*
|
166 |
+
* @since 6.0
|
167 |
+
*/
|
168 |
+
function amp_add_generator_metadata() {
|
169 |
+
printf( '<meta name="generator" content="%s" />', esc_attr( 'AMP Plugin v' . AMP__VERSION ) );
|
170 |
+
}
|
includes/class-amp-autoloader.php
ADDED
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Autoloader
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Autoload the classes used by the AMP plugin.
|
10 |
+
*
|
11 |
+
* Class AMP_Autoloader
|
12 |
+
*/
|
13 |
+
class AMP_Autoloader {
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Map of Classname to relative filepath sans extension.
|
17 |
+
*
|
18 |
+
* @note We omitted the leading slash and the .php extension from each
|
19 |
+
* relative filepath because they are redundant and to include
|
20 |
+
* them would take up unnecessary bytes of memory at runtime.
|
21 |
+
*
|
22 |
+
* @example Format (note no leading / and no .php extension):
|
23 |
+
*
|
24 |
+
* array(
|
25 |
+
* 'Class_Name1' => 'subdir-of-includes/filename1',
|
26 |
+
* 'Class_Name2' => '2nd-subdir-of-includes/filename2',
|
27 |
+
* );
|
28 |
+
*
|
29 |
+
* @var string[]
|
30 |
+
*/
|
31 |
+
private static $_classmap = array(
|
32 |
+
'AMP_Template_Customizer' => 'includes/admin/class-amp-customizer',
|
33 |
+
'AMP_Post_Meta_Box' => 'includes/admin/class-amp-post-meta-box',
|
34 |
+
'AMP_Post_Type_Support' => 'includes/class-amp-post-type-support',
|
35 |
+
'AMP_Base_Embed_Handler' => 'includes/embeds/class-amp-base-embed-handler',
|
36 |
+
'AMP_DailyMotion_Embed_Handler' => 'includes/embeds/class-amp-dailymotion-embed',
|
37 |
+
'AMP_Facebook_Embed_Handler' => 'includes/embeds/class-amp-facebook-embed',
|
38 |
+
'AMP_Gallery_Embed_Handler' => 'includes/embeds/class-amp-gallery-embed',
|
39 |
+
'AMP_Instagram_Embed_Handler' => 'includes/embeds/class-amp-instagram-embed',
|
40 |
+
'AMP_Pinterest_Embed_Handler' => 'includes/embeds/class-amp-pinterest-embed',
|
41 |
+
'AMP_SoundCloud_Embed_Handler' => 'includes/embeds/class-amp-soundcloud-embed',
|
42 |
+
'AMP_Twitter_Embed_Handler' => 'includes/embeds/class-amp-twitter-embed',
|
43 |
+
'AMP_Vimeo_Embed_Handler' => 'includes/embeds/class-amp-vimeo-embed',
|
44 |
+
'AMP_Vine_Embed_Handler' => 'includes/embeds/class-amp-vine-embed',
|
45 |
+
'AMP_YouTube_Embed_Handler' => 'includes/embeds/class-amp-youtube-embed',
|
46 |
+
'FastImage' => 'includes/lib/fastimage/class-fastimage',
|
47 |
+
'WillWashburn\Stream\Exception\StreamBufferTooSmallException' => 'includes/lib/fasterimage/Stream/Exception/StreamBufferTooSmallException',
|
48 |
+
'WillWashburn\Stream\StreamableInterface' => 'includes/lib/fasterimage/Stream/StreamableInterface',
|
49 |
+
'WillWashburn\Stream\Stream' => 'includes/lib/fasterimage/Stream/Stream',
|
50 |
+
'FasterImage\Exception\InvalidImageException' => 'includes/lib/fasterimage/Exception/InvalidImageException',
|
51 |
+
'FasterImage\ExifParser' => 'includes/lib/fasterimage/ExifParser',
|
52 |
+
'FasterImage\ImageParser' => 'includes/lib/fasterimage/ImageParser',
|
53 |
+
'FasterImage\FasterImage' => 'includes/lib/fasterimage/FasterImage',
|
54 |
+
'AMP_Analytics_Options_Submenu' => 'includes/options/class-amp-analytics-options-submenu',
|
55 |
+
'AMP_Options_Menu' => 'includes/options/class-amp-options-menu',
|
56 |
+
'AMP_Options_Manager' => 'includes/options/class-amp-options-manager',
|
57 |
+
'AMP_Analytics_Options_Submenu_Page' => 'includes/options/views/class-amp-analytics-options-submenu-page',
|
58 |
+
'AMP_Options_Menu_Page' => 'includes/options/views/class-amp-options-menu-page',
|
59 |
+
'AMP_Rule_Spec' => 'includes/sanitizers/class-amp-rule-spec',
|
60 |
+
'AMP_Allowed_Tags_Generated' => 'includes/sanitizers/class-amp-allowed-tags-generated',
|
61 |
+
'AMP_Audio_Sanitizer' => 'includes/sanitizers/class-amp-audio-sanitizer',
|
62 |
+
'AMP_Base_Sanitizer' => 'includes/sanitizers/class-amp-base-sanitizer',
|
63 |
+
'AMP_Blacklist_Sanitizer' => 'includes/sanitizers/class-amp-blacklist-sanitizer',
|
64 |
+
'AMP_Iframe_Sanitizer' => 'includes/sanitizers/class-amp-iframe-sanitizer',
|
65 |
+
'AMP_Img_Sanitizer' => 'includes/sanitizers/class-amp-img-sanitizer',
|
66 |
+
'AMP_Playbuzz_Sanitizer' => 'includes/sanitizers/class-amp-playbuzz-sanitizer',
|
67 |
+
'AMP_Style_Sanitizer' => 'includes/sanitizers/class-amp-style-sanitizer',
|
68 |
+
'AMP_Tag_And_Attribute_Sanitizer' => 'includes/sanitizers/class-amp-tag-and-attribute-sanitizer',
|
69 |
+
'AMP_Video_Sanitizer' => 'includes/sanitizers/class-amp-video-sanitizer',
|
70 |
+
'AMP_Customizer_Design_Settings' => 'includes/settings/class-amp-customizer-design-settings',
|
71 |
+
'AMP_Customizer_Settings' => 'includes/settings/class-amp-customizer-settings',
|
72 |
+
'AMP_Content' => 'includes/templates/class-amp-content',
|
73 |
+
'AMP_Content_Sanitizer' => 'includes/templates/class-amp-content-sanitizer',
|
74 |
+
'AMP_Post_Template' => 'includes/templates/class-amp-post-template',
|
75 |
+
'AMP_DOM_Utils' => 'includes/utils/class-amp-dom-utils',
|
76 |
+
'AMP_HTML_Utils' => 'includes/utils/class-amp-html-utils',
|
77 |
+
'AMP_Image_Dimension_Extractor' => 'includes/utils/class-amp-image-dimension-extractor',
|
78 |
+
'AMP_String_Utils' => 'includes/utils/class-amp-string-utils',
|
79 |
+
'AMP_WP_Utils' => 'includes/utils/class-amp-wp-utils',
|
80 |
+
'WPCOM_AMP_Polldaddy_Embed' => 'wpcom/class-amp-polldaddy-embed',
|
81 |
+
'AMP_Test_Stub_Sanitizer' => 'tests/stubs',
|
82 |
+
'AMP_Test_World_Sanitizer' => 'tests/stubs',
|
83 |
+
);
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Is registered.
|
87 |
+
*
|
88 |
+
* @var bool
|
89 |
+
*/
|
90 |
+
public static $is_registered = false;
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Perform the autoload on demand when requested by PHP runtime.
|
94 |
+
*
|
95 |
+
* Design Goal: Execute as few lines of code as possible each call.
|
96 |
+
*
|
97 |
+
* @since 0.6
|
98 |
+
*
|
99 |
+
* @param string $class_name Class name.
|
100 |
+
*/
|
101 |
+
protected static function autoload( $class_name ) {
|
102 |
+
if ( ! isset( self::$_classmap[ $class_name ] ) ) {
|
103 |
+
return;
|
104 |
+
}
|
105 |
+
$filepath = self::$_classmap[ $class_name ];
|
106 |
+
require AMP__DIR__ . "/{$filepath}.php";
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Registers this autoloader to PHP.
|
111 |
+
*
|
112 |
+
* @since 0.6
|
113 |
+
*
|
114 |
+
* Called at the end of this file; calling a second time has no effect.
|
115 |
+
*/
|
116 |
+
public static function register() {
|
117 |
+
if ( ! self::$is_registered ) {
|
118 |
+
spl_autoload_register( array( __CLASS__, 'autoload' ) );
|
119 |
+
self::$is_registered = true;
|
120 |
+
}
|
121 |
+
}
|
122 |
+
|
123 |
+
/**
|
124 |
+
* Allows an extensions plugin to register a class and its file for autoloading
|
125 |
+
*
|
126 |
+
* @since 0.6
|
127 |
+
*
|
128 |
+
* @param string $class_name Full classname (include namespace if applicable).
|
129 |
+
* @param string $filepath Absolute filepath to class file, including .php extension.
|
130 |
+
*/
|
131 |
+
public static function register_autoload_class( $class_name, $filepath ) {
|
132 |
+
self::$_classmap[ $class_name ] = '!' . $filepath;
|
133 |
+
}
|
134 |
+
}
|
includes/class-amp-post-type-support.php
ADDED
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* AMP Post type support.
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
* @since 0.6
|
7 |
+
*/
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Class AMP_Post_Type_Support.
|
11 |
+
*/
|
12 |
+
class AMP_Post_Type_Support {
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Get post types that plugin supports out of the box (which cannot be disabled).
|
16 |
+
*
|
17 |
+
* @return string[] Post types.
|
18 |
+
*/
|
19 |
+
public static function get_builtin_supported_post_types() {
|
20 |
+
return array_filter( array( 'post' ), 'post_type_exists' );
|
21 |
+
}
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Get post types that are eligible for AMP support.
|
25 |
+
*
|
26 |
+
* @since 0.6
|
27 |
+
* @return string[] Post types eligible for AMP.
|
28 |
+
*/
|
29 |
+
public static function get_eligible_post_types() {
|
30 |
+
return array_merge(
|
31 |
+
self::get_builtin_supported_post_types(),
|
32 |
+
array( 'page' ),
|
33 |
+
array_values( get_post_types(
|
34 |
+
array(
|
35 |
+
'public' => true,
|
36 |
+
'_builtin' => false,
|
37 |
+
),
|
38 |
+
'names'
|
39 |
+
) )
|
40 |
+
);
|
41 |
+
}
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Declare support for post types.
|
45 |
+
*
|
46 |
+
* This function should only be invoked through the 'after_setup_theme' action to
|
47 |
+
* allow plugins/theme to overwrite the post types support.
|
48 |
+
*
|
49 |
+
* @since 0.6
|
50 |
+
*/
|
51 |
+
public static function add_post_type_support() {
|
52 |
+
$post_types = array_merge(
|
53 |
+
self::get_builtin_supported_post_types(),
|
54 |
+
AMP_Options_Manager::get_option( 'supported_post_types', array() )
|
55 |
+
);
|
56 |
+
foreach ( $post_types as $post_type ) {
|
57 |
+
add_post_type_support( $post_type, AMP_QUERY_VAR );
|
58 |
+
}
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Return error codes for why a given post does not have AMP support.
|
63 |
+
*
|
64 |
+
* @since 0.6
|
65 |
+
*
|
66 |
+
* @param WP_Post|int $post Post.
|
67 |
+
* @return array Error codes for why a given post does not have AMP support.
|
68 |
+
*/
|
69 |
+
public static function get_support_errors( $post ) {
|
70 |
+
if ( ! ( $post instanceof WP_Post ) ) {
|
71 |
+
$post = get_post( $post );
|
72 |
+
}
|
73 |
+
$errors = array();
|
74 |
+
|
75 |
+
// Because `add_rewrite_endpoint` doesn't let us target specific post_types.
|
76 |
+
if ( ! post_type_supports( $post->post_type, AMP_QUERY_VAR ) ) {
|
77 |
+
$errors[] = 'post-type-support';
|
78 |
+
}
|
79 |
+
|
80 |
+
if ( post_password_required( $post ) ) {
|
81 |
+
$errors[] = 'password-protected';
|
82 |
+
}
|
83 |
+
|
84 |
+
/**
|
85 |
+
* Filters whether to skip the post from AMP.
|
86 |
+
*
|
87 |
+
* @since 0.3
|
88 |
+
*
|
89 |
+
* @param bool $skipped Skipped.
|
90 |
+
* @param int $post_id Post ID.
|
91 |
+
* @param WP_Post $post Post.
|
92 |
+
*/
|
93 |
+
if ( true === apply_filters( 'amp_skip_post', false, $post->ID, $post ) ) {
|
94 |
+
$errors[] = 'skip-post';
|
95 |
+
}
|
96 |
+
|
97 |
+
return $errors;
|
98 |
+
}
|
99 |
+
}
|
includes/embeds/class-amp-base-embed-handler.php
CHANGED
@@ -1,8 +1,15 @@
|
|
1 |
<?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
abstract class AMP_Base_Embed_Handler {
|
7 |
protected $DEFAULT_WIDTH = 600;
|
8 |
protected $DEFAULT_HEIGHT = 480;
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Base_Embed_Handler
|
4 |
+
*
|
5 |
+
* Used by some children.
|
6 |
+
*
|
7 |
+
* @package AMP
|
8 |
+
*/
|
9 |
|
10 |
+
/**
|
11 |
+
* Class AMP_Base_Embed_Handler
|
12 |
+
*/
|
13 |
abstract class AMP_Base_Embed_Handler {
|
14 |
protected $DEFAULT_WIDTH = 600;
|
15 |
protected $DEFAULT_HEIGHT = 480;
|
includes/embeds/class-amp-dailymotion-embed.php
CHANGED
@@ -1,8 +1,15 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
class AMP_DailyMotion_Embed_Handler extends AMP_Base_Embed_Handler {
|
7 |
|
8 |
const URL_PATTERN = '#https?:\/\/(www\.)?dailymotion\.com\/video\/.*#i';
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_DailyMotion_Embed_Handler
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class AMP_DailyMotion_Embed_Handler
|
10 |
+
*
|
11 |
+
* Much of this class is borrowed from Jetpack embeds
|
12 |
+
*/
|
13 |
class AMP_DailyMotion_Embed_Handler extends AMP_Base_Embed_Handler {
|
14 |
|
15 |
const URL_PATTERN = '#https?:\/\/(www\.)?dailymotion\.com\/video\/.*#i';
|
includes/embeds/class-amp-facebook-embed.php
CHANGED
@@ -1,7 +1,13 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
4 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
class AMP_Facebook_Embed_Handler extends AMP_Base_Embed_Handler {
|
6 |
const URL_PATTERN = '#https?://(www\.)?facebook\.com/.*#i';
|
7 |
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Facebook_Embed_Handler
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class AMP_Facebook_Embed_Handler
|
10 |
+
*/
|
11 |
class AMP_Facebook_Embed_Handler extends AMP_Base_Embed_Handler {
|
12 |
const URL_PATTERN = '#https?://(www\.)?facebook\.com/.*#i';
|
13 |
|
includes/embeds/class-amp-gallery-embed.php
CHANGED
@@ -1,7 +1,13 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
4 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
class AMP_Gallery_Embed_Handler extends AMP_Base_Embed_Handler {
|
6 |
private static $script_slug = 'amp-carousel';
|
7 |
private static $script_src = 'https://cdn.ampproject.org/v0/amp-carousel-0.1.js';
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Gallery_Embed_Handler
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class AMP_Gallery_Embed_Handler
|
10 |
+
*/
|
11 |
class AMP_Gallery_Embed_Handler extends AMP_Base_Embed_Handler {
|
12 |
private static $script_slug = 'amp-carousel';
|
13 |
private static $script_src = 'https://cdn.ampproject.org/v0/amp-carousel-0.1.js';
|
includes/embeds/class-amp-instagram-embed.php
CHANGED
@@ -1,8 +1,15 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
class AMP_Instagram_Embed_Handler extends AMP_Base_Embed_Handler {
|
7 |
const SHORT_URL_HOST = 'instagr.am';
|
8 |
const URL_PATTERN = '#http(s?)://(www\.)?instagr(\.am|am\.com)/p/([^/?]+)#i';
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Instagram_Embed_Handler
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class AMP_Instagram_Embed_Handler
|
10 |
+
*
|
11 |
+
* Much of this class is borrowed from Jetpack embeds
|
12 |
+
*/
|
13 |
class AMP_Instagram_Embed_Handler extends AMP_Base_Embed_Handler {
|
14 |
const SHORT_URL_HOST = 'instagr.am';
|
15 |
const URL_PATTERN = '#http(s?)://(www\.)?instagr(\.am|am\.com)/p/([^/?]+)#i';
|
includes/embeds/class-amp-pinterest-embed.php
CHANGED
@@ -1,7 +1,13 @@
|
|
1 |
<?php
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
-
|
4 |
-
|
|
|
5 |
class AMP_Pinterest_Embed_Handler extends AMP_Base_Embed_Handler {
|
6 |
|
7 |
const URL_PATTERN = '#https?://(www\.)?pinterest\.com/pin/.*#i';
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Pinterest_Embed_Handler
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
|
8 |
+
/**
|
9 |
+
* Class AMP_Pinterest_Embed_Handler
|
10 |
+
*/
|
11 |
class AMP_Pinterest_Embed_Handler extends AMP_Base_Embed_Handler {
|
12 |
|
13 |
const URL_PATTERN = '#https?://(www\.)?pinterest\.com/pin/.*#i';
|
includes/embeds/class-amp-soundcloud-embed.php
CHANGED
@@ -1,24 +1,59 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
4 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
class AMP_SoundCloud_Embed_Handler extends AMP_Base_Embed_Handler {
|
6 |
-
|
|
|
|
|
|
|
|
|
|
|
7 |
protected $DEFAULT_HEIGHT = 200;
|
8 |
|
|
|
|
|
|
|
|
|
|
|
9 |
private static $script_slug = 'amp-soundcloud';
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
private static $script_src = 'https://cdn.ampproject.org/v0/amp-soundcloud-0.1.js';
|
11 |
|
|
|
|
|
|
|
12 |
public function register_embed() {
|
13 |
-
wp_embed_register_handler( 'amp-soundcloud', self::URL_PATTERN, array( $this, 'oembed' ), -1 );
|
14 |
add_shortcode( 'soundcloud', array( $this, 'shortcode' ) );
|
|
|
15 |
}
|
16 |
|
|
|
|
|
|
|
17 |
public function unregister_embed() {
|
18 |
-
wp_embed_unregister_handler( 'amp-soundcloud', -1 );
|
19 |
remove_shortcode( 'soundcloud' );
|
|
|
20 |
}
|
21 |
|
|
|
|
|
|
|
|
|
|
|
22 |
public function get_scripts() {
|
23 |
if ( ! $this->did_convert_elements ) {
|
24 |
return array();
|
@@ -27,21 +62,81 @@ class AMP_SoundCloud_Embed_Handler extends AMP_Base_Embed_Handler {
|
|
27 |
return array( self::$script_slug => self::$script_src );
|
28 |
}
|
29 |
|
30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
$track_id = $this->get_track_id_from_url( $url );
|
32 |
-
return $this->render(
|
33 |
-
'track_id' => $track_id,
|
34 |
-
) );
|
35 |
}
|
36 |
|
37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
|
39 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
|
41 |
-
|
42 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
} else {
|
44 |
-
$url =
|
|
|
|
|
|
|
|
|
45 |
if ( isset( $attr['url'] ) ) {
|
46 |
$url = $attr['url'];
|
47 |
} elseif ( isset( $attr[0] ) ) {
|
@@ -50,27 +145,28 @@ class AMP_SoundCloud_Embed_Handler extends AMP_Base_Embed_Handler {
|
|
50 |
$url = shortcode_new_to_old_params( $attr );
|
51 |
}
|
52 |
|
53 |
-
if (
|
54 |
-
$
|
55 |
}
|
56 |
}
|
57 |
-
|
58 |
-
if ( empty( $track_id ) ) {
|
59 |
-
return '';
|
60 |
-
}
|
61 |
-
|
62 |
-
return $this->render( array(
|
63 |
-
'track_id' => $track_id,
|
64 |
-
) );
|
65 |
}
|
66 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
public function render( $args ) {
|
68 |
$args = wp_parse_args( $args, array(
|
69 |
'track_id' => false,
|
|
|
70 |
) );
|
71 |
|
72 |
if ( empty( $args['track_id'] ) ) {
|
73 |
-
return
|
74 |
}
|
75 |
|
76 |
$this->did_convert_elements = true;
|
@@ -79,17 +175,40 @@ class AMP_SoundCloud_Embed_Handler extends AMP_Base_Embed_Handler {
|
|
79 |
'amp-soundcloud',
|
80 |
array(
|
81 |
'data-trackid' => $args['track_id'],
|
82 |
-
'layout'
|
83 |
-
'height'
|
84 |
)
|
85 |
);
|
86 |
}
|
87 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
88 |
private function get_track_id_from_url( $url ) {
|
89 |
$parsed_url = AMP_WP_Utils::parse_url( $url );
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
return $track_id;
|
94 |
}
|
95 |
}
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_SoundCloud_Embed_Handler
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class AMP_SoundCloud_Embed_Handler
|
10 |
+
*
|
11 |
+
* @since 0.5
|
12 |
+
*/
|
13 |
class AMP_SoundCloud_Embed_Handler extends AMP_Base_Embed_Handler {
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Default height.
|
17 |
+
*
|
18 |
+
* @var int
|
19 |
+
*/
|
20 |
protected $DEFAULT_HEIGHT = 200;
|
21 |
|
22 |
+
/**
|
23 |
+
* Script slug.
|
24 |
+
*
|
25 |
+
* @var string
|
26 |
+
*/
|
27 |
private static $script_slug = 'amp-soundcloud';
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Script source.
|
31 |
+
*
|
32 |
+
* @var string
|
33 |
+
*/
|
34 |
private static $script_src = 'https://cdn.ampproject.org/v0/amp-soundcloud-0.1.js';
|
35 |
|
36 |
+
/**
|
37 |
+
* Register embed.
|
38 |
+
*/
|
39 |
public function register_embed() {
|
|
|
40 |
add_shortcode( 'soundcloud', array( $this, 'shortcode' ) );
|
41 |
+
add_filter( 'embed_oembed_html', array( $this, 'filter_embed_oembed_html' ), 10, 2 );
|
42 |
}
|
43 |
|
44 |
+
/**
|
45 |
+
* Unregister embed.
|
46 |
+
*/
|
47 |
public function unregister_embed() {
|
|
|
48 |
remove_shortcode( 'soundcloud' );
|
49 |
+
remove_filter( 'embed_oembed_html', array( $this, 'filter_embed_oembed_html' ), 10 );
|
50 |
}
|
51 |
|
52 |
+
/**
|
53 |
+
* Get scripts needed by component.
|
54 |
+
*
|
55 |
+
* @return array Scripts.
|
56 |
+
*/
|
57 |
public function get_scripts() {
|
58 |
if ( ! $this->did_convert_elements ) {
|
59 |
return array();
|
62 |
return array( self::$script_slug => self::$script_src );
|
63 |
}
|
64 |
|
65 |
+
/**
|
66 |
+
* Render oEmbed.
|
67 |
+
*
|
68 |
+
* @see \WP_Embed::shortcode()
|
69 |
+
*
|
70 |
+
* @deprecated Core's oEmbed handler is now used instead, with embed_oembed_html filter used to convert to AMP.
|
71 |
+
* @param array $matches URL pattern matches.
|
72 |
+
* @param array $attr Shortcode attribues.
|
73 |
+
* @param string $url URL.
|
74 |
+
* @return string Rendered oEmbed.
|
75 |
+
*/
|
76 |
+
public function oembed( $matches, $attr, $url ) {
|
77 |
+
_deprecated_function( __METHOD__, '0.6' );
|
78 |
+
unset( $matches, $attr );
|
79 |
$track_id = $this->get_track_id_from_url( $url );
|
80 |
+
return $this->render( compact( 'track_id' ) );
|
|
|
|
|
81 |
}
|
82 |
|
83 |
+
/**
|
84 |
+
* Filter oEmbed HTML for SoundCloud to convert to AMP.
|
85 |
+
*
|
86 |
+
* @param string $cache Cache for oEmbed.
|
87 |
+
* @param string $url Embed URL.
|
88 |
+
* @return string Embed.
|
89 |
+
*/
|
90 |
+
public function filter_embed_oembed_html( $cache, $url ) {
|
91 |
+
$parsed_url = wp_parse_url( $url );
|
92 |
+
if ( false === strpos( $parsed_url['host'], 'soundcloud.com' ) ) {
|
93 |
+
return $cache;
|
94 |
+
}
|
95 |
+
return $this->parse_amp_component_from_iframe( $cache );
|
96 |
+
}
|
97 |
|
98 |
+
/**
|
99 |
+
* Parse AMP component from iframe.
|
100 |
+
*
|
101 |
+
* @param string $html HTML.
|
102 |
+
* @return string AMP component or empty if unable to determine SoundCloud ID.
|
103 |
+
*/
|
104 |
+
private function parse_amp_component_from_iframe( $html ) {
|
105 |
+
$embed = '';
|
106 |
+
if ( preg_match( '#<iframe.+?src="(?P<url>.+?)".*>#', $html, $matches ) ) {
|
107 |
+
$src = html_entity_decode( $matches['url'], ENT_QUOTES );
|
108 |
+
$query = array();
|
109 |
+
parse_str( wp_parse_url( $src, PHP_URL_QUERY ), $query );
|
110 |
+
if ( ! empty( $query['url'] ) ) {
|
111 |
+
$embed = $this->render( array(
|
112 |
+
'track_id' => $this->get_track_id_from_url( $query['url'] ),
|
113 |
+
) );
|
114 |
+
}
|
115 |
+
}
|
116 |
+
return $embed;
|
117 |
+
}
|
118 |
|
119 |
+
/**
|
120 |
+
* Render shortcode.
|
121 |
+
*
|
122 |
+
* @param array $attr Shortcode attributes.
|
123 |
+
* @param string $content Shortcode content.
|
124 |
+
* @return string Rendered shortcode.
|
125 |
+
*/
|
126 |
+
public function shortcode( $attr, $content = null ) {
|
127 |
+
$output = '';
|
128 |
+
if ( function_exists( 'soundcloud_shortcode' ) ) {
|
129 |
+
if ( empty( $attr['url'] ) && ! empty( $attr['id'] ) ) {
|
130 |
+
$attr['url'] = 'https://api.soundcloud.com/tracks/' . intval( $attr['id'] );
|
131 |
+
}
|
132 |
+
$output = soundcloud_shortcode( $attr, $content );
|
133 |
+
$output = $this->parse_amp_component_from_iframe( $output );
|
134 |
} else {
|
135 |
+
$url = null;
|
136 |
+
if ( isset( $attr['id'] ) ) {
|
137 |
+
$url = 'https://w.soundcloud.com/player/?url=https%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F' . intval( $attr['id'] );
|
138 |
+
}
|
139 |
+
|
140 |
if ( isset( $attr['url'] ) ) {
|
141 |
$url = $attr['url'];
|
142 |
} elseif ( isset( $attr[0] ) ) {
|
145 |
$url = shortcode_new_to_old_params( $attr );
|
146 |
}
|
147 |
|
148 |
+
if ( $url ) {
|
149 |
+
$output = $this->render_embed_fallback( $url );
|
150 |
}
|
151 |
}
|
152 |
+
return $output;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
153 |
}
|
154 |
|
155 |
+
/**
|
156 |
+
* Render embed.
|
157 |
+
*
|
158 |
+
* @param array $args Args.
|
159 |
+
* @return string Rendered embed.
|
160 |
+
* @global WP_Embed $wp_embed
|
161 |
+
*/
|
162 |
public function render( $args ) {
|
163 |
$args = wp_parse_args( $args, array(
|
164 |
'track_id' => false,
|
165 |
+
'url' => null,
|
166 |
) );
|
167 |
|
168 |
if ( empty( $args['track_id'] ) ) {
|
169 |
+
return $this->render_embed_fallback( $args['url'] );
|
170 |
}
|
171 |
|
172 |
$this->did_convert_elements = true;
|
175 |
'amp-soundcloud',
|
176 |
array(
|
177 |
'data-trackid' => $args['track_id'],
|
178 |
+
'layout' => 'fixed-height',
|
179 |
+
'height' => $this->args['height'],
|
180 |
)
|
181 |
);
|
182 |
}
|
183 |
|
184 |
+
/**
|
185 |
+
* Render embed fallback.
|
186 |
+
*
|
187 |
+
* @param string $url URL.
|
188 |
+
* @returns string
|
189 |
+
*/
|
190 |
+
private function render_embed_fallback( $url ) {
|
191 |
+
return AMP_HTML_Utils::build_tag( 'a',
|
192 |
+
array(
|
193 |
+
'href' => esc_url( $url ),
|
194 |
+
'class' => 'amp-wp-embed-fallback',
|
195 |
+
),
|
196 |
+
esc_html( $url )
|
197 |
+
);
|
198 |
+
}
|
199 |
+
|
200 |
+
/**
|
201 |
+
* Get track_id from URL.
|
202 |
+
*
|
203 |
+
* @param string $url URL.
|
204 |
+
*
|
205 |
+
* @return string Track ID or empty string if none matched.
|
206 |
+
*/
|
207 |
private function get_track_id_from_url( $url ) {
|
208 |
$parsed_url = AMP_WP_Utils::parse_url( $url );
|
209 |
+
if ( ! preg_match( '#tracks/(?P<track_id>[^/]+)#', $parsed_url['path'], $matches ) ) {
|
210 |
+
return '';
|
211 |
+
}
|
212 |
+
return $matches['track_id'];
|
213 |
}
|
214 |
}
|
includes/embeds/class-amp-twitter-embed.php
CHANGED
@@ -1,8 +1,15 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
class AMP_Twitter_Embed_Handler extends AMP_Base_Embed_Handler {
|
7 |
const URL_PATTERN = '#http(s|):\/\/twitter\.com(\/\#\!\/|\/)([a-zA-Z0-9_]{1,20})\/status(es)*\/(\d+)#i';
|
8 |
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Twitter_Embed_Handler
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class AMP_Twitter_Embed_Handler
|
10 |
+
*
|
11 |
+
* Much of this class is borrowed from Jetpack embeds
|
12 |
+
*/
|
13 |
class AMP_Twitter_Embed_Handler extends AMP_Base_Embed_Handler {
|
14 |
const URL_PATTERN = '#http(s|):\/\/twitter\.com(\/\#\!\/|\/)([a-zA-Z0-9_]{1,20})\/status(es)*\/(\d+)#i';
|
15 |
|
includes/embeds/class-amp-vimeo-embed.php
CHANGED
@@ -1,8 +1,15 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
class AMP_Vimeo_Embed_Handler extends AMP_Base_Embed_Handler {
|
7 |
|
8 |
const URL_PATTERN = '#https?:\/\/(www\.)?vimeo\.com\/.*#i';
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Vimeo_Embed_Handler
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class AMP_Vimeo_Embed_Handler
|
10 |
+
*
|
11 |
+
* Much of this class is borrowed from Jetpack embeds
|
12 |
+
*/
|
13 |
class AMP_Vimeo_Embed_Handler extends AMP_Base_Embed_Handler {
|
14 |
|
15 |
const URL_PATTERN = '#https?:\/\/(www\.)?vimeo\.com\/.*#i';
|
includes/embeds/class-amp-vine-embed.php
CHANGED
@@ -1,7 +1,13 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
4 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
class AMP_Vine_Embed_Handler extends AMP_Base_Embed_Handler {
|
6 |
const URL_PATTERN = '#https?://vine\.co/v/([^/?]+)#i';
|
7 |
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Vine_Embed_Handler
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class AMP_Vine_Embed_Handler
|
10 |
+
*/
|
11 |
class AMP_Vine_Embed_Handler extends AMP_Base_Embed_Handler {
|
12 |
const URL_PATTERN = '#https?://vine\.co/v/([^/?]+)#i';
|
13 |
|
includes/embeds/class-amp-youtube-embed.php
CHANGED
@@ -1,8 +1,15 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
class AMP_YouTube_Embed_Handler extends AMP_Base_Embed_Handler {
|
7 |
const SHORT_URL_HOST = 'youtu.be';
|
8 |
// Only handling single videos. Playlists are handled elsewhere.
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_YouTube_Embed_Handler
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class AMP_YouTube_Embed_Handler
|
10 |
+
*
|
11 |
+
* Much of this class is borrowed from Jetpack embeds.
|
12 |
+
*/
|
13 |
class AMP_YouTube_Embed_Handler extends AMP_Base_Embed_Handler {
|
14 |
const SHORT_URL_HOST = 'youtu.be';
|
15 |
// Only handling single videos. Playlists are handled elsewhere.
|
includes/lib/fasterimage/amp-fasterimage.php
CHANGED
@@ -1,25 +1,27 @@
|
|
1 |
<?php
|
|
|
|
|
|
|
|
|
|
|
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
function amp_load_fasterimage_classes() {
|
4 |
-
|
5 |
-
$fasterimage__DIR__ = dirname( __FILE__ );
|
6 |
-
|
7 |
-
// Stream files
|
8 |
-
require_once( $fasterimage__DIR__ . '/Stream/Exception/StreamBufferTooSmallException.php' );
|
9 |
-
require_once( $fasterimage__DIR__ . '/Stream/StreamableInterface.php' );
|
10 |
-
require_once( $fasterimage__DIR__ . '/Stream/Stream.php' );
|
11 |
-
|
12 |
-
// FasterImage files
|
13 |
-
require_once( $fasterimage__DIR__ . '/Exception/InvalidImageException.php' );
|
14 |
-
require_once( $fasterimage__DIR__ . '/ExifParser.php' );
|
15 |
-
require_once( $fasterimage__DIR__ . '/ImageParser.php' );
|
16 |
-
require_once( $fasterimage__DIR__ . '/FasterImage.php' );
|
17 |
}
|
18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
function amp_get_fasterimage_client( $user_agent ) {
|
20 |
-
if ( ! class_exists( 'FasterImage\FasterImage' ) ) {
|
21 |
-
amp_load_fasterimage_classes();
|
22 |
-
}
|
23 |
-
|
24 |
return new FasterImage\FasterImage( $user_agent );
|
25 |
}
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Functions for FasterImage.
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
|
8 |
+
/**
|
9 |
+
* Load classes for FasterImage.
|
10 |
+
*
|
11 |
+
* This is obsolete now that there is an autoloader.
|
12 |
+
*
|
13 |
+
* @deprecated
|
14 |
+
*/
|
15 |
function amp_load_fasterimage_classes() {
|
16 |
+
_deprecated_function( __FUNCTION__, '0.6' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
}
|
18 |
|
19 |
+
/**
|
20 |
+
* Get FasterImage client for user agent.
|
21 |
+
*
|
22 |
+
* @param string $user_agent User Agent.
|
23 |
+
* @return \FasterImage\FasterImage Instance.
|
24 |
+
*/
|
25 |
function amp_get_fasterimage_client( $user_agent ) {
|
|
|
|
|
|
|
|
|
26 |
return new FasterImage\FasterImage( $user_agent );
|
27 |
}
|
includes/options/class-amp-analytics-options-submenu.php
CHANGED
@@ -1,8 +1,13 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
|
|
|
|
|
|
|
|
|
|
6 |
class AMP_Analytics_Options_Submenu {
|
7 |
|
8 |
private $parent_menu_slug;
|
@@ -37,7 +42,10 @@ class AMP_Analytics_Options_Submenu {
|
|
37 |
public function amp_options_styles() {
|
38 |
?>
|
39 |
<style>
|
40 |
-
.analytics-data-container
|
|
|
|
|
|
|
41 |
background: red;
|
42 |
border-color: red;
|
43 |
text-shadow: 0 0 0;
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Analytics_Options_Submenu
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class AMP_Analytics_Options_Submenu
|
10 |
+
*/
|
11 |
class AMP_Analytics_Options_Submenu {
|
12 |
|
13 |
private $parent_menu_slug;
|
42 |
public function amp_options_styles() {
|
43 |
?>
|
44 |
<style>
|
45 |
+
.analytics-data-container .button.delete,
|
46 |
+
.analytics-data-container .button.delete:hover,
|
47 |
+
.analytics-data-container .button.delete:active,
|
48 |
+
.analytics-data-container .button.delete:focus {
|
49 |
background: red;
|
50 |
border-color: red;
|
51 |
text-shadow: 0 0 0;
|
includes/options/class-amp-options-manager.php
ADDED
@@ -0,0 +1,244 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Options_Manager.
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class AMP_Options_Manager
|
10 |
+
*/
|
11 |
+
class AMP_Options_Manager {
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Option name.
|
15 |
+
*
|
16 |
+
* @var string
|
17 |
+
*/
|
18 |
+
const OPTION_NAME = 'amp-options';
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Register settings.
|
22 |
+
*/
|
23 |
+
public static function register_settings() {
|
24 |
+
register_setting(
|
25 |
+
self::OPTION_NAME,
|
26 |
+
self::OPTION_NAME,
|
27 |
+
array(
|
28 |
+
'type' => 'array',
|
29 |
+
'sanitize_callback' => array( __CLASS__, 'validate_options' ),
|
30 |
+
)
|
31 |
+
);
|
32 |
+
|
33 |
+
add_action( 'update_option_' . self::OPTION_NAME, 'flush_rewrite_rules' );
|
34 |
+
}
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Get plugin options.
|
38 |
+
*
|
39 |
+
* @return array Options.
|
40 |
+
*/
|
41 |
+
public static function get_options() {
|
42 |
+
return get_option( self::OPTION_NAME, array() );
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Get plugin option.
|
47 |
+
*
|
48 |
+
* @param string $option Plugin option name.
|
49 |
+
* @param bool $default Default value.
|
50 |
+
*
|
51 |
+
* @return mixed Option value.
|
52 |
+
*/
|
53 |
+
public static function get_option( $option, $default = false ) {
|
54 |
+
$amp_options = self::get_options();
|
55 |
+
|
56 |
+
if ( ! isset( $amp_options[ $option ] ) ) {
|
57 |
+
return $default;
|
58 |
+
}
|
59 |
+
|
60 |
+
return $amp_options[ $option ];
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Validate options.
|
65 |
+
*
|
66 |
+
* @param array $new_options Plugin options.
|
67 |
+
* @return array Options.
|
68 |
+
*/
|
69 |
+
public static function validate_options( $new_options ) {
|
70 |
+
$defaults = array(
|
71 |
+
'supported_post_types' => array(),
|
72 |
+
'analytics' => array(),
|
73 |
+
);
|
74 |
+
|
75 |
+
$options = array_merge(
|
76 |
+
$defaults,
|
77 |
+
self::get_options()
|
78 |
+
);
|
79 |
+
|
80 |
+
// Validate post type support.
|
81 |
+
if ( isset( $new_options['supported_post_types'] ) ) {
|
82 |
+
$options['supported_post_types'] = array();
|
83 |
+
foreach ( $new_options['supported_post_types'] as $post_type ) {
|
84 |
+
if ( ! post_type_exists( $post_type ) ) {
|
85 |
+
add_settings_error( self::OPTION_NAME, 'unknown_post_type', __( 'Unrecognized post type.', 'amp' ) );
|
86 |
+
} else {
|
87 |
+
$options['supported_post_types'][] = $post_type;
|
88 |
+
}
|
89 |
+
}
|
90 |
+
}
|
91 |
+
|
92 |
+
// Validate analytics.
|
93 |
+
if ( isset( $new_options['analytics'] ) ) {
|
94 |
+
foreach ( $new_options['analytics'] as $id => $data ) {
|
95 |
+
|
96 |
+
// Check save/delete pre-conditions and proceed if correct.
|
97 |
+
if ( empty( $data['type'] ) || empty( $data['config'] ) ) {
|
98 |
+
add_settings_error( self::OPTION_NAME, 'missing_analytics_vendor_or_config', __( 'Missing vendor type or config.', 'amp' ) );
|
99 |
+
continue;
|
100 |
+
}
|
101 |
+
|
102 |
+
// Validate JSON configuration.
|
103 |
+
$is_valid_json = AMP_HTML_Utils::is_valid_json( $data['config'] );
|
104 |
+
if ( ! $is_valid_json ) {
|
105 |
+
add_settings_error( self::OPTION_NAME, 'invalid_analytics_config_json', __( 'Invalid analytics config JSON.', 'amp' ) );
|
106 |
+
continue;
|
107 |
+
}
|
108 |
+
|
109 |
+
$entry_vendor_type = sanitize_key( $data['type'] );
|
110 |
+
$entry_config = trim( $data['config'] );
|
111 |
+
|
112 |
+
if ( ! empty( $data['id'] ) && '__new__' !== $data['id'] ) {
|
113 |
+
$entry_id = sanitize_key( $data['id'] );
|
114 |
+
} else {
|
115 |
+
|
116 |
+
// Generate a hash string to uniquely identify this entry.
|
117 |
+
$entry_id = substr( md5( $entry_vendor_type . $entry_config ), 0, 12 );
|
118 |
+
|
119 |
+
// Avoid duplicates.
|
120 |
+
if ( isset( $options['analytics'][ $entry_id ] ) ) {
|
121 |
+
add_settings_error( self::OPTION_NAME, 'duplicate_analytics_entry', __( 'Duplicate analytics entry found.', 'amp' ) );
|
122 |
+
continue;
|
123 |
+
}
|
124 |
+
}
|
125 |
+
|
126 |
+
if ( isset( $data['delete'] ) ) {
|
127 |
+
unset( $options['analytics'][ $entry_id ] );
|
128 |
+
} else {
|
129 |
+
$options['analytics'][ $entry_id ] = array(
|
130 |
+
'type' => $entry_vendor_type,
|
131 |
+
'config' => $entry_config,
|
132 |
+
);
|
133 |
+
}
|
134 |
+
}
|
135 |
+
}
|
136 |
+
|
137 |
+
return $options;
|
138 |
+
}
|
139 |
+
|
140 |
+
|
141 |
+
/**
|
142 |
+
* Check for errors with updating the supported post types.
|
143 |
+
*
|
144 |
+
* @since 0.6
|
145 |
+
* @see add_settings_error()
|
146 |
+
*/
|
147 |
+
public static function check_supported_post_type_update_errors() {
|
148 |
+
$builtin_support = AMP_Post_Type_Support::get_builtin_supported_post_types();
|
149 |
+
$supported_types = self::get_option( 'supported_post_types', array() );
|
150 |
+
foreach ( AMP_Post_Type_Support::get_eligible_post_types() as $name ) {
|
151 |
+
$post_type = get_post_type_object( $name );
|
152 |
+
if ( empty( $post_type ) || in_array( $post_type->name, $builtin_support, true ) ) {
|
153 |
+
continue;
|
154 |
+
}
|
155 |
+
|
156 |
+
$post_type_supported = post_type_supports( $post_type->name, AMP_QUERY_VAR );
|
157 |
+
$is_support_elected = in_array( $post_type->name, $supported_types, true );
|
158 |
+
|
159 |
+
$error = null;
|
160 |
+
$code = null;
|
161 |
+
if ( $is_support_elected && ! $post_type_supported ) {
|
162 |
+
/* translators: %s: Post type name. */
|
163 |
+
$error = __( '"%s" could not be activated because support is removed by a plugin or theme', 'amp' );
|
164 |
+
$code = sprintf( '%s_activation_error', $post_type->name );
|
165 |
+
} elseif ( ! $is_support_elected && $post_type_supported ) {
|
166 |
+
/* translators: %s: Post type name. */
|
167 |
+
$error = __( '"%s" could not be deactivated because support is added by a plugin or theme', 'amp' );
|
168 |
+
$code = sprintf( '%s_deactivation_error', $post_type->name );
|
169 |
+
}
|
170 |
+
|
171 |
+
if ( isset( $error, $code ) ) {
|
172 |
+
add_settings_error(
|
173 |
+
self::OPTION_NAME,
|
174 |
+
$code,
|
175 |
+
sprintf(
|
176 |
+
$error,
|
177 |
+
isset( $post_type->label ) ? $post_type->label : $post_type->name
|
178 |
+
)
|
179 |
+
);
|
180 |
+
}
|
181 |
+
}
|
182 |
+
}
|
183 |
+
|
184 |
+
/**
|
185 |
+
* Update plugin option.
|
186 |
+
*
|
187 |
+
* @param string $option Plugin option name.
|
188 |
+
* @param mixed $value Plugin option value.
|
189 |
+
*
|
190 |
+
* @return bool Whether update succeeded.
|
191 |
+
*/
|
192 |
+
public static function update_option( $option, $value ) {
|
193 |
+
$amp_options = self::get_options();
|
194 |
+
|
195 |
+
$amp_options[ $option ] = $value;
|
196 |
+
|
197 |
+
return update_option( self::OPTION_NAME, $amp_options, false );
|
198 |
+
}
|
199 |
+
|
200 |
+
/**
|
201 |
+
* Handle analytics submission.
|
202 |
+
*/
|
203 |
+
public static function handle_analytics_submit() {
|
204 |
+
|
205 |
+
// Request must come from user with right capabilities.
|
206 |
+
if ( ! current_user_can( 'manage_options' ) ) {
|
207 |
+
wp_die( esc_html__( 'Sorry, you do not have the necessary permissions to perform this action', 'amp' ) );
|
208 |
+
}
|
209 |
+
|
210 |
+
// Ensure request is coming from analytics option form.
|
211 |
+
check_admin_referer( 'analytics-options', 'analytics-options' );
|
212 |
+
|
213 |
+
if ( isset( $_POST['amp-options']['analytics'] ) ) {
|
214 |
+
self::update_option( 'analytics', wp_unslash( $_POST['amp-options']['analytics'] ) );
|
215 |
+
|
216 |
+
$errors = get_settings_errors( self::OPTION_NAME );
|
217 |
+
if ( empty( $errors ) ) {
|
218 |
+
add_settings_error( self::OPTION_NAME, 'settings_updated', __( 'The analytics entry was successfully saved!', 'amp' ), 'updated' );
|
219 |
+
$errors = get_settings_errors( self::OPTION_NAME );
|
220 |
+
}
|
221 |
+
set_transient( 'settings_errors', $errors );
|
222 |
+
}
|
223 |
+
|
224 |
+
/*
|
225 |
+
* Redirect to keep the user in the analytics options page.
|
226 |
+
* Wrap in is_admin() to enable phpunit tests to exercise this code.
|
227 |
+
*/
|
228 |
+
wp_safe_redirect( admin_url( 'admin.php?page=amp-analytics-options&settings-updated=1' ) );
|
229 |
+
exit;
|
230 |
+
}
|
231 |
+
|
232 |
+
/**
|
233 |
+
* Update analytics options.
|
234 |
+
*
|
235 |
+
* @codeCoverageIgnore
|
236 |
+
* @deprecated
|
237 |
+
* @param array $data Unsanitized unslashed data.
|
238 |
+
* @return bool Whether options were updated.
|
239 |
+
*/
|
240 |
+
public static function update_analytics_options( $data ) {
|
241 |
+
_deprecated_function( __METHOD__, '0.6', __CLASS__ . '::update_option' );
|
242 |
+
return self::update_option( 'analytics', wp_unslash( $data ) );
|
243 |
+
}
|
244 |
+
}
|
includes/options/class-amp-options-menu.php
CHANGED
@@ -1,54 +1,133 @@
|
|
1 |
<?php
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
class AMP_Options_Menu {
|
8 |
-
const ICON_BASE64_SVG = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyB3aWR0aD0iNjJweCIgaGVpZ2h0PSI2MnB4IiB2aWV3Qm94PSIwIDAgNjIgNjIiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+ICAgICAgICA8dGl0bGU+QU1QLUJyYW5kLUJsYWNrLUljb248L3RpdGxlPiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4gICAgPGRlZnM+PC9kZWZzPiAgICA8ZyBpZD0iYW1wLWxvZ28taW50ZXJuYWwtc2l0ZSIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+ICAgICAgICA8ZyBpZD0iQU1QLUJyYW5kLUJsYWNrLUljb24iIGZpbGw9IiMwMDAwMDAiPiAgICAgICAgICAgIDxwYXRoIGQ9Ik00MS42Mjg4NjY3LDI4LjE2MTQzMzMgTDI4LjYyNDM2NjcsNDkuODAzNTY2NyBMMjYuMjY4MzY2Nyw0OS44MDM1NjY3IEwyOC41OTc1LDM1LjcwMTY2NjcgTDIxLjM4MzgsMzUuNzEwOTY2NyBDMjEuMzgzOCwzNS43MTA5NjY3IDIxLjMxNTYsMzUuNzEzMDMzMyAyMS4yODM1NjY3LDM1LjcxMzAzMzMgQzIwLjYzMzYsMzUuNzEzMDMzMyAyMC4xMDc2MzMzLDM1LjE4NzA2NjcgMjAuMTA3NjMzMywzNC41MzcxIEMyMC4xMDc2MzMzLDM0LjI1ODEgMjAuMzY3LDMzLjc4NTg2NjcgMjAuMzY3LDMzLjc4NTg2NjcgTDMzLjMyOTEzMzMsMTIuMTY5NTY2NyBMMzUuNzI0NCwxMi4xNzk5IEwzMy4zMzYzNjY3LDI2LjMwMzUgTDQwLjU4NzI2NjcsMjYuMjk0MiBDNDAuNTg3MjY2NywyNi4yOTQyIDQwLjY2NDc2NjcsMjYuMjkzMTY2NyA0MC43MDE5NjY3LDI2LjI5MzE2NjcgQzQxLjM1MTkzMzMsMjYuMjkzMTY2NyA0MS44Nzc5LDI2LjgxOTEzMzMgNDEuODc3OSwyNy40NjkxIEM0MS44Nzc5LDI3LjczMjYgNDEuNzc0NTY2NywyNy45NjQwNjY3IDQxLjYyNzgzMzMsMjguMTYwNCBMNDEuNjI4ODY2NywyOC4xNjE0MzMzIFogTTMxLDAgQzEzLjg3ODcsMCAwLDEzLjg3OTczMzMgMCwzMSBDMCw0OC4xMjEzIDEzLjg3ODcsNjIgMzEsNjIgQzQ4LjEyMDI2NjcsNjIgNjIsNDguMTIxMyA2MiwzMSBDNjIsMTMuODc5NzMzMyA0OC4xMjAyNjY3LDAgMzEsMCBMMzEsMCBaIiBpZD0iRmlsbC0xIj48L3BhdGg+ICAgICAgICA8L2c+ICAgIDwvZz48L3N2Zz4=';
|
9 |
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
}
|
17 |
|
|
|
|
|
|
|
18 |
public function init() {
|
19 |
add_action( 'admin_post_amp_analytics_options', 'AMP_Options_Manager::handle_analytics_submit' );
|
20 |
-
|
21 |
add_action( 'admin_menu', array( $this, 'add_menu_items' ) );
|
22 |
}
|
23 |
|
|
|
|
|
|
|
24 |
public function add_menu_items() {
|
|
|
25 |
add_menu_page(
|
26 |
__( 'AMP Options', 'amp' ),
|
27 |
__( 'AMP', 'amp' ),
|
28 |
'manage_options',
|
29 |
-
|
30 |
-
array( $this
|
31 |
self::ICON_BASE64_SVG
|
32 |
);
|
33 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
$submenus = array(
|
35 |
-
new AMP_Analytics_Options_Submenu(
|
36 |
);
|
37 |
|
38 |
// Create submenu items and calls on the Submenu Page object to render the actual contents of the page.
|
39 |
foreach ( $submenus as $submenu ) {
|
40 |
-
$submenu->init(
|
41 |
}
|
|
|
42 |
|
43 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
}
|
45 |
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
|
|
|
|
52 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
}
|
54 |
}
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* AMP Options.
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
|
8 |
+
/**
|
9 |
+
* AMP_Options_Menu class.
|
10 |
+
*/
|
|
|
11 |
class AMP_Options_Menu {
|
|
|
12 |
|
13 |
+
/**
|
14 |
+
* The AMP svg menu icon.
|
15 |
+
*
|
16 |
+
* @var string
|
17 |
+
*/
|
18 |
+
const ICON_BASE64_SVG = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyB3aWR0aD0iNjJweCIgaGVpZ2h0PSI2MnB4IiB2aWV3Qm94PSIwIDAgNjIgNjIiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+ICAgICAgICA8dGl0bGU+QU1QLUJyYW5kLUJsYWNrLUljb248L3RpdGxlPiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4gICAgPGRlZnM+PC9kZWZzPiAgICA8ZyBpZD0iYW1wLWxvZ28taW50ZXJuYWwtc2l0ZSIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+ICAgICAgICA8ZyBpZD0iQU1QLUJyYW5kLUJsYWNrLUljb24iIGZpbGw9IiMwMDAwMDAiPiAgICAgICAgICAgIDxwYXRoIGQ9Ik00MS42Mjg4NjY3LDI4LjE2MTQzMzMgTDI4LjYyNDM2NjcsNDkuODAzNTY2NyBMMjYuMjY4MzY2Nyw0OS44MDM1NjY3IEwyOC41OTc1LDM1LjcwMTY2NjcgTDIxLjM4MzgsMzUuNzEwOTY2NyBDMjEuMzgzOCwzNS43MTA5NjY3IDIxLjMxNTYsMzUuNzEzMDMzMyAyMS4yODM1NjY3LDM1LjcxMzAzMzMgQzIwLjYzMzYsMzUuNzEzMDMzMyAyMC4xMDc2MzMzLDM1LjE4NzA2NjcgMjAuMTA3NjMzMywzNC41MzcxIEMyMC4xMDc2MzMzLDM0LjI1ODEgMjAuMzY3LDMzLjc4NTg2NjcgMjAuMzY3LDMzLjc4NTg2NjcgTDMzLjMyOTEzMzMsMTIuMTY5NTY2NyBMMzUuNzI0NCwxMi4xNzk5IEwzMy4zMzYzNjY3LDI2LjMwMzUgTDQwLjU4NzI2NjcsMjYuMjk0MiBDNDAuNTg3MjY2NywyNi4yOTQyIDQwLjY2NDc2NjcsMjYuMjkzMTY2NyA0MC43MDE5NjY3LDI2LjI5MzE2NjcgQzQxLjM1MTkzMzMsMjYuMjkzMTY2NyA0MS44Nzc5LDI2LjgxOTEzMzMgNDEuODc3OSwyNy40NjkxIEM0MS44Nzc5LDI3LjczMjYgNDEuNzc0NTY2NywyNy45NjQwNjY3IDQxLjYyNzgzMzMsMjguMTYwNCBMNDEuNjI4ODY2NywyOC4xNjE0MzMzIFogTTMxLDAgQzEzLjg3ODcsMCAwLDEzLjg3OTczMzMgMCwzMSBDMCw0OC4xMjEzIDEzLjg3ODcsNjIgMzEsNjIgQzQ4LjEyMDI2NjcsNjIgNjIsNDguMTIxMyA2MiwzMSBDNjIsMTMuODc5NzMzMyA0OC4xMjAyNjY3LDAgMzEsMCBMMzEsMCBaIiBpZD0iRmlsbC0xIj48L3BhdGg+ICAgICAgICA8L2c+ICAgIDwvZz48L3N2Zz4=';
|
|
|
19 |
|
20 |
+
/**
|
21 |
+
* Initialize.
|
22 |
+
*/
|
23 |
public function init() {
|
24 |
add_action( 'admin_post_amp_analytics_options', 'AMP_Options_Manager::handle_analytics_submit' );
|
|
|
25 |
add_action( 'admin_menu', array( $this, 'add_menu_items' ) );
|
26 |
}
|
27 |
|
28 |
+
/**
|
29 |
+
* Add menu.
|
30 |
+
*/
|
31 |
public function add_menu_items() {
|
32 |
+
|
33 |
add_menu_page(
|
34 |
__( 'AMP Options', 'amp' ),
|
35 |
__( 'AMP', 'amp' ),
|
36 |
'manage_options',
|
37 |
+
AMP_Options_Manager::OPTION_NAME,
|
38 |
+
array( $this, 'render_screen' ),
|
39 |
self::ICON_BASE64_SVG
|
40 |
);
|
41 |
|
42 |
+
add_submenu_page(
|
43 |
+
AMP_Options_Manager::OPTION_NAME,
|
44 |
+
__( 'AMP Settings', 'amp' ),
|
45 |
+
__( 'General', 'amp' ),
|
46 |
+
'manage_options',
|
47 |
+
AMP_Options_Manager::OPTION_NAME
|
48 |
+
);
|
49 |
+
|
50 |
+
add_settings_section(
|
51 |
+
'post_types',
|
52 |
+
false,
|
53 |
+
'__return_false',
|
54 |
+
AMP_Options_Manager::OPTION_NAME
|
55 |
+
);
|
56 |
+
add_settings_field(
|
57 |
+
'supported_post_types',
|
58 |
+
__( 'Post Type Support', 'amp' ),
|
59 |
+
array( $this, 'render_post_types_support' ),
|
60 |
+
AMP_Options_Manager::OPTION_NAME,
|
61 |
+
'post_types'
|
62 |
+
);
|
63 |
+
|
64 |
$submenus = array(
|
65 |
+
new AMP_Analytics_Options_Submenu( AMP_Options_Manager::OPTION_NAME ),
|
66 |
);
|
67 |
|
68 |
// Create submenu items and calls on the Submenu Page object to render the actual contents of the page.
|
69 |
foreach ( $submenus as $submenu ) {
|
70 |
+
$submenu->init();
|
71 |
}
|
72 |
+
}
|
73 |
|
74 |
+
/**
|
75 |
+
* Post types support section renderer.
|
76 |
+
*
|
77 |
+
* @since 0.6
|
78 |
+
*/
|
79 |
+
public function render_post_types_support() {
|
80 |
+
$builtin_support = AMP_Post_Type_Support::get_builtin_supported_post_types();
|
81 |
+
$element_name = AMP_Options_Manager::OPTION_NAME . '[supported_post_types][]';
|
82 |
+
?>
|
83 |
+
<fieldset>
|
84 |
+
<?php foreach ( array_map( 'get_post_type_object', AMP_Post_Type_Support::get_eligible_post_types() ) as $post_type ) : ?>
|
85 |
+
<?php
|
86 |
+
$element_id = AMP_Options_Manager::OPTION_NAME . "-supported_post_types-{$post_type->name}";
|
87 |
+
$is_builtin = in_array( $post_type->name, $builtin_support, true );
|
88 |
+
?>
|
89 |
+
<?php if ( $is_builtin ) : ?>
|
90 |
+
<input type="hidden" name="<?php echo esc_attr( $element_name ); ?>" value="<?php echo esc_attr( $post_type->name ); ?>">
|
91 |
+
<?php endif; ?>
|
92 |
+
<input
|
93 |
+
type="checkbox"
|
94 |
+
id="<?php echo esc_attr( $element_id ); ?>"
|
95 |
+
name="<?php echo esc_attr( $element_name ); ?>"
|
96 |
+
value="<?php echo esc_attr( $post_type->name ); ?>"
|
97 |
+
<?php checked( true, post_type_supports( $post_type->name, AMP_QUERY_VAR ) ); ?>
|
98 |
+
<?php disabled( $is_builtin ); ?>
|
99 |
+
>
|
100 |
+
<label for="<?php echo esc_attr( $element_id ); ?>">
|
101 |
+
<?php echo esc_html( $post_type->label ); ?>
|
102 |
+
</label>
|
103 |
+
<br>
|
104 |
+
<?php endforeach; ?>
|
105 |
+
<p class="description"><?php esc_html_e( 'Enable/disable AMP post type(s) support', 'amp' ); ?></p>
|
106 |
+
</fieldset>
|
107 |
+
<?php
|
108 |
}
|
109 |
|
110 |
+
/**
|
111 |
+
* Display Settings.
|
112 |
+
*
|
113 |
+
* @since 0.6
|
114 |
+
*/
|
115 |
+
public function render_screen() {
|
116 |
+
if ( ! empty( $_GET['settings-updated'] ) ) { // WPCS: CSRF ok.
|
117 |
+
AMP_Options_Manager::check_supported_post_type_update_errors();
|
118 |
}
|
119 |
+
?>
|
120 |
+
<div class="wrap">
|
121 |
+
<h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
|
122 |
+
<?php settings_errors(); ?>
|
123 |
+
<form action="options.php" method="post">
|
124 |
+
<?php
|
125 |
+
settings_fields( AMP_Options_Manager::OPTION_NAME );
|
126 |
+
do_settings_sections( AMP_Options_Manager::OPTION_NAME );
|
127 |
+
submit_button();
|
128 |
+
?>
|
129 |
+
</form>
|
130 |
+
</div>
|
131 |
+
<?php
|
132 |
}
|
133 |
}
|
includes/options/views/class-amp-analytics-options-submenu-page.php
CHANGED
@@ -1,19 +1,30 @@
|
|
1 |
<?php
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
-
|
4 |
-
|
|
|
5 |
class AMP_Analytics_Options_Submenu_Page {
|
6 |
|
7 |
private function render_entry( $id = '', $type = '', $config = '' ) {
|
8 |
$is_existing_entry = ! empty( $id );
|
9 |
|
10 |
-
$analytics_title = false;
|
11 |
if ( $is_existing_entry ) {
|
12 |
$entry_slug = sprintf( '%s%s', ( $type ? $type . '-' : '' ), substr( $id, -6 ) );
|
13 |
$analytics_title = sprintf( __( 'Analytics: %s', 'amp' ), $entry_slug );
|
14 |
} else {
|
15 |
$analytics_title = __( 'Add new entry:', 'amp' );
|
16 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
?>
|
18 |
<div class="analytics-data-container">
|
19 |
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
|
@@ -23,20 +34,20 @@ class AMP_Analytics_Options_Submenu_Page {
|
|
23 |
<div class="options">
|
24 |
<p>
|
25 |
<label>
|
26 |
-
<?php
|
27 |
-
<input class="option-input" type="text" name=
|
28 |
</label>
|
29 |
<label>
|
30 |
-
<?php
|
31 |
-
<input type="text"
|
32 |
</label>
|
33 |
-
|
34 |
</p>
|
35 |
<p>
|
36 |
<label>
|
37 |
-
<?php
|
38 |
<br />
|
39 |
-
<textarea rows="10" cols="100" name="config"><?php echo esc_textarea( $config ); ?></textarea>
|
40 |
</label>
|
41 |
</p>
|
42 |
<input type="hidden" name="action" value="amp_analytics_options">
|
@@ -46,7 +57,7 @@ class AMP_Analytics_Options_Submenu_Page {
|
|
46 |
wp_nonce_field( 'analytics-options', 'analytics-options' );
|
47 |
submit_button( __( 'Save', 'amp' ), 'primary', 'save', false );
|
48 |
if ( $is_existing_entry ) {
|
49 |
-
submit_button( __( 'Delete', 'amp' ), 'delete button-primary', 'delete', false );
|
50 |
}
|
51 |
?>
|
52 |
</p>
|
@@ -55,33 +66,14 @@ class AMP_Analytics_Options_Submenu_Page {
|
|
55 |
<?php
|
56 |
}
|
57 |
|
|
|
|
|
|
|
58 |
public function render_title() {
|
59 |
-
$admin_notice_text = false;
|
60 |
-
$admin_notice_type = false;
|
61 |
-
if ( isset( $_GET['valid'] ) ) {
|
62 |
-
$is_valid = (bool) $_GET['valid'];
|
63 |
-
|
64 |
-
if ( $is_valid ) {
|
65 |
-
$admin_notice_text = __( 'The analytics entry was successfully saved!', 'amp' );
|
66 |
-
$admin_notice_type = 'success';
|
67 |
-
} else {
|
68 |
-
$admin_notice_text = __( 'Failed to save the analytics entry. Please make sure that the JSON configuration is valid and unique.', 'amp' );
|
69 |
-
$admin_notice_type = 'error';
|
70 |
-
}
|
71 |
-
}
|
72 |
?>
|
73 |
<div class="wrap">
|
74 |
<h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
|
75 |
-
<?php
|
76 |
-
// If redirected from serializer, check if action succeeded
|
77 |
-
if ( $admin_notice_text ) : ?>
|
78 |
-
<div class="amp-analytics-options notice <?php echo esc_attr( 'notice-' . $admin_notice_type ); ?> is-dismissible">
|
79 |
-
<p><?php echo esc_html( $admin_notice_text ); ?></p>
|
80 |
-
<button type="button" class="notice-dismiss">
|
81 |
-
<span class="screen-reader-text"><?php __( 'Dismiss this notice.', 'amp' ) ?></span>
|
82 |
-
</button>
|
83 |
-
</div>
|
84 |
-
<?php endif; ?>
|
85 |
</div><!-- .wrap -->
|
86 |
<?php
|
87 |
}
|
@@ -91,11 +83,12 @@ class AMP_Analytics_Options_Submenu_Page {
|
|
91 |
|
92 |
$this->render_title();
|
93 |
|
94 |
-
// Render entries stored in the DB
|
95 |
foreach ( $analytics_entries as $entry_id => $entry ) {
|
96 |
$this->render_entry( $entry_id, $entry['type'], $entry['config'] );
|
97 |
}
|
98 |
-
|
|
|
99 |
$this->render_entry();
|
100 |
}
|
101 |
}
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Analytics_Options_Submenu_Page
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
|
8 |
+
/**
|
9 |
+
* Class AMP_Analytics_Options_Submenu_Page
|
10 |
+
*/
|
11 |
class AMP_Analytics_Options_Submenu_Page {
|
12 |
|
13 |
private function render_entry( $id = '', $type = '', $config = '' ) {
|
14 |
$is_existing_entry = ! empty( $id );
|
15 |
|
|
|
16 |
if ( $is_existing_entry ) {
|
17 |
$entry_slug = sprintf( '%s%s', ( $type ? $type . '-' : '' ), substr( $id, -6 ) );
|
18 |
$analytics_title = sprintf( __( 'Analytics: %s', 'amp' ), $entry_slug );
|
19 |
} else {
|
20 |
$analytics_title = __( 'Add new entry:', 'amp' );
|
21 |
}
|
22 |
+
|
23 |
+
if ( ! $is_existing_entry ) {
|
24 |
+
$id = '__new__';
|
25 |
+
}
|
26 |
+
|
27 |
+
$id_base = sprintf( '%s[analytics][%s]', AMP_Options_Manager::OPTION_NAME, $id );
|
28 |
?>
|
29 |
<div class="analytics-data-container">
|
30 |
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
|
34 |
<div class="options">
|
35 |
<p>
|
36 |
<label>
|
37 |
+
<?php esc_html_e( 'Type:', 'amp' ); ?>
|
38 |
+
<input class="option-input" type="text" name="<?php echo esc_attr( $id_base . '[type]' ); ?>" value="<?php echo esc_attr( $type ); ?>" />
|
39 |
</label>
|
40 |
<label>
|
41 |
+
<?php esc_html_e( 'ID:', 'amp' ); ?>
|
42 |
+
<input type="text" value="<?php echo esc_attr( $is_existing_entry ? $id : '' ); ?>" readonly />
|
43 |
</label>
|
44 |
+
<input type="hidden" name="<?php echo esc_attr( $id_base . '[id]' ); ?>" value="<?php echo esc_attr( $id ); ?>" />
|
45 |
</p>
|
46 |
<p>
|
47 |
<label>
|
48 |
+
<?php esc_html_e( 'JSON Configuration:', 'amp' ); ?>
|
49 |
<br />
|
50 |
+
<textarea rows="10" cols="100" name="<?php echo esc_attr( $id_base . '[config]' ); ?>"><?php echo esc_textarea( $config ); ?></textarea>
|
51 |
</label>
|
52 |
</p>
|
53 |
<input type="hidden" name="action" value="amp_analytics_options">
|
57 |
wp_nonce_field( 'analytics-options', 'analytics-options' );
|
58 |
submit_button( __( 'Save', 'amp' ), 'primary', 'save', false );
|
59 |
if ( $is_existing_entry ) {
|
60 |
+
submit_button( __( 'Delete', 'amp' ), 'delete button-primary', $id_base . '[delete]', false );
|
61 |
}
|
62 |
?>
|
63 |
</p>
|
66 |
<?php
|
67 |
}
|
68 |
|
69 |
+
/**
|
70 |
+
* Render title.
|
71 |
+
*/
|
72 |
public function render_title() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
?>
|
74 |
<div class="wrap">
|
75 |
<h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
|
76 |
+
<?php settings_errors(); ?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
</div><!-- .wrap -->
|
78 |
<?php
|
79 |
}
|
83 |
|
84 |
$this->render_title();
|
85 |
|
86 |
+
// Render entries stored in the DB.
|
87 |
foreach ( $analytics_entries as $entry_id => $entry ) {
|
88 |
$this->render_entry( $entry_id, $entry['type'], $entry['config'] );
|
89 |
}
|
90 |
+
|
91 |
+
// Empty form for adding more entries.
|
92 |
$this->render_entry();
|
93 |
}
|
94 |
}
|
includes/options/views/class-amp-options-manager.php
DELETED
@@ -1,84 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
require_once( AMP__DIR__ . '/includes/utils/class-amp-html-utils.php' );
|
4 |
-
|
5 |
-
class AMP_Options_Manager {
|
6 |
-
const OPTION_NAME = 'amp-options';
|
7 |
-
|
8 |
-
public static function get_options() {
|
9 |
-
return get_option( self::OPTION_NAME, array() );
|
10 |
-
}
|
11 |
-
|
12 |
-
public static function get_option( $option, $default = false ) {
|
13 |
-
$amp_options = self::get_options();
|
14 |
-
|
15 |
-
if ( ! isset( $amp_options[ $option ] ) ) {
|
16 |
-
return $default;
|
17 |
-
}
|
18 |
-
|
19 |
-
return $amp_options[ $option ];
|
20 |
-
}
|
21 |
-
|
22 |
-
public static function update_option( $option, $value ) {
|
23 |
-
$amp_options = self::get_options();
|
24 |
-
|
25 |
-
$amp_options[ $option ] = $value;
|
26 |
-
|
27 |
-
return update_option( self::OPTION_NAME, $amp_options, false );
|
28 |
-
}
|
29 |
-
|
30 |
-
public static function handle_analytics_submit() {
|
31 |
-
// Request must come from user with right capabilities
|
32 |
-
if ( ! current_user_can( 'manage_options' ) ) {
|
33 |
-
wp_die( __( 'Sorry, you do not have the necessary permissions to perform this action', 'amp' ) );
|
34 |
-
}
|
35 |
-
// Ensure request is coming from analytics option form
|
36 |
-
check_admin_referer( 'analytics-options', 'analytics-options' );
|
37 |
-
|
38 |
-
$status = AMP_Options_Manager::update_analytics_options( $_POST );
|
39 |
-
|
40 |
-
// Redirect to keep the user in the analytics options page
|
41 |
-
// Wrap in is_admin() to enable phpunit tests to exercise this code
|
42 |
-
wp_safe_redirect( admin_url( 'admin.php?page=amp-analytics-options&valid=' . $status ) );
|
43 |
-
exit;
|
44 |
-
}
|
45 |
-
|
46 |
-
public static function update_analytics_options( $data ) {
|
47 |
-
// Check save/delete pre-conditions and proceed if correct
|
48 |
-
if ( empty( $data['vendor-type'] ) || empty( $data['config'] ) ) {
|
49 |
-
return false;
|
50 |
-
}
|
51 |
-
|
52 |
-
// Validate JSON configuration
|
53 |
-
$is_valid_json = AMP_HTML_Utils::is_valid_json( stripslashes( $data['config'] ) );
|
54 |
-
if ( ! $is_valid_json ) {
|
55 |
-
return false;
|
56 |
-
}
|
57 |
-
$amp_analytics = self::get_option( 'analytics', array() );
|
58 |
-
|
59 |
-
$entry_vendor_type = sanitize_key( $data['vendor-type'] );
|
60 |
-
$entry_config = stripslashes( trim( $data['config'] ) );
|
61 |
-
|
62 |
-
if ( ! empty( $data['id-value'] ) ) {
|
63 |
-
$entry_id = sanitize_key( $data['id-value'] );
|
64 |
-
} else {
|
65 |
-
// Generate a hash string to uniquely identify this entry
|
66 |
-
$entry_id = substr( md5( $entry_vendor_type . $entry_config ), 0, 12 );
|
67 |
-
// Avoid duplicates
|
68 |
-
if ( isset( $amp_analytics[ $entry_id ] ) ) {
|
69 |
-
return false;
|
70 |
-
}
|
71 |
-
}
|
72 |
-
|
73 |
-
if ( isset( $data['delete'] ) ) {
|
74 |
-
unset( $amp_analytics[ $entry_id ] );
|
75 |
-
} else {
|
76 |
-
$amp_analytics[ $entry_id ] = array(
|
77 |
-
'type' => $entry_vendor_type,
|
78 |
-
'config' => $entry_config,
|
79 |
-
);
|
80 |
-
}
|
81 |
-
|
82 |
-
return self::update_option( 'analytics', $amp_analytics );
|
83 |
-
}
|
84 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
includes/options/views/class-amp-options-menu-page.php
DELETED
@@ -1,17 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
class AMP_Options_Menu_Page {
|
4 |
-
public function render() {
|
5 |
-
?>
|
6 |
-
<div class="ampoptions-admin-page">
|
7 |
-
<h1><?php echo __( 'AMP Plugin Options', 'amp' ) ?></h1>
|
8 |
-
<p>
|
9 |
-
<?php
|
10 |
-
__( 'This admin panel menu contains configuration options for the AMP Plugin.',
|
11 |
-
'amp' );
|
12 |
-
?>
|
13 |
-
</p>
|
14 |
-
</div>
|
15 |
-
<?php
|
16 |
-
}
|
17 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
includes/sanitizers/class-amp-allowed-tags-generated.php
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
<?php
|
2 |
/**
|
3 |
-
* Generated by
|
4 |
*
|
5 |
* This is a list of HTML tags and attributes that are allowed by the
|
6 |
* AMP specification. Note that tag names have been converted to lowercase.
|
@@ -11,17 +11,19 @@
|
|
11 |
*/
|
12 |
class AMP_Allowed_Tags_Generated {
|
13 |
|
14 |
-
private static $spec_file_revision =
|
15 |
-
private static $minimum_validator_revision_required =
|
16 |
|
17 |
private static $allowed_tags = array(
|
18 |
'a' => array(
|
19 |
array(
|
20 |
'attr_spec_list' => array(
|
|
|
21 |
'border' => array(),
|
22 |
'download' => array(),
|
23 |
'href' => array(
|
24 |
'blacklisted_value_regex' => '__amp_source_origin',
|
|
|
25 |
'allow_relative' => true,
|
26 |
'allowed_protocol' => array(
|
27 |
'bbmi',
|
@@ -59,7 +61,11 @@ class AMP_Allowed_Tags_Generated {
|
|
59 |
),
|
60 |
),
|
61 |
'tag_spec' => array(
|
62 |
-
'
|
|
|
|
|
|
|
|
|
63 |
),
|
64 |
|
65 |
),
|
@@ -89,6 +95,28 @@ class AMP_Allowed_Tags_Generated {
|
|
89 |
|
90 |
),
|
91 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
92 |
'amp-accordion' => array(
|
93 |
array(
|
94 |
'attr_spec_list' => array(
|
@@ -97,22 +125,48 @@ class AMP_Allowed_Tags_Generated {
|
|
97 |
),
|
98 |
),
|
99 |
'tag_spec' => array(
|
100 |
-
'
|
101 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
),
|
103 |
'html_format' => array(
|
104 |
'amp',
|
105 |
-
'amp4ads',
|
106 |
),
|
107 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/
|
108 |
),
|
109 |
|
110 |
),
|
111 |
-
),
|
112 |
-
'amp-ad' => array(
|
113 |
array(
|
114 |
'attr_spec_list' => array(
|
115 |
'alt' => array(),
|
|
|
|
|
|
|
116 |
'json' => array(),
|
117 |
'media' => array(),
|
118 |
'noloading' => array(
|
@@ -132,12 +186,36 @@ class AMP_Allowed_Tags_Generated {
|
|
132 |
'tag_spec' => array(
|
133 |
'disallowed_ancestor' => array(
|
134 |
'amp-app-banner',
|
135 |
-
'amp-
|
|
|
|
|
|
|
136 |
),
|
137 |
'html_format' => array(
|
138 |
'amp',
|
139 |
),
|
140 |
-
'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
141 |
),
|
142 |
|
143 |
),
|
@@ -147,6 +225,7 @@ class AMP_Allowed_Tags_Generated {
|
|
147 |
'attr_spec_list' => array(
|
148 |
'config' => array(
|
149 |
'blacklisted_value_regex' => '__amp_source_origin',
|
|
|
150 |
'allow_relative' => true,
|
151 |
'allowed_protocol' => array(
|
152 |
'https',
|
@@ -155,17 +234,11 @@ class AMP_Allowed_Tags_Generated {
|
|
155 |
'type' => array(),
|
156 |
),
|
157 |
'tag_spec' => array(
|
158 |
-
'also_requires_tag' => array(
|
159 |
-
'amp-analytics extension .js script',
|
160 |
-
),
|
161 |
-
'disallowed_ancestor' => array(
|
162 |
-
'amp-sidebar',
|
163 |
-
),
|
164 |
'html_format' => array(
|
165 |
'amp',
|
166 |
'amp4ads',
|
167 |
),
|
168 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/
|
169 |
),
|
170 |
|
171 |
),
|
@@ -175,9 +248,6 @@ class AMP_Allowed_Tags_Generated {
|
|
175 |
'attr_spec_list' => array(
|
176 |
'alt' => array(),
|
177 |
'attribution' => array(),
|
178 |
-
'autoplay' => array(
|
179 |
-
'value' => '',
|
180 |
-
),
|
181 |
'controls' => array(),
|
182 |
'media' => array(),
|
183 |
'noloading' => array(
|
@@ -198,17 +268,31 @@ class AMP_Allowed_Tags_Generated {
|
|
198 |
),
|
199 |
),
|
200 |
'tag_spec' => array(
|
201 |
-
'
|
202 |
-
'amp
|
|
|
203 |
),
|
204 |
-
'
|
205 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
206 |
),
|
|
|
|
|
207 |
'html_format' => array(
|
208 |
'amp',
|
209 |
'amp4ads',
|
210 |
),
|
211 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-anim.html',
|
212 |
),
|
213 |
|
214 |
),
|
@@ -228,13 +312,10 @@ class AMP_Allowed_Tags_Generated {
|
|
228 |
),
|
229 |
),
|
230 |
'tag_spec' => array(
|
231 |
-
'also_requires_tag' => array(
|
232 |
-
'amp-apester-media extension .js script',
|
233 |
-
),
|
234 |
'html_format' => array(
|
235 |
'amp',
|
236 |
),
|
237 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/
|
238 |
),
|
239 |
|
240 |
),
|
@@ -251,16 +332,11 @@ class AMP_Allowed_Tags_Generated {
|
|
251 |
),
|
252 |
),
|
253 |
'tag_spec' => array(
|
254 |
-
'also_requires_tag' => array(
|
255 |
-
'amp-app-banner button[open-button]',
|
256 |
-
'amp-app-banner extension .js script',
|
257 |
-
),
|
258 |
'html_format' => array(
|
259 |
'amp',
|
260 |
),
|
261 |
'mandatory_parent' => 'body',
|
262 |
-
'
|
263 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-add-banner.html',
|
264 |
'unique' => true,
|
265 |
),
|
266 |
|
@@ -269,10 +345,14 @@ class AMP_Allowed_Tags_Generated {
|
|
269 |
'amp-audio' => array(
|
270 |
array(
|
271 |
'attr_spec_list' => array(
|
|
|
|
|
|
|
272 |
'autoplay' => array(
|
273 |
-
'
|
274 |
),
|
275 |
'controls' => array(),
|
|
|
276 |
'loop' => array(
|
277 |
'value' => '',
|
278 |
),
|
@@ -292,22 +372,27 @@ class AMP_Allowed_Tags_Generated {
|
|
292 |
),
|
293 |
),
|
294 |
'tag_spec' => array(
|
295 |
-
'also_requires_tag' => array(
|
296 |
-
'amp-audio extension .js script',
|
297 |
-
),
|
298 |
'disallowed_ancestor' => array(
|
299 |
-
'amp-
|
300 |
),
|
301 |
'html_format' => array(
|
302 |
'amp',
|
303 |
),
|
304 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/
|
305 |
),
|
306 |
|
307 |
),
|
308 |
array(
|
309 |
'attr_spec_list' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
310 |
'controls' => array(),
|
|
|
311 |
'loop' => array(
|
312 |
'value' => '',
|
313 |
),
|
@@ -327,17 +412,46 @@ class AMP_Allowed_Tags_Generated {
|
|
327 |
),
|
328 |
),
|
329 |
'tag_spec' => array(
|
330 |
-
'
|
331 |
-
'amp
|
332 |
),
|
333 |
-
'
|
334 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
335 |
),
|
|
|
|
|
336 |
'html_format' => array(
|
337 |
'amp4ads',
|
338 |
),
|
339 |
'spec_name' => 'amp-audio (a4a)',
|
340 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/
|
341 |
),
|
342 |
|
343 |
),
|
@@ -357,6 +471,8 @@ class AMP_Allowed_Tags_Generated {
|
|
357 |
'html_format' => array(
|
358 |
'amp',
|
359 |
),
|
|
|
|
|
360 |
),
|
361 |
|
362 |
),
|
@@ -364,6 +480,10 @@ class AMP_Allowed_Tags_Generated {
|
|
364 |
'amp-brid-player' => array(
|
365 |
array(
|
366 |
'attr_spec_list' => array(
|
|
|
|
|
|
|
|
|
367 |
'data-partner' => array(
|
368 |
'mandatory' => true,
|
369 |
'value_regex' => '[0-9]+',
|
@@ -384,17 +504,10 @@ class AMP_Allowed_Tags_Generated {
|
|
384 |
),
|
385 |
),
|
386 |
'tag_spec' => array(
|
387 |
-
'also_requires_tag' => array(
|
388 |
-
'amp-brid-player extension .js script',
|
389 |
-
),
|
390 |
-
'disallowed_ancestor' => array(
|
391 |
-
'amp-sidebar',
|
392 |
-
),
|
393 |
'html_format' => array(
|
394 |
'amp',
|
395 |
-
'amp4ads',
|
396 |
),
|
397 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/
|
398 |
),
|
399 |
|
400 |
),
|
@@ -402,30 +515,50 @@ class AMP_Allowed_Tags_Generated {
|
|
402 |
'amp-brightcove' => array(
|
403 |
array(
|
404 |
'attr_spec_list' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
405 |
'data-account' => array(
|
406 |
'mandatory' => true,
|
407 |
),
|
408 |
-
'data-embed' => array(),
|
409 |
-
'data-player' => array(),
|
410 |
-
'data-playlist-id' => array(),
|
411 |
-
'data-video-id' => array(),
|
412 |
'media' => array(),
|
413 |
'noloading' => array(
|
414 |
'value' => '',
|
415 |
),
|
416 |
),
|
417 |
'tag_spec' => array(
|
418 |
-
'
|
419 |
-
'amp
|
420 |
),
|
421 |
-
'
|
422 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
423 |
),
|
|
|
|
|
424 |
'html_format' => array(
|
425 |
'amp',
|
426 |
-
'amp4ads',
|
427 |
),
|
428 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/
|
429 |
),
|
430 |
|
431 |
),
|
@@ -433,6 +566,7 @@ class AMP_Allowed_Tags_Generated {
|
|
433 |
'amp-carousel' => array(
|
434 |
array(
|
435 |
'attr_spec_list' => array(
|
|
|
436 |
'arrows' => array(
|
437 |
'value' => '',
|
438 |
),
|
@@ -458,17 +592,7 @@ class AMP_Allowed_Tags_Generated {
|
|
458 |
),
|
459 |
),
|
460 |
'tag_spec' => array(
|
461 |
-
'
|
462 |
-
'amp-carousel extension .js script',
|
463 |
-
),
|
464 |
-
'disallowed_ancestor' => array(
|
465 |
-
'amp-sidebar',
|
466 |
-
),
|
467 |
-
'html_format' => array(
|
468 |
-
'amp',
|
469 |
-
'amp4ads',
|
470 |
-
),
|
471 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-carousel.html',
|
472 |
),
|
473 |
|
474 |
),
|
@@ -476,6 +600,7 @@ class AMP_Allowed_Tags_Generated {
|
|
476 |
'amp-dailymotion' => array(
|
477 |
array(
|
478 |
'attr_spec_list' => array(
|
|
|
479 |
'data-endscreen-enable' => array(
|
480 |
'value_regex' => 'true|false',
|
481 |
),
|
@@ -507,25 +632,52 @@ class AMP_Allowed_Tags_Generated {
|
|
507 |
),
|
508 |
),
|
509 |
'tag_spec' => array(
|
510 |
-
'
|
511 |
-
'amp
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
512 |
),
|
|
|
|
|
|
|
|
|
|
|
513 |
'disallowed_ancestor' => array(
|
514 |
-
'amp-
|
515 |
),
|
516 |
'html_format' => array(
|
517 |
'amp',
|
518 |
-
'amp4ads',
|
519 |
),
|
520 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/
|
521 |
),
|
522 |
|
523 |
),
|
524 |
-
),
|
525 |
-
'amp-embed' => array(
|
526 |
array(
|
527 |
'attr_spec_list' => array(
|
528 |
'alt' => array(),
|
|
|
|
|
|
|
|
|
529 |
'json' => array(),
|
530 |
'media' => array(),
|
531 |
'noloading' => array(
|
@@ -544,12 +696,17 @@ class AMP_Allowed_Tags_Generated {
|
|
544 |
),
|
545 |
'tag_spec' => array(
|
546 |
'disallowed_ancestor' => array(
|
547 |
-
'amp-
|
|
|
|
|
|
|
|
|
548 |
),
|
549 |
'html_format' => array(
|
550 |
'amp',
|
551 |
),
|
552 |
-
'
|
|
|
553 |
),
|
554 |
|
555 |
),
|
@@ -558,16 +715,10 @@ class AMP_Allowed_Tags_Generated {
|
|
558 |
array(
|
559 |
'attr_spec_list' => array(),
|
560 |
'tag_spec' => array(
|
561 |
-
'also_requires_tag' => array(
|
562 |
-
'amp-experiment extension .js script',
|
563 |
-
),
|
564 |
-
'disallowed_ancestor' => array(
|
565 |
-
'amp-sidebar',
|
566 |
-
),
|
567 |
'html_format' => array(
|
568 |
'amp',
|
569 |
),
|
570 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/
|
571 |
'unique' => true,
|
572 |
),
|
573 |
|
@@ -585,44 +736,70 @@ class AMP_Allowed_Tags_Generated {
|
|
585 |
),
|
586 |
),
|
587 |
'tag_spec' => array(
|
588 |
-
'
|
589 |
-
'amp
|
590 |
),
|
591 |
-
|
592 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
593 |
),
|
|
|
|
|
594 |
'html_format' => array(
|
595 |
'amp',
|
596 |
-
'amp4ads',
|
597 |
),
|
598 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-facebook.html',
|
599 |
),
|
600 |
|
601 |
),
|
602 |
),
|
603 |
-
'amp-
|
604 |
array(
|
605 |
'attr_spec_list' => array(
|
606 |
-
'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
607 |
'media' => array(),
|
608 |
-
'min-font-size' => array(),
|
609 |
'noloading' => array(
|
610 |
'value' => '',
|
611 |
),
|
612 |
),
|
613 |
'tag_spec' => array(
|
614 |
-
'also_requires_tag' => array(
|
615 |
-
'amp-fit-text extension .js script',
|
616 |
-
),
|
617 |
'html_format' => array(
|
618 |
'amp',
|
619 |
-
'amp4ads',
|
620 |
),
|
621 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-fit-text.html',
|
622 |
),
|
623 |
|
624 |
),
|
625 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
626 |
'amp-font' => array(
|
627 |
array(
|
628 |
'attr_spec_list' => array(
|
@@ -645,17 +822,10 @@ class AMP_Allowed_Tags_Generated {
|
|
645 |
),
|
646 |
),
|
647 |
'tag_spec' => array(
|
648 |
-
'also_requires_tag' => array(
|
649 |
-
'amp-font extension .js script',
|
650 |
-
),
|
651 |
-
'disallowed_ancestor' => array(
|
652 |
-
'amp-sidebar',
|
653 |
-
),
|
654 |
'html_format' => array(
|
655 |
'amp',
|
656 |
'amp4ads',
|
657 |
),
|
658 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-font.html',
|
659 |
),
|
660 |
|
661 |
),
|
@@ -672,17 +842,9 @@ class AMP_Allowed_Tags_Generated {
|
|
672 |
),
|
673 |
),
|
674 |
'tag_spec' => array(
|
675 |
-
'also_requires_tag' => array(
|
676 |
-
'amp-fx-flying-carpet extension .js script',
|
677 |
-
),
|
678 |
-
'disallowed_ancestor' => array(
|
679 |
-
'amp-sidebar',
|
680 |
-
),
|
681 |
'html_format' => array(
|
682 |
'amp',
|
683 |
-
'amp4ads',
|
684 |
),
|
685 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-fx-flying-carpet.html',
|
686 |
),
|
687 |
|
688 |
),
|
@@ -702,17 +864,49 @@ class AMP_Allowed_Tags_Generated {
|
|
702 |
),
|
703 |
),
|
704 |
'tag_spec' => array(
|
705 |
-
'
|
706 |
-
'amp
|
707 |
),
|
708 |
-
'
|
709 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
710 |
),
|
|
|
|
|
711 |
'html_format' => array(
|
712 |
'amp',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
713 |
'amp4ads',
|
714 |
),
|
715 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-gfycat.html',
|
716 |
),
|
717 |
|
718 |
),
|
@@ -729,16 +923,10 @@ class AMP_Allowed_Tags_Generated {
|
|
729 |
),
|
730 |
),
|
731 |
'tag_spec' => array(
|
732 |
-
'also_requires_tag' => array(
|
733 |
-
'amp-hulu extension .js script',
|
734 |
-
),
|
735 |
-
'disallowed_ancestor' => array(
|
736 |
-
'amp-sidebar',
|
737 |
-
),
|
738 |
'html_format' => array(
|
739 |
'amp',
|
740 |
-
'amp4ads',
|
741 |
),
|
|
|
742 |
),
|
743 |
|
744 |
),
|
@@ -746,9 +934,16 @@ class AMP_Allowed_Tags_Generated {
|
|
746 |
'amp-iframe' => array(
|
747 |
array(
|
748 |
'attr_spec_list' => array(
|
|
|
|
|
|
|
|
|
749 |
'allowfullscreen' => array(
|
750 |
'value' => '',
|
751 |
),
|
|
|
|
|
|
|
752 |
'allowtransparency' => array(
|
753 |
'value' => '',
|
754 |
),
|
@@ -778,16 +973,40 @@ class AMP_Allowed_Tags_Generated {
|
|
778 |
'srcdoc' => array(),
|
779 |
),
|
780 |
'tag_spec' => array(
|
781 |
-
'
|
782 |
-
'amp
|
783 |
),
|
784 |
-
|
785 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
786 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
787 |
'html_format' => array(
|
788 |
'amp',
|
789 |
),
|
790 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/
|
791 |
),
|
792 |
|
793 |
),
|
@@ -802,17 +1021,9 @@ class AMP_Allowed_Tags_Generated {
|
|
802 |
),
|
803 |
),
|
804 |
'tag_spec' => array(
|
805 |
-
'also_requires_tag' => array(
|
806 |
-
'amp-image-lightbox extension .js script',
|
807 |
-
),
|
808 |
-
'disallowed_ancestor' => array(
|
809 |
-
'amp-sidebar',
|
810 |
-
),
|
811 |
'html_format' => array(
|
812 |
'amp',
|
813 |
-
'amp4ads',
|
814 |
),
|
815 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-image-lightbox.html',
|
816 |
),
|
817 |
|
818 |
),
|
@@ -820,6 +1031,10 @@ class AMP_Allowed_Tags_Generated {
|
|
820 |
'amp-img' => array(
|
821 |
array(
|
822 |
'attr_spec_list' => array(
|
|
|
|
|
|
|
|
|
823 |
'alt' => array(),
|
824 |
'attribution' => array(),
|
825 |
'media' => array(),
|
@@ -846,7 +1061,26 @@ class AMP_Allowed_Tags_Generated {
|
|
846 |
'amp',
|
847 |
'amp4ads',
|
848 |
),
|
849 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/amp-img
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
850 |
),
|
851 |
|
852 |
),
|
@@ -864,17 +1098,9 @@ class AMP_Allowed_Tags_Generated {
|
|
864 |
),
|
865 |
),
|
866 |
'tag_spec' => array(
|
867 |
-
'also_requires_tag' => array(
|
868 |
-
'amp-instagram extension .js script',
|
869 |
-
),
|
870 |
-
'disallowed_ancestor' => array(
|
871 |
-
'amp-sidebar',
|
872 |
-
),
|
873 |
'html_format' => array(
|
874 |
'amp',
|
875 |
-
'amp4ads',
|
876 |
),
|
877 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-instagram.html',
|
878 |
),
|
879 |
|
880 |
),
|
@@ -882,6 +1108,13 @@ class AMP_Allowed_Tags_Generated {
|
|
882 |
'amp-install-serviceworker' => array(
|
883 |
array(
|
884 |
'attr_spec_list' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
885 |
'src' => array(
|
886 |
'blacklisted_value_regex' => '__amp_source_origin',
|
887 |
'mandatory' => true,
|
@@ -892,16 +1125,29 @@ class AMP_Allowed_Tags_Generated {
|
|
892 |
),
|
893 |
),
|
894 |
'tag_spec' => array(
|
895 |
-
'
|
896 |
-
'amp
|
897 |
),
|
898 |
-
|
899 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
900 |
),
|
|
|
|
|
901 |
'html_format' => array(
|
902 |
'amp',
|
903 |
),
|
904 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-install-serviceworker.html',
|
905 |
),
|
906 |
|
907 |
),
|
@@ -921,17 +1167,9 @@ class AMP_Allowed_Tags_Generated {
|
|
921 |
),
|
922 |
),
|
923 |
'tag_spec' => array(
|
924 |
-
'also_requires_tag' => array(
|
925 |
-
'amp-jwplayer extension .js script',
|
926 |
-
),
|
927 |
-
'disallowed_ancestor' => array(
|
928 |
-
'amp-sidebar',
|
929 |
-
),
|
930 |
'html_format' => array(
|
931 |
'amp',
|
932 |
-
'amp4ads',
|
933 |
),
|
934 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-jwplayer.html',
|
935 |
),
|
936 |
|
937 |
),
|
@@ -948,17 +1186,27 @@ class AMP_Allowed_Tags_Generated {
|
|
948 |
),
|
949 |
),
|
950 |
'tag_spec' => array(
|
951 |
-
'
|
952 |
-
'amp
|
953 |
),
|
954 |
-
|
955 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
956 |
),
|
|
|
|
|
957 |
'html_format' => array(
|
958 |
'amp',
|
959 |
'amp4ads',
|
960 |
),
|
961 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/
|
962 |
),
|
963 |
|
964 |
),
|
@@ -975,17 +1223,9 @@ class AMP_Allowed_Tags_Generated {
|
|
975 |
'scrollable' => array(),
|
976 |
),
|
977 |
'tag_spec' => array(
|
978 |
-
'also_requires_tag' => array(
|
979 |
-
'amp-lightbox extension .js script',
|
980 |
-
),
|
981 |
-
'disallowed_ancestor' => array(
|
982 |
-
'amp-sidebar',
|
983 |
-
),
|
984 |
'html_format' => array(
|
985 |
'amp',
|
986 |
-
'amp4ads',
|
987 |
),
|
988 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-lightbox.html',
|
989 |
),
|
990 |
|
991 |
),
|
@@ -993,11 +1233,16 @@ class AMP_Allowed_Tags_Generated {
|
|
993 |
'amp-list' => array(
|
994 |
array(
|
995 |
'attr_spec_list' => array(
|
|
|
|
|
996 |
'credentials' => array(),
|
|
|
|
|
997 |
'media' => array(),
|
998 |
'noloading' => array(
|
999 |
'value' => '',
|
1000 |
),
|
|
|
1001 |
'src' => array(
|
1002 |
'blacklisted_value_regex' => '__amp_source_origin',
|
1003 |
'mandatory' => true,
|
@@ -1009,14 +1254,9 @@ class AMP_Allowed_Tags_Generated {
|
|
1009 |
'template' => array(),
|
1010 |
),
|
1011 |
'tag_spec' => array(
|
1012 |
-
'also_requires_tag' => array(
|
1013 |
-
'amp-list extension .js script',
|
1014 |
-
),
|
1015 |
'html_format' => array(
|
1016 |
'amp',
|
1017 |
-
'amp4ads',
|
1018 |
),
|
1019 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-list.html',
|
1020 |
),
|
1021 |
|
1022 |
),
|
@@ -1039,14 +1279,46 @@ class AMP_Allowed_Tags_Generated {
|
|
1039 |
),
|
1040 |
),
|
1041 |
'tag_spec' => array(
|
1042 |
-
'
|
1043 |
-
'amp
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1044 |
),
|
|
|
|
|
1045 |
'html_format' => array(
|
1046 |
'amp',
|
1047 |
-
'amp4ads',
|
1048 |
),
|
1049 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-live-list.html',
|
1050 |
),
|
1051 |
|
1052 |
),
|
@@ -1057,28 +1329,18 @@ class AMP_Allowed_Tags_Generated {
|
|
1057 |
'data-bcid' => array(
|
1058 |
'mandatory' => true,
|
1059 |
),
|
1060 |
-
'data-bid' => array(),
|
1061 |
'data-pid' => array(
|
1062 |
'mandatory' => true,
|
1063 |
),
|
1064 |
-
'data-vid' => array(),
|
1065 |
'media' => array(),
|
1066 |
'noloading' => array(
|
1067 |
'value' => '',
|
1068 |
),
|
1069 |
),
|
1070 |
'tag_spec' => array(
|
1071 |
-
'also_requires_tag' => array(
|
1072 |
-
'amp-o2-player extension .js script',
|
1073 |
-
),
|
1074 |
-
'disallowed_ancestor' => array(
|
1075 |
-
'amp-sidebar',
|
1076 |
-
),
|
1077 |
'html_format' => array(
|
1078 |
'amp',
|
1079 |
-
'amp4ads',
|
1080 |
),
|
1081 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-o2-player.html',
|
1082 |
),
|
1083 |
|
1084 |
),
|
@@ -1086,7 +1348,6 @@ class AMP_Allowed_Tags_Generated {
|
|
1086 |
'amp-ooyala-player' => array(
|
1087 |
array(
|
1088 |
'attr_spec_list' => array(
|
1089 |
-
'data-config' => array(),
|
1090 |
'data-embedcode' => array(
|
1091 |
'mandatory' => true,
|
1092 |
),
|
@@ -1096,21 +1357,15 @@ class AMP_Allowed_Tags_Generated {
|
|
1096 |
'data-playerid' => array(
|
1097 |
'mandatory' => true,
|
1098 |
),
|
1099 |
-
'data-playerversion' => array(),
|
1100 |
'media' => array(),
|
1101 |
'noloading' => array(
|
1102 |
'value' => '',
|
1103 |
),
|
1104 |
),
|
1105 |
'tag_spec' => array(
|
1106 |
-
'also_requires_tag' => array(
|
1107 |
-
'amp-ooyala-player extension .js script',
|
1108 |
-
),
|
1109 |
'html_format' => array(
|
1110 |
'amp',
|
1111 |
-
'amp4ads',
|
1112 |
),
|
1113 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-ooyala-player.html',
|
1114 |
),
|
1115 |
|
1116 |
),
|
@@ -1127,17 +1382,10 @@ class AMP_Allowed_Tags_Generated {
|
|
1127 |
),
|
1128 |
),
|
1129 |
'tag_spec' => array(
|
1130 |
-
'also_requires_tag' => array(
|
1131 |
-
'amp-pinterest extension .js script',
|
1132 |
-
),
|
1133 |
-
'disallowed_ancestor' => array(
|
1134 |
-
'amp-sidebar',
|
1135 |
-
),
|
1136 |
'html_format' => array(
|
1137 |
'amp',
|
1138 |
-
'amp4ads',
|
1139 |
),
|
1140 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/
|
1141 |
),
|
1142 |
|
1143 |
),
|
@@ -1149,9 +1397,13 @@ class AMP_Allowed_Tags_Generated {
|
|
1149 |
'noloading' => array(
|
1150 |
'value' => '',
|
1151 |
),
|
|
|
|
|
|
|
1152 |
'src' => array(
|
1153 |
'blacklisted_value_regex' => '__amp_source_origin',
|
1154 |
'mandatory' => true,
|
|
|
1155 |
'allow_relative' => true,
|
1156 |
'allowed_protocol' => array(
|
1157 |
'https',
|
@@ -1159,14 +1411,11 @@ class AMP_Allowed_Tags_Generated {
|
|
1159 |
),
|
1160 |
),
|
1161 |
'tag_spec' => array(
|
1162 |
-
'disallowed_ancestor' => array(
|
1163 |
-
'amp-sidebar',
|
1164 |
-
),
|
1165 |
'html_format' => array(
|
1166 |
'amp',
|
1167 |
'amp4ads',
|
1168 |
),
|
1169 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/amp-pixel
|
1170 |
),
|
1171 |
|
1172 |
),
|
@@ -1177,6 +1426,7 @@ class AMP_Allowed_Tags_Generated {
|
|
1177 |
'data-comments' => array(
|
1178 |
'value_regex_casei' => '(false|true)',
|
1179 |
),
|
|
|
1180 |
'data-item-info' => array(
|
1181 |
'value_regex_casei' => '(false|true)',
|
1182 |
),
|
@@ -1187,19 +1437,36 @@ class AMP_Allowed_Tags_Generated {
|
|
1187 |
'noloading' => array(
|
1188 |
'value' => '',
|
1189 |
),
|
1190 |
-
'src' => array(
|
1191 |
-
'mandatory' => true,
|
1192 |
-
),
|
1193 |
),
|
1194 |
'tag_spec' => array(
|
1195 |
-
'
|
1196 |
-
'amp
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1197 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
1198 |
'html_format' => array(
|
1199 |
'amp',
|
1200 |
'amp4ads',
|
1201 |
),
|
1202 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-playbuzz',
|
1203 |
),
|
1204 |
|
1205 |
),
|
@@ -1217,17 +1484,9 @@ class AMP_Allowed_Tags_Generated {
|
|
1217 |
),
|
1218 |
),
|
1219 |
'tag_spec' => array(
|
1220 |
-
'also_requires_tag' => array(
|
1221 |
-
'amp-reach-player extension .js script',
|
1222 |
-
),
|
1223 |
-
'disallowed_ancestor' => array(
|
1224 |
-
'amp-sidebar',
|
1225 |
-
),
|
1226 |
'html_format' => array(
|
1227 |
'amp',
|
1228 |
-
'amp4ads',
|
1229 |
),
|
1230 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-reach-player.html',
|
1231 |
),
|
1232 |
|
1233 |
),
|
@@ -1254,17 +1513,9 @@ class AMP_Allowed_Tags_Generated {
|
|
1254 |
),
|
1255 |
),
|
1256 |
'tag_spec' => array(
|
1257 |
-
'also_requires_tag' => array(
|
1258 |
-
'amp-reddit extension .js script',
|
1259 |
-
),
|
1260 |
-
'disallowed_ancestor' => array(
|
1261 |
-
'amp-sidebar',
|
1262 |
-
),
|
1263 |
'html_format' => array(
|
1264 |
'amp',
|
1265 |
-
'amp4ads',
|
1266 |
),
|
1267 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-reddit',
|
1268 |
),
|
1269 |
|
1270 |
),
|
@@ -1272,32 +1523,32 @@ class AMP_Allowed_Tags_Generated {
|
|
1272 |
'amp-selector' => array(
|
1273 |
array(
|
1274 |
'attr_spec_list' => array(
|
|
|
1275 |
'disabled' => array(
|
1276 |
'value' => '',
|
1277 |
),
|
1278 |
'form' => array(),
|
|
|
|
|
|
|
1279 |
'media' => array(),
|
1280 |
'multiple' => array(
|
1281 |
'value' => '',
|
1282 |
),
|
1283 |
-
'name' => array(
|
|
|
|
|
1284 |
'noloading' => array(
|
1285 |
'value' => '',
|
1286 |
),
|
1287 |
),
|
1288 |
'tag_spec' => array(
|
1289 |
-
'also_requires_tag' => array(
|
1290 |
-
'amp-selector extension .js script',
|
1291 |
-
),
|
1292 |
'disallowed_ancestor' => array(
|
1293 |
'amp-selector',
|
1294 |
-
'amp-sidebar',
|
1295 |
),
|
1296 |
'html_format' => array(
|
1297 |
'amp',
|
1298 |
-
'amp4ads',
|
1299 |
),
|
1300 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-selector.html',
|
1301 |
),
|
1302 |
|
1303 |
),
|
@@ -1314,18 +1565,10 @@ class AMP_Allowed_Tags_Generated {
|
|
1314 |
),
|
1315 |
),
|
1316 |
'tag_spec' => array(
|
1317 |
-
'also_requires_tag' => array(
|
1318 |
-
'amp-sidebar extension .js script',
|
1319 |
-
),
|
1320 |
-
'disallowed_ancestor' => array(
|
1321 |
-
'amp-sidebar',
|
1322 |
-
),
|
1323 |
'html_format' => array(
|
1324 |
'amp',
|
1325 |
),
|
1326 |
'mandatory_parent' => 'body',
|
1327 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-sidebar.html',
|
1328 |
-
'unique' => true,
|
1329 |
),
|
1330 |
|
1331 |
),
|
@@ -1364,14 +1607,10 @@ class AMP_Allowed_Tags_Generated {
|
|
1364 |
),
|
1365 |
),
|
1366 |
'tag_spec' => array(
|
1367 |
-
'also_requires_tag' => array(
|
1368 |
-
'amp-social-share extension .js script',
|
1369 |
-
),
|
1370 |
'html_format' => array(
|
1371 |
'amp',
|
1372 |
'amp4ads',
|
1373 |
),
|
1374 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-social-share.html',
|
1375 |
),
|
1376 |
|
1377 |
),
|
@@ -1382,11 +1621,13 @@ class AMP_Allowed_Tags_Generated {
|
|
1382 |
'data-color' => array(
|
1383 |
'value_regex_casei' => '([0-9a-f]{3}){1,2}',
|
1384 |
),
|
|
|
|
|
|
|
1385 |
'data-secret-token' => array(
|
1386 |
'value_regex' => '[a-za-z0-9_-]+',
|
1387 |
),
|
1388 |
'data-trackid' => array(
|
1389 |
-
'mandatory' => true,
|
1390 |
'value_regex' => '[0-9]+',
|
1391 |
),
|
1392 |
'data-visual' => array(
|
@@ -1398,17 +1639,9 @@ class AMP_Allowed_Tags_Generated {
|
|
1398 |
),
|
1399 |
),
|
1400 |
'tag_spec' => array(
|
1401 |
-
'also_requires_tag' => array(
|
1402 |
-
'amp-soundcloud extension .js script',
|
1403 |
-
),
|
1404 |
-
'disallowed_ancestor' => array(
|
1405 |
-
'amp-sidebar',
|
1406 |
-
),
|
1407 |
'html_format' => array(
|
1408 |
'amp',
|
1409 |
-
'amp4ads',
|
1410 |
),
|
1411 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-soundcloud.html',
|
1412 |
),
|
1413 |
|
1414 |
),
|
@@ -1443,17 +1676,35 @@ class AMP_Allowed_Tags_Generated {
|
|
1443 |
),
|
1444 |
),
|
1445 |
'tag_spec' => array(
|
1446 |
-
'
|
1447 |
-
'amp
|
1448 |
),
|
1449 |
-
|
1450 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1451 |
),
|
|
|
|
|
1452 |
'html_format' => array(
|
1453 |
'amp',
|
1454 |
-
'amp4ads',
|
1455 |
),
|
1456 |
-
'
|
|
|
1457 |
),
|
1458 |
|
1459 |
),
|
@@ -1467,45 +1718,126 @@ class AMP_Allowed_Tags_Generated {
|
|
1467 |
),
|
1468 |
),
|
1469 |
'tag_spec' => array(
|
1470 |
-
'also_requires_tag' => array(
|
1471 |
-
'amp-sticky-ad extension .js script',
|
1472 |
-
),
|
1473 |
'disallowed_ancestor' => array(
|
1474 |
'amp-app-banner',
|
1475 |
-
'amp-sidebar',
|
1476 |
),
|
1477 |
'html_format' => array(
|
1478 |
'amp',
|
1479 |
),
|
1480 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-sticky-ad.html',
|
1481 |
'unique' => true,
|
1482 |
),
|
1483 |
|
1484 |
),
|
1485 |
),
|
1486 |
-
'amp-
|
1487 |
array(
|
1488 |
'attr_spec_list' => array(
|
1489 |
-
'
|
1490 |
-
'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1491 |
),
|
|
|
1492 |
'media' => array(),
|
1493 |
'noloading' => array(
|
1494 |
'value' => '',
|
1495 |
),
|
1496 |
),
|
1497 |
'tag_spec' => array(
|
1498 |
-
'
|
1499 |
-
'amp
|
1500 |
),
|
1501 |
-
'
|
1502 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1503 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
1504 |
'html_format' => array(
|
1505 |
'amp',
|
1506 |
-
'amp4ads',
|
1507 |
),
|
1508 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-twitter.html',
|
1509 |
),
|
1510 |
|
1511 |
),
|
@@ -1527,23 +1859,18 @@ class AMP_Allowed_Tags_Generated {
|
|
1527 |
'https',
|
1528 |
),
|
1529 |
),
|
|
|
|
|
|
|
1530 |
'media' => array(),
|
1531 |
'noloading' => array(
|
1532 |
'value' => '',
|
1533 |
),
|
1534 |
),
|
1535 |
'tag_spec' => array(
|
1536 |
-
'also_requires_tag' => array(
|
1537 |
-
'amp-analytics extension .js script',
|
1538 |
-
'amp-user-notification extension .js script',
|
1539 |
-
),
|
1540 |
-
'disallowed_ancestor' => array(
|
1541 |
-
'amp-sidebar',
|
1542 |
-
),
|
1543 |
'html_format' => array(
|
1544 |
'amp',
|
1545 |
),
|
1546 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-user-notification.html',
|
1547 |
),
|
1548 |
|
1549 |
),
|
@@ -1551,7 +1878,22 @@ class AMP_Allowed_Tags_Generated {
|
|
1551 |
'amp-video' => array(
|
1552 |
array(
|
1553 |
'attr_spec_list' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1554 |
'alt' => array(),
|
|
|
|
|
1555 |
'attribution' => array(),
|
1556 |
'autoplay' => array(
|
1557 |
'value' => '',
|
@@ -1559,6 +1901,11 @@ class AMP_Allowed_Tags_Generated {
|
|
1559 |
'controls' => array(
|
1560 |
'value' => '',
|
1561 |
),
|
|
|
|
|
|
|
|
|
|
|
1562 |
'loop' => array(
|
1563 |
'value' => '',
|
1564 |
),
|
@@ -1584,13 +1931,79 @@ class AMP_Allowed_Tags_Generated {
|
|
1584 |
),
|
1585 |
'tag_spec' => array(
|
1586 |
'disallowed_ancestor' => array(
|
1587 |
-
'amp-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1588 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1589 |
'html_format' => array(
|
1590 |
'amp',
|
1591 |
'amp4ads',
|
1592 |
),
|
1593 |
-
'
|
|
|
|
|
1594 |
),
|
1595 |
|
1596 |
),
|
@@ -1608,17 +2021,9 @@ class AMP_Allowed_Tags_Generated {
|
|
1608 |
),
|
1609 |
),
|
1610 |
'tag_spec' => array(
|
1611 |
-
'also_requires_tag' => array(
|
1612 |
-
'amp-vimeo extension .js script',
|
1613 |
-
),
|
1614 |
-
'disallowed_ancestor' => array(
|
1615 |
-
'amp-sidebar',
|
1616 |
-
),
|
1617 |
'html_format' => array(
|
1618 |
'amp',
|
1619 |
-
'amp4ads',
|
1620 |
),
|
1621 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-vimeo.html',
|
1622 |
),
|
1623 |
|
1624 |
),
|
@@ -1635,47 +2040,113 @@ class AMP_Allowed_Tags_Generated {
|
|
1635 |
),
|
1636 |
),
|
1637 |
'tag_spec' => array(
|
1638 |
-
'
|
1639 |
-
'amp
|
1640 |
),
|
1641 |
-
|
1642 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1643 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
1644 |
'html_format' => array(
|
1645 |
'amp',
|
1646 |
-
'amp4ads',
|
1647 |
),
|
1648 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-vine.html',
|
1649 |
),
|
1650 |
|
1651 |
),
|
1652 |
),
|
1653 |
-
'amp-
|
1654 |
array(
|
1655 |
'attr_spec_list' => array(
|
1656 |
-
'
|
1657 |
-
'data-videoid' => array(
|
1658 |
'mandatory' => true,
|
1659 |
-
'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1660 |
),
|
1661 |
'media' => array(),
|
1662 |
'noloading' => array(
|
1663 |
'value' => '',
|
1664 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1665 |
),
|
1666 |
'tag_spec' => array(
|
1667 |
-
'
|
1668 |
-
'amp
|
1669 |
),
|
1670 |
-
'
|
1671 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1672 |
),
|
|
|
|
|
1673 |
'html_format' => array(
|
1674 |
'amp',
|
1675 |
-
'amp4ads',
|
1676 |
),
|
1677 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1678 |
),
|
|
|
1679 |
|
1680 |
),
|
1681 |
),
|
@@ -1716,7 +2187,7 @@ class AMP_Allowed_Tags_Generated {
|
|
1716 |
),
|
1717 |
'mandatory_ancestor' => 'noscript',
|
1718 |
'mandatory_ancestor_suggested_alternative' => 'amp-audio',
|
1719 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/
|
1720 |
),
|
1721 |
|
1722 |
),
|
@@ -1761,23 +2232,11 @@ class AMP_Allowed_Tags_Generated {
|
|
1761 |
'align' => array(),
|
1762 |
'cite' => array(
|
1763 |
'blacklisted_value_regex' => '__amp_source_origin',
|
|
|
1764 |
'allow_relative' => true,
|
1765 |
'allowed_protocol' => array(
|
1766 |
-
'fb-messenger',
|
1767 |
-
'ftp',
|
1768 |
'http',
|
1769 |
'https',
|
1770 |
-
'intent',
|
1771 |
-
'mailto',
|
1772 |
-
'skype',
|
1773 |
-
'sms',
|
1774 |
-
'snapchat',
|
1775 |
-
'tel',
|
1776 |
-
'tg',
|
1777 |
-
'threema',
|
1778 |
-
'twitter',
|
1779 |
-
'viber',
|
1780 |
-
'whatsapp',
|
1781 |
),
|
1782 |
),
|
1783 |
),
|
@@ -1791,7 +2250,7 @@ class AMP_Allowed_Tags_Generated {
|
|
1791 |
'tag_spec' => array(
|
1792 |
'mandatory' => true,
|
1793 |
'mandatory_parent' => 'html',
|
1794 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
1795 |
'unique' => true,
|
1796 |
),
|
1797 |
|
@@ -1807,10 +2266,15 @@ class AMP_Allowed_Tags_Generated {
|
|
1807 |
'button' => array(
|
1808 |
array(
|
1809 |
'attr_spec_list' => array(
|
|
|
|
|
|
|
1810 |
'disabled' => array(
|
1811 |
'value' => '',
|
1812 |
),
|
1813 |
-
'name' => array(
|
|
|
|
|
1814 |
'role' => array(),
|
1815 |
'tabindex' => array(),
|
1816 |
'type' => array(),
|
@@ -1821,7 +2285,9 @@ class AMP_Allowed_Tags_Generated {
|
|
1821 |
),
|
1822 |
array(
|
1823 |
'attr_spec_list' => array(
|
1824 |
-
'name' => array(
|
|
|
|
|
1825 |
'open-button' => array(
|
1826 |
'value' => '',
|
1827 |
),
|
@@ -1831,6 +2297,10 @@ class AMP_Allowed_Tags_Generated {
|
|
1831 |
'value' => array(),
|
1832 |
),
|
1833 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
1834 |
'mandatory_ancestor' => 'amp-app-banner',
|
1835 |
'spec_name' => 'amp-app-banner button[open-button]',
|
1836 |
),
|
@@ -1855,12 +2325,735 @@ class AMP_Allowed_Tags_Generated {
|
|
1855 |
|
1856 |
),
|
1857 |
),
|
1858 |
-
'circle' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1859 |
array(
|
1860 |
'attr_spec_list' => array(
|
1861 |
'alignment-baseline' => array(),
|
1862 |
'baseline-shift' => array(),
|
1863 |
-
'class' => array(),
|
1864 |
'clip' => array(),
|
1865 |
'clip-path' => array(),
|
1866 |
'clip-rule' => array(),
|
@@ -1870,13 +3063,10 @@ class AMP_Allowed_Tags_Generated {
|
|
1870 |
'color-profile' => array(),
|
1871 |
'color-rendering' => array(),
|
1872 |
'cursor' => array(),
|
1873 |
-
'cx' => array(),
|
1874 |
-
'cy' => array(),
|
1875 |
'direction' => array(),
|
1876 |
'display' => array(),
|
1877 |
'dominant-baseline' => array(),
|
1878 |
'enable-background' => array(),
|
1879 |
-
'externalresourcesrequired' => array(),
|
1880 |
'fill' => array(),
|
1881 |
'fill-opacity' => array(),
|
1882 |
'fill-rule' => array(),
|
@@ -1892,6 +3082,7 @@ class AMP_Allowed_Tags_Generated {
|
|
1892 |
'font-weight' => array(),
|
1893 |
'glyph-orientation-horizontal' => array(),
|
1894 |
'glyph-orientation-vertical' => array(),
|
|
|
1895 |
'image-rendering' => array(),
|
1896 |
'kerning' => array(),
|
1897 |
'letter-spacing' => array(),
|
@@ -1903,11 +3094,8 @@ class AMP_Allowed_Tags_Generated {
|
|
1903 |
'opacity' => array(),
|
1904 |
'overflow' => array(),
|
1905 |
'pointer-events' => array(),
|
1906 |
-
'
|
1907 |
-
'requiredextensions' => array(),
|
1908 |
-
'requiredfeatures' => array(),
|
1909 |
'shape-rendering' => array(),
|
1910 |
-
'sketch:type' => array(),
|
1911 |
'stop-color' => array(),
|
1912 |
'stop-opacity' => array(),
|
1913 |
'stroke' => array(),
|
@@ -1918,45 +3106,44 @@ class AMP_Allowed_Tags_Generated {
|
|
1918 |
'stroke-miterlimit' => array(),
|
1919 |
'stroke-opacity' => array(),
|
1920 |
'stroke-width' => array(),
|
1921 |
-
'
|
|
|
|
|
1922 |
'text-anchor' => array(),
|
1923 |
'text-decoration' => array(),
|
1924 |
'text-rendering' => array(),
|
1925 |
-
'transform' => array(),
|
1926 |
'unicode-bidi' => array(),
|
|
|
1927 |
'visibility' => array(),
|
|
|
1928 |
'word-spacing' => array(),
|
1929 |
'writing-mode' => array(),
|
1930 |
-
'
|
1931 |
'xml:lang' => array(),
|
1932 |
'xml:space' => array(),
|
1933 |
'xmlns' => array(),
|
1934 |
'xmlns:xlink' => array(),
|
|
|
1935 |
),
|
1936 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
1937 |
'mandatory_ancestor' => 'svg',
|
1938 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
1939 |
),
|
1940 |
|
1941 |
),
|
1942 |
),
|
1943 |
-
'
|
1944 |
-
array(
|
1945 |
-
'attr_spec_list' => array(),
|
1946 |
-
'tag_spec' => array(),
|
1947 |
-
|
1948 |
-
),
|
1949 |
-
),
|
1950 |
-
'clippath' => array(
|
1951 |
array(
|
1952 |
'attr_spec_list' => array(
|
1953 |
'alignment-baseline' => array(),
|
1954 |
'baseline-shift' => array(),
|
1955 |
-
'class' => array(),
|
1956 |
'clip' => array(),
|
1957 |
'clip-path' => array(),
|
1958 |
'clip-rule' => array(),
|
1959 |
-
'clippathunits' => array(),
|
1960 |
'color' => array(),
|
1961 |
'color-interpolation' => array(),
|
1962 |
'color-interpolation-filters' => array(),
|
@@ -1966,8 +3153,8 @@ class AMP_Allowed_Tags_Generated {
|
|
1966 |
'direction' => array(),
|
1967 |
'display' => array(),
|
1968 |
'dominant-baseline' => array(),
|
|
|
1969 |
'enable-background' => array(),
|
1970 |
-
'externalresourcesrequired' => array(),
|
1971 |
'fill' => array(),
|
1972 |
'fill-opacity' => array(),
|
1973 |
'fill-rule' => array(),
|
@@ -1983,7 +3170,9 @@ class AMP_Allowed_Tags_Generated {
|
|
1983 |
'font-weight' => array(),
|
1984 |
'glyph-orientation-horizontal' => array(),
|
1985 |
'glyph-orientation-vertical' => array(),
|
|
|
1986 |
'image-rendering' => array(),
|
|
|
1987 |
'kerning' => array(),
|
1988 |
'letter-spacing' => array(),
|
1989 |
'lighting-color' => array(),
|
@@ -1994,9 +3183,9 @@ class AMP_Allowed_Tags_Generated {
|
|
1994 |
'opacity' => array(),
|
1995 |
'overflow' => array(),
|
1996 |
'pointer-events' => array(),
|
1997 |
-
'
|
1998 |
-
'requiredfeatures' => array(),
|
1999 |
'shape-rendering' => array(),
|
|
|
2000 |
'stop-color' => array(),
|
2001 |
'stop-opacity' => array(),
|
2002 |
'stroke' => array(),
|
@@ -2007,86 +3196,41 @@ class AMP_Allowed_Tags_Generated {
|
|
2007 |
'stroke-miterlimit' => array(),
|
2008 |
'stroke-opacity' => array(),
|
2009 |
'stroke-width' => array(),
|
2010 |
-
'
|
|
|
|
|
2011 |
'text-anchor' => array(),
|
2012 |
'text-decoration' => array(),
|
2013 |
'text-rendering' => array(),
|
2014 |
-
'transform' => array(),
|
2015 |
'unicode-bidi' => array(),
|
|
|
2016 |
'visibility' => array(),
|
|
|
2017 |
'word-spacing' => array(),
|
2018 |
'writing-mode' => array(),
|
2019 |
-
'
|
2020 |
'xml:lang' => array(),
|
2021 |
'xml:space' => array(),
|
2022 |
'xmlns' => array(),
|
2023 |
'xmlns:xlink' => array(),
|
|
|
2024 |
),
|
2025 |
'tag_spec' => array(
|
2026 |
-
'
|
2027 |
-
|
2028 |
-
|
2029 |
-
|
2030 |
-
),
|
2031 |
-
),
|
2032 |
-
'code' => array(
|
2033 |
-
array(
|
2034 |
-
'attr_spec_list' => array(),
|
2035 |
-
'tag_spec' => array(),
|
2036 |
-
|
2037 |
-
),
|
2038 |
-
),
|
2039 |
-
'col' => array(
|
2040 |
-
array(
|
2041 |
-
'attr_spec_list' => array(
|
2042 |
-
'span' => array(),
|
2043 |
-
),
|
2044 |
-
'tag_spec' => array(),
|
2045 |
-
|
2046 |
-
),
|
2047 |
-
),
|
2048 |
-
'colgroup' => array(
|
2049 |
-
array(
|
2050 |
-
'attr_spec_list' => array(
|
2051 |
-
'span' => array(),
|
2052 |
-
),
|
2053 |
-
'tag_spec' => array(),
|
2054 |
-
|
2055 |
-
),
|
2056 |
-
),
|
2057 |
-
'data' => array(
|
2058 |
-
array(
|
2059 |
-
'attr_spec_list' => array(),
|
2060 |
-
'tag_spec' => array(),
|
2061 |
-
|
2062 |
-
),
|
2063 |
-
),
|
2064 |
-
'datalist' => array(
|
2065 |
-
array(
|
2066 |
-
'attr_spec_list' => array(),
|
2067 |
-
'tag_spec' => array(
|
2068 |
-
'also_requires_tag' => array(
|
2069 |
-
'amp-form extension .js script',
|
2070 |
),
|
2071 |
-
'mandatory_ancestor' => '
|
2072 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/
|
2073 |
),
|
2074 |
|
2075 |
),
|
2076 |
),
|
2077 |
-
'
|
2078 |
-
array(
|
2079 |
-
'attr_spec_list' => array(),
|
2080 |
-
'tag_spec' => array(),
|
2081 |
-
|
2082 |
-
),
|
2083 |
-
),
|
2084 |
-
'defs' => array(
|
2085 |
array(
|
2086 |
'attr_spec_list' => array(
|
2087 |
'alignment-baseline' => array(),
|
2088 |
'baseline-shift' => array(),
|
2089 |
-
'class' => array(),
|
2090 |
'clip' => array(),
|
2091 |
'clip-path' => array(),
|
2092 |
'clip-rule' => array(),
|
@@ -2100,7 +3244,6 @@ class AMP_Allowed_Tags_Generated {
|
|
2100 |
'display' => array(),
|
2101 |
'dominant-baseline' => array(),
|
2102 |
'enable-background' => array(),
|
2103 |
-
'externalresourcesrequired' => array(),
|
2104 |
'fill' => array(),
|
2105 |
'fill-opacity' => array(),
|
2106 |
'fill-rule' => array(),
|
@@ -2116,6 +3259,7 @@ class AMP_Allowed_Tags_Generated {
|
|
2116 |
'font-weight' => array(),
|
2117 |
'glyph-orientation-horizontal' => array(),
|
2118 |
'glyph-orientation-vertical' => array(),
|
|
|
2119 |
'image-rendering' => array(),
|
2120 |
'kerning' => array(),
|
2121 |
'letter-spacing' => array(),
|
@@ -2127,8 +3271,7 @@ class AMP_Allowed_Tags_Generated {
|
|
2127 |
'opacity' => array(),
|
2128 |
'overflow' => array(),
|
2129 |
'pointer-events' => array(),
|
2130 |
-
'
|
2131 |
-
'requiredfeatures' => array(),
|
2132 |
'shape-rendering' => array(),
|
2133 |
'stop-color' => array(),
|
2134 |
'stop-opacity' => array(),
|
@@ -2140,148 +3283,64 @@ class AMP_Allowed_Tags_Generated {
|
|
2140 |
'stroke-miterlimit' => array(),
|
2141 |
'stroke-opacity' => array(),
|
2142 |
'stroke-width' => array(),
|
2143 |
-
'
|
|
|
|
|
2144 |
'text-anchor' => array(),
|
2145 |
'text-decoration' => array(),
|
2146 |
'text-rendering' => array(),
|
2147 |
-
'transform' => array(),
|
2148 |
'unicode-bidi' => array(),
|
|
|
2149 |
'visibility' => array(),
|
|
|
2150 |
'word-spacing' => array(),
|
2151 |
'writing-mode' => array(),
|
2152 |
-
'
|
2153 |
'xml:lang' => array(),
|
2154 |
'xml:space' => array(),
|
2155 |
'xmlns' => array(),
|
2156 |
'xmlns:xlink' => array(),
|
|
|
2157 |
),
|
2158 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
2159 |
'mandatory_ancestor' => 'svg',
|
2160 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
2161 |
),
|
2162 |
|
2163 |
),
|
2164 |
),
|
2165 |
-
'
|
2166 |
array(
|
2167 |
'attr_spec_list' => array(
|
2168 |
-
'
|
2169 |
-
|
2170 |
-
'
|
2171 |
-
'allowed_protocol' => array(
|
2172 |
-
'fb-messenger',
|
2173 |
-
'ftp',
|
2174 |
-
'http',
|
2175 |
-
'https',
|
2176 |
-
'intent',
|
2177 |
-
'mailto',
|
2178 |
-
'skype',
|
2179 |
-
'sms',
|
2180 |
-
'snapchat',
|
2181 |
-
'tel',
|
2182 |
-
'tg',
|
2183 |
-
'threema',
|
2184 |
-
'twitter',
|
2185 |
-
'viber',
|
2186 |
-
'whatsapp',
|
2187 |
-
),
|
2188 |
),
|
2189 |
-
'datetime' => array(),
|
2190 |
-
),
|
2191 |
-
'tag_spec' => array(),
|
2192 |
-
|
2193 |
-
),
|
2194 |
-
),
|
2195 |
-
'desc' => array(
|
2196 |
-
array(
|
2197 |
-
'attr_spec_list' => array(
|
2198 |
-
'class' => array(),
|
2199 |
-
'xml:base' => array(),
|
2200 |
'xml:lang' => array(),
|
2201 |
'xml:space' => array(),
|
2202 |
'xmlns' => array(),
|
2203 |
'xmlns:xlink' => array(),
|
2204 |
),
|
2205 |
-
'tag_spec' => array(
|
2206 |
-
'mandatory_ancestor' => 'svg',
|
2207 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec.html#svg',
|
2208 |
-
),
|
2209 |
-
|
2210 |
-
),
|
2211 |
-
),
|
2212 |
-
'dfn' => array(
|
2213 |
-
array(
|
2214 |
-
'attr_spec_list' => array(),
|
2215 |
-
'tag_spec' => array(),
|
2216 |
-
|
2217 |
-
),
|
2218 |
-
),
|
2219 |
-
'dir' => array(
|
2220 |
-
array(
|
2221 |
-
'attr_spec_list' => array(),
|
2222 |
'tag_spec' => array(
|
2223 |
'html_format' => array(
|
2224 |
'amp',
|
|
|
2225 |
),
|
|
|
|
|
2226 |
),
|
2227 |
|
2228 |
),
|
2229 |
),
|
2230 |
-
'
|
2231 |
-
array(
|
2232 |
-
'attr_spec_list' => array(
|
2233 |
-
'align' => array(),
|
2234 |
-
),
|
2235 |
-
'tag_spec' => array(),
|
2236 |
-
|
2237 |
-
),
|
2238 |
-
array(
|
2239 |
-
'attr_spec_list' => array(
|
2240 |
-
'align' => array(),
|
2241 |
-
'submit-success' => array(
|
2242 |
-
'mandatory' => true,
|
2243 |
-
),
|
2244 |
-
),
|
2245 |
-
'tag_spec' => array(
|
2246 |
-
'mandatory_parent' => 'form',
|
2247 |
-
'spec_name' => 'form > div [submit-success]',
|
2248 |
-
),
|
2249 |
-
|
2250 |
-
),
|
2251 |
-
array(
|
2252 |
-
'attr_spec_list' => array(
|
2253 |
-
'align' => array(),
|
2254 |
-
'submit-error' => array(
|
2255 |
-
'mandatory' => true,
|
2256 |
-
),
|
2257 |
-
),
|
2258 |
-
'tag_spec' => array(
|
2259 |
-
'mandatory_parent' => 'form',
|
2260 |
-
'spec_name' => 'form > div [submit-error]',
|
2261 |
-
),
|
2262 |
-
|
2263 |
-
),
|
2264 |
-
),
|
2265 |
-
'dl' => array(
|
2266 |
-
array(
|
2267 |
-
'attr_spec_list' => array(),
|
2268 |
-
'tag_spec' => array(),
|
2269 |
-
|
2270 |
-
),
|
2271 |
-
),
|
2272 |
-
'dt' => array(
|
2273 |
-
array(
|
2274 |
-
'attr_spec_list' => array(),
|
2275 |
-
'tag_spec' => array(),
|
2276 |
-
|
2277 |
-
),
|
2278 |
-
),
|
2279 |
-
'ellipse' => array(
|
2280 |
array(
|
2281 |
'attr_spec_list' => array(
|
2282 |
'alignment-baseline' => array(),
|
2283 |
'baseline-shift' => array(),
|
2284 |
-
'class' => array(),
|
2285 |
'clip' => array(),
|
2286 |
'clip-path' => array(),
|
2287 |
'clip-rule' => array(),
|
@@ -2291,13 +3350,12 @@ class AMP_Allowed_Tags_Generated {
|
|
2291 |
'color-profile' => array(),
|
2292 |
'color-rendering' => array(),
|
2293 |
'cursor' => array(),
|
2294 |
-
'cx' => array(),
|
2295 |
-
'cy' => array(),
|
2296 |
'direction' => array(),
|
2297 |
'display' => array(),
|
2298 |
'dominant-baseline' => array(),
|
|
|
|
|
2299 |
'enable-background' => array(),
|
2300 |
-
'externalresourcesrequired' => array(),
|
2301 |
'fill' => array(),
|
2302 |
'fill-opacity' => array(),
|
2303 |
'fill-rule' => array(),
|
@@ -2313,7 +3371,9 @@ class AMP_Allowed_Tags_Generated {
|
|
2313 |
'font-weight' => array(),
|
2314 |
'glyph-orientation-horizontal' => array(),
|
2315 |
'glyph-orientation-vertical' => array(),
|
|
|
2316 |
'image-rendering' => array(),
|
|
|
2317 |
'kerning' => array(),
|
2318 |
'letter-spacing' => array(),
|
2319 |
'lighting-color' => array(),
|
@@ -2324,12 +3384,8 @@ class AMP_Allowed_Tags_Generated {
|
|
2324 |
'opacity' => array(),
|
2325 |
'overflow' => array(),
|
2326 |
'pointer-events' => array(),
|
2327 |
-
'
|
2328 |
-
'requiredfeatures' => array(),
|
2329 |
-
'rx' => array(),
|
2330 |
-
'ry' => array(),
|
2331 |
'shape-rendering' => array(),
|
2332 |
-
'sketch:type' => array(),
|
2333 |
'stop-color' => array(),
|
2334 |
'stop-opacity' => array(),
|
2335 |
'stroke' => array(),
|
@@ -2340,40 +3396,44 @@ class AMP_Allowed_Tags_Generated {
|
|
2340 |
'stroke-miterlimit' => array(),
|
2341 |
'stroke-opacity' => array(),
|
2342 |
'stroke-width' => array(),
|
2343 |
-
'
|
|
|
|
|
2344 |
'text-anchor' => array(),
|
2345 |
'text-decoration' => array(),
|
2346 |
'text-rendering' => array(),
|
2347 |
-
'transform' => array(),
|
2348 |
'unicode-bidi' => array(),
|
|
|
2349 |
'visibility' => array(),
|
|
|
2350 |
'word-spacing' => array(),
|
2351 |
'writing-mode' => array(),
|
2352 |
-
'
|
2353 |
'xml:lang' => array(),
|
2354 |
'xml:space' => array(),
|
2355 |
'xmlns' => array(),
|
2356 |
'xmlns:xlink' => array(),
|
|
|
2357 |
),
|
2358 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
2359 |
'mandatory_ancestor' => 'svg',
|
2360 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
2361 |
),
|
2362 |
|
2363 |
),
|
2364 |
),
|
2365 |
-
'em' => array(
|
2366 |
-
array(
|
2367 |
-
'attr_spec_list' => array(),
|
2368 |
-
'tag_spec' => array(),
|
2369 |
-
|
2370 |
-
),
|
2371 |
-
),
|
2372 |
'fieldset' => array(
|
2373 |
array(
|
2374 |
'attr_spec_list' => array(
|
|
|
2375 |
'disabled' => array(),
|
2376 |
-
'name' => array(
|
|
|
|
|
2377 |
),
|
2378 |
'tag_spec' => array(),
|
2379 |
|
@@ -2398,7 +3458,6 @@ class AMP_Allowed_Tags_Generated {
|
|
2398 |
'attr_spec_list' => array(
|
2399 |
'alignment-baseline' => array(),
|
2400 |
'baseline-shift' => array(),
|
2401 |
-
'class' => array(),
|
2402 |
'clip' => array(),
|
2403 |
'clip-path' => array(),
|
2404 |
'clip-rule' => array(),
|
@@ -2454,10 +3513,14 @@ class AMP_Allowed_Tags_Generated {
|
|
2454 |
'stroke-miterlimit' => array(),
|
2455 |
'stroke-opacity' => array(),
|
2456 |
'stroke-width' => array(),
|
|
|
|
|
|
|
2457 |
'text-anchor' => array(),
|
2458 |
'text-decoration' => array(),
|
2459 |
'text-rendering' => array(),
|
2460 |
'unicode-bidi' => array(),
|
|
|
2461 |
'visibility' => array(),
|
2462 |
'width' => array(),
|
2463 |
'word-spacing' => array(),
|
@@ -2466,13 +3529,20 @@ class AMP_Allowed_Tags_Generated {
|
|
2466 |
'xlink:actuate' => array(),
|
2467 |
'xlink:arcrole' => array(),
|
2468 |
'xlink:href' => array(
|
2469 |
-
'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2470 |
),
|
2471 |
'xlink:role' => array(),
|
2472 |
'xlink:show' => array(),
|
2473 |
'xlink:title' => array(),
|
2474 |
'xlink:type' => array(),
|
2475 |
-
'xml:base' => array(),
|
2476 |
'xml:lang' => array(),
|
2477 |
'xml:space' => array(),
|
2478 |
'xmlns' => array(),
|
@@ -2480,8 +3550,12 @@ class AMP_Allowed_Tags_Generated {
|
|
2480 |
'y' => array(),
|
2481 |
),
|
2482 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
2483 |
'mandatory_ancestor' => 'svg',
|
2484 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
2485 |
),
|
2486 |
|
2487 |
),
|
@@ -2498,7 +3572,6 @@ class AMP_Allowed_Tags_Generated {
|
|
2498 |
'attr_spec_list' => array(
|
2499 |
'alignment-baseline' => array(),
|
2500 |
'baseline-shift' => array(),
|
2501 |
-
'class' => array(),
|
2502 |
'clip' => array(),
|
2503 |
'clip-path' => array(),
|
2504 |
'clip-rule' => array(),
|
@@ -2553,18 +3626,21 @@ class AMP_Allowed_Tags_Generated {
|
|
2553 |
'stroke-miterlimit' => array(),
|
2554 |
'stroke-opacity' => array(),
|
2555 |
'stroke-width' => array(),
|
|
|
|
|
|
|
2556 |
'systemlanguage' => array(),
|
2557 |
'text-anchor' => array(),
|
2558 |
'text-decoration' => array(),
|
2559 |
'text-rendering' => array(),
|
2560 |
'transform' => array(),
|
2561 |
'unicode-bidi' => array(),
|
|
|
2562 |
'visibility' => array(),
|
2563 |
'width' => array(),
|
2564 |
'word-spacing' => array(),
|
2565 |
'writing-mode' => array(),
|
2566 |
'x' => array(),
|
2567 |
-
'xml:base' => array(),
|
2568 |
'xml:lang' => array(),
|
2569 |
'xml:space' => array(),
|
2570 |
'xmlns' => array(),
|
@@ -2572,8 +3648,12 @@ class AMP_Allowed_Tags_Generated {
|
|
2572 |
'y' => array(),
|
2573 |
),
|
2574 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
2575 |
'mandatory_ancestor' => 'svg',
|
2576 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
2577 |
),
|
2578 |
|
2579 |
),
|
@@ -2590,9 +3670,6 @@ class AMP_Allowed_Tags_Generated {
|
|
2590 |
'allowed_protocol' => array(
|
2591 |
'https',
|
2592 |
),
|
2593 |
-
'disallowed_domain' => array(
|
2594 |
-
'cdn.ampproject.org',
|
2595 |
-
),
|
2596 |
),
|
2597 |
'action-xhr' => array(
|
2598 |
'blacklisted_value_regex' => '__amp_source_origin',
|
@@ -2600,13 +3677,10 @@ class AMP_Allowed_Tags_Generated {
|
|
2600 |
'allowed_protocol' => array(
|
2601 |
'https',
|
2602 |
),
|
2603 |
-
'disallowed_domain' => array(
|
2604 |
-
'cdn.ampproject.org',
|
2605 |
-
),
|
2606 |
),
|
2607 |
'autocomplete' => array(),
|
2608 |
'custom-validation-reporting' => array(
|
2609 |
-
'value_regex' => '(show-first-on-submit|show-all-on-submit|as-you-go)',
|
2610 |
),
|
2611 |
'enctype' => array(),
|
2612 |
'method' => array(
|
@@ -2618,16 +3692,23 @@ class AMP_Allowed_Tags_Generated {
|
|
2618 |
'mandatory' => true,
|
2619 |
'value_regex_casei' => '(_blank|_top)',
|
2620 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2621 |
),
|
2622 |
'tag_spec' => array(
|
2623 |
-
'also_requires_tag' => array(
|
2624 |
-
'amp-form extension .js script',
|
2625 |
-
),
|
2626 |
'disallowed_ancestor' => array(
|
2627 |
'amp-app-banner',
|
2628 |
),
|
|
|
|
|
|
|
|
|
2629 |
'spec_name' => 'form [method=get]',
|
2630 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-form.html',
|
2631 |
),
|
2632 |
|
2633 |
),
|
@@ -2642,9 +3723,6 @@ class AMP_Allowed_Tags_Generated {
|
|
2642 |
'allowed_protocol' => array(
|
2643 |
'https',
|
2644 |
),
|
2645 |
-
'disallowed_domain' => array(
|
2646 |
-
'cdn.ampproject.org',
|
2647 |
-
),
|
2648 |
),
|
2649 |
'autocomplete' => array(),
|
2650 |
'custom-validation-reporting' => array(
|
@@ -2652,7 +3730,6 @@ class AMP_Allowed_Tags_Generated {
|
|
2652 |
),
|
2653 |
'enctype' => array(),
|
2654 |
'method' => array(
|
2655 |
-
'dispatch_key' => true,
|
2656 |
'mandatory' => true,
|
2657 |
'value_casei' => 'post',
|
2658 |
),
|
@@ -2662,16 +3739,23 @@ class AMP_Allowed_Tags_Generated {
|
|
2662 |
'mandatory' => true,
|
2663 |
'value_regex_casei' => '(_blank|_top)',
|
2664 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2665 |
),
|
2666 |
'tag_spec' => array(
|
2667 |
-
'also_requires_tag' => array(
|
2668 |
-
'amp-form extension .js script',
|
2669 |
-
),
|
2670 |
'disallowed_ancestor' => array(
|
2671 |
'amp-app-banner',
|
2672 |
),
|
|
|
|
|
|
|
|
|
2673 |
'spec_name' => 'form [method=post]',
|
2674 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-form.html',
|
2675 |
),
|
2676 |
|
2677 |
),
|
@@ -2681,7 +3765,6 @@ class AMP_Allowed_Tags_Generated {
|
|
2681 |
'attr_spec_list' => array(
|
2682 |
'alignment-baseline' => array(),
|
2683 |
'baseline-shift' => array(),
|
2684 |
-
'class' => array(),
|
2685 |
'clip' => array(),
|
2686 |
'clip-path' => array(),
|
2687 |
'clip-rule' => array(),
|
@@ -2735,24 +3818,31 @@ class AMP_Allowed_Tags_Generated {
|
|
2735 |
'stroke-miterlimit' => array(),
|
2736 |
'stroke-opacity' => array(),
|
2737 |
'stroke-width' => array(),
|
|
|
|
|
|
|
2738 |
'systemlanguage' => array(),
|
2739 |
'text-anchor' => array(),
|
2740 |
'text-decoration' => array(),
|
2741 |
'text-rendering' => array(),
|
2742 |
'transform' => array(),
|
2743 |
'unicode-bidi' => array(),
|
|
|
2744 |
'visibility' => array(),
|
2745 |
'word-spacing' => array(),
|
2746 |
'writing-mode' => array(),
|
2747 |
-
'xml:base' => array(),
|
2748 |
'xml:lang' => array(),
|
2749 |
'xml:space' => array(),
|
2750 |
'xmlns' => array(),
|
2751 |
'xmlns:xlink' => array(),
|
2752 |
),
|
2753 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
2754 |
'mandatory_ancestor' => 'svg',
|
2755 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
2756 |
),
|
2757 |
|
2758 |
),
|
@@ -2763,7 +3853,6 @@ class AMP_Allowed_Tags_Generated {
|
|
2763 |
'alignment-baseline' => array(),
|
2764 |
'arabic-form' => array(),
|
2765 |
'baseline-shift' => array(),
|
2766 |
-
'class' => array(),
|
2767 |
'clip' => array(),
|
2768 |
'clip-path' => array(),
|
2769 |
'clip-rule' => array(),
|
@@ -2818,26 +3907,33 @@ class AMP_Allowed_Tags_Generated {
|
|
2818 |
'stroke-miterlimit' => array(),
|
2819 |
'stroke-opacity' => array(),
|
2820 |
'stroke-width' => array(),
|
|
|
|
|
|
|
2821 |
'text-anchor' => array(),
|
2822 |
'text-decoration' => array(),
|
2823 |
'text-rendering' => array(),
|
2824 |
'unicode' => array(),
|
2825 |
'unicode-bidi' => array(),
|
|
|
2826 |
'vert-adv-y' => array(),
|
2827 |
'vert-origin-x' => array(),
|
2828 |
'vert-origin-y' => array(),
|
2829 |
'visibility' => array(),
|
2830 |
'word-spacing' => array(),
|
2831 |
'writing-mode' => array(),
|
2832 |
-
'xml:base' => array(),
|
2833 |
'xml:lang' => array(),
|
2834 |
'xml:space' => array(),
|
2835 |
'xmlns' => array(),
|
2836 |
'xmlns:xlink' => array(),
|
2837 |
),
|
2838 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
2839 |
'mandatory_ancestor' => 'svg',
|
2840 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
2841 |
),
|
2842 |
|
2843 |
),
|
@@ -2847,7 +3943,6 @@ class AMP_Allowed_Tags_Generated {
|
|
2847 |
'attr_spec_list' => array(
|
2848 |
'alignment-baseline' => array(),
|
2849 |
'baseline-shift' => array(),
|
2850 |
-
'class' => array(),
|
2851 |
'clip' => array(),
|
2852 |
'clip-path' => array(),
|
2853 |
'clip-rule' => array(),
|
@@ -2902,10 +3997,14 @@ class AMP_Allowed_Tags_Generated {
|
|
2902 |
'stroke-miterlimit' => array(),
|
2903 |
'stroke-opacity' => array(),
|
2904 |
'stroke-width' => array(),
|
|
|
|
|
|
|
2905 |
'text-anchor' => array(),
|
2906 |
'text-decoration' => array(),
|
2907 |
'text-rendering' => array(),
|
2908 |
'unicode-bidi' => array(),
|
|
|
2909 |
'visibility' => array(),
|
2910 |
'word-spacing' => array(),
|
2911 |
'writing-mode' => array(),
|
@@ -2913,13 +4012,20 @@ class AMP_Allowed_Tags_Generated {
|
|
2913 |
'xlink:actuate' => array(),
|
2914 |
'xlink:arcrole' => array(),
|
2915 |
'xlink:href' => array(
|
2916 |
-
'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2917 |
),
|
2918 |
'xlink:role' => array(),
|
2919 |
'xlink:show' => array(),
|
2920 |
'xlink:title' => array(),
|
2921 |
'xlink:type' => array(),
|
2922 |
-
'xml:base' => array(),
|
2923 |
'xml:lang' => array(),
|
2924 |
'xml:space' => array(),
|
2925 |
'xmlns' => array(),
|
@@ -2927,8 +4033,12 @@ class AMP_Allowed_Tags_Generated {
|
|
2927 |
'y' => array(),
|
2928 |
),
|
2929 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
2930 |
'mandatory_ancestor' => 'svg',
|
2931 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
2932 |
),
|
2933 |
|
2934 |
),
|
@@ -3011,17 +4121,23 @@ class AMP_Allowed_Tags_Generated {
|
|
3011 |
'g1' => array(),
|
3012 |
'g2' => array(),
|
3013 |
'k' => array(),
|
|
|
|
|
|
|
3014 |
'u1' => array(),
|
3015 |
'u2' => array(),
|
3016 |
-
'xml:base' => array(),
|
3017 |
'xml:lang' => array(),
|
3018 |
'xml:space' => array(),
|
3019 |
'xmlns' => array(),
|
3020 |
'xmlns:xlink' => array(),
|
3021 |
),
|
3022 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
3023 |
'mandatory_ancestor' => 'svg',
|
3024 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
3025 |
),
|
3026 |
|
3027 |
),
|
@@ -3040,12 +4156,49 @@ class AMP_Allowed_Tags_Generated {
|
|
3040 |
|
3041 |
),
|
3042 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3043 |
'image' => array(
|
3044 |
array(
|
3045 |
'attr_spec_list' => array(
|
3046 |
'alignment-baseline' => array(),
|
3047 |
'baseline-shift' => array(),
|
3048 |
-
'class' => array(),
|
3049 |
'clip' => array(),
|
3050 |
'clip-path' => array(),
|
3051 |
'clip-rule' => array(),
|
@@ -3101,12 +4254,16 @@ class AMP_Allowed_Tags_Generated {
|
|
3101 |
'stroke-miterlimit' => array(),
|
3102 |
'stroke-opacity' => array(),
|
3103 |
'stroke-width' => array(),
|
|
|
|
|
|
|
3104 |
'systemlanguage' => array(),
|
3105 |
'text-anchor' => array(),
|
3106 |
'text-decoration' => array(),
|
3107 |
'text-rendering' => array(),
|
3108 |
'transform' => array(),
|
3109 |
'unicode-bidi' => array(),
|
|
|
3110 |
'visibility' => array(),
|
3111 |
'width' => array(),
|
3112 |
'word-spacing' => array(),
|
@@ -3115,18 +4272,22 @@ class AMP_Allowed_Tags_Generated {
|
|
3115 |
'xlink:actuate' => array(),
|
3116 |
'xlink:arcrole' => array(),
|
3117 |
'xlink:href' => array(
|
|
|
|
|
|
|
3118 |
'blacklisted_value_regex' => '(^|\\s)data:image\\/svg\\+xml',
|
3119 |
'allow_empty' => false,
|
3120 |
-
'allow_relative' =>
|
3121 |
'allowed_protocol' => array(
|
3122 |
'data',
|
|
|
|
|
3123 |
),
|
3124 |
),
|
3125 |
'xlink:role' => array(),
|
3126 |
'xlink:show' => array(),
|
3127 |
'xlink:title' => array(),
|
3128 |
'xlink:type' => array(),
|
3129 |
-
'xml:base' => array(),
|
3130 |
'xml:lang' => array(),
|
3131 |
'xml:space' => array(),
|
3132 |
'xmlns' => array(),
|
@@ -3134,8 +4295,12 @@ class AMP_Allowed_Tags_Generated {
|
|
3134 |
'y' => array(),
|
3135 |
),
|
3136 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
3137 |
'mandatory_ancestor' => 'svg',
|
3138 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
3139 |
),
|
3140 |
|
3141 |
),
|
@@ -3175,7 +4340,7 @@ class AMP_Allowed_Tags_Generated {
|
|
3175 |
),
|
3176 |
'mandatory_ancestor' => 'noscript',
|
3177 |
'mandatory_ancestor_suggested_alternative' => 'amp-img',
|
3178 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/amp-img
|
3179 |
),
|
3180 |
|
3181 |
),
|
@@ -3183,12 +4348,34 @@ class AMP_Allowed_Tags_Generated {
|
|
3183 |
'input' => array(
|
3184 |
array(
|
3185 |
'attr_spec_list' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3186 |
'accept' => array(),
|
3187 |
'accesskey' => array(),
|
3188 |
'autocomplete' => array(),
|
3189 |
'autofocus' => array(),
|
3190 |
'checked' => array(),
|
3191 |
-
'default-value' => array(),
|
3192 |
'disabled' => array(),
|
3193 |
'height' => array(),
|
3194 |
'inputmode' => array(),
|
@@ -3199,7 +4386,7 @@ class AMP_Allowed_Tags_Generated {
|
|
3199 |
'minlength' => array(),
|
3200 |
'multiple' => array(),
|
3201 |
'name' => array(
|
3202 |
-
'blacklisted_value_regex' => '
|
3203 |
),
|
3204 |
'pattern' => array(),
|
3205 |
'placeholder' => array(),
|
@@ -3217,7 +4404,7 @@ class AMP_Allowed_Tags_Generated {
|
|
3217 |
'width' => array(),
|
3218 |
),
|
3219 |
'tag_spec' => array(
|
3220 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/
|
3221 |
),
|
3222 |
|
3223 |
),
|
@@ -3227,23 +4414,11 @@ class AMP_Allowed_Tags_Generated {
|
|
3227 |
'attr_spec_list' => array(
|
3228 |
'cite' => array(
|
3229 |
'blacklisted_value_regex' => '__amp_source_origin',
|
|
|
3230 |
'allow_relative' => true,
|
3231 |
'allowed_protocol' => array(
|
3232 |
-
'fb-messenger',
|
3233 |
-
'ftp',
|
3234 |
'http',
|
3235 |
'https',
|
3236 |
-
'intent',
|
3237 |
-
'mailto',
|
3238 |
-
'skype',
|
3239 |
-
'sms',
|
3240 |
-
'snapchat',
|
3241 |
-
'tel',
|
3242 |
-
'tg',
|
3243 |
-
'threema',
|
3244 |
-
'twitter',
|
3245 |
-
'viber',
|
3246 |
-
'whatsapp',
|
3247 |
),
|
3248 |
),
|
3249 |
'datetime' => array(),
|
@@ -3265,7 +4440,7 @@ class AMP_Allowed_Tags_Generated {
|
|
3265 |
'for' => array(),
|
3266 |
),
|
3267 |
'tag_spec' => array(
|
3268 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/
|
3269 |
),
|
3270 |
|
3271 |
),
|
@@ -3293,7 +4468,6 @@ class AMP_Allowed_Tags_Generated {
|
|
3293 |
'attr_spec_list' => array(
|
3294 |
'alignment-baseline' => array(),
|
3295 |
'baseline-shift' => array(),
|
3296 |
-
'class' => array(),
|
3297 |
'clip' => array(),
|
3298 |
'clip-path' => array(),
|
3299 |
'clip-rule' => array(),
|
@@ -3348,18 +4522,21 @@ class AMP_Allowed_Tags_Generated {
|
|
3348 |
'stroke-miterlimit' => array(),
|
3349 |
'stroke-opacity' => array(),
|
3350 |
'stroke-width' => array(),
|
|
|
|
|
|
|
3351 |
'systemlanguage' => array(),
|
3352 |
'text-anchor' => array(),
|
3353 |
'text-decoration' => array(),
|
3354 |
'text-rendering' => array(),
|
3355 |
'transform' => array(),
|
3356 |
'unicode-bidi' => array(),
|
|
|
3357 |
'visibility' => array(),
|
3358 |
'word-spacing' => array(),
|
3359 |
'writing-mode' => array(),
|
3360 |
'x1' => array(),
|
3361 |
'x2' => array(),
|
3362 |
-
'xml:base' => array(),
|
3363 |
'xml:lang' => array(),
|
3364 |
'xml:space' => array(),
|
3365 |
'xmlns' => array(),
|
@@ -3368,8 +4545,12 @@ class AMP_Allowed_Tags_Generated {
|
|
3368 |
'y2' => array(),
|
3369 |
),
|
3370 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
3371 |
'mandatory_ancestor' => 'svg',
|
3372 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
3373 |
),
|
3374 |
|
3375 |
),
|
@@ -3379,7 +4560,6 @@ class AMP_Allowed_Tags_Generated {
|
|
3379 |
'attr_spec_list' => array(
|
3380 |
'alignment-baseline' => array(),
|
3381 |
'baseline-shift' => array(),
|
3382 |
-
'class' => array(),
|
3383 |
'clip' => array(),
|
3384 |
'clip-path' => array(),
|
3385 |
'clip-rule' => array(),
|
@@ -3434,10 +4614,14 @@ class AMP_Allowed_Tags_Generated {
|
|
3434 |
'stroke-miterlimit' => array(),
|
3435 |
'stroke-opacity' => array(),
|
3436 |
'stroke-width' => array(),
|
|
|
|
|
|
|
3437 |
'text-anchor' => array(),
|
3438 |
'text-decoration' => array(),
|
3439 |
'text-rendering' => array(),
|
3440 |
'unicode-bidi' => array(),
|
|
|
3441 |
'visibility' => array(),
|
3442 |
'word-spacing' => array(),
|
3443 |
'writing-mode' => array(),
|
@@ -3446,13 +4630,20 @@ class AMP_Allowed_Tags_Generated {
|
|
3446 |
'xlink:actuate' => array(),
|
3447 |
'xlink:arcrole' => array(),
|
3448 |
'xlink:href' => array(
|
3449 |
-
'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3450 |
),
|
3451 |
'xlink:role' => array(),
|
3452 |
'xlink:show' => array(),
|
3453 |
'xlink:title' => array(),
|
3454 |
'xlink:type' => array(),
|
3455 |
-
'xml:base' => array(),
|
3456 |
'xml:lang' => array(),
|
3457 |
'xml:space' => array(),
|
3458 |
'xmlns' => array(),
|
@@ -3461,8 +4652,12 @@ class AMP_Allowed_Tags_Generated {
|
|
3461 |
'y2' => array(),
|
3462 |
),
|
3463 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
3464 |
'mandatory_ancestor' => 'svg',
|
3465 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
3466 |
),
|
3467 |
|
3468 |
),
|
@@ -3489,8 +4684,12 @@ class AMP_Allowed_Tags_Generated {
|
|
3489 |
'disallowed_ancestor' => array(
|
3490 |
'template',
|
3491 |
),
|
|
|
|
|
|
|
|
|
3492 |
'spec_name' => 'link rel=',
|
3493 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
3494 |
),
|
3495 |
|
3496 |
),
|
@@ -3505,7 +4704,6 @@ class AMP_Allowed_Tags_Generated {
|
|
3505 |
),
|
3506 |
'hreflang' => array(),
|
3507 |
'itemprop' => array(
|
3508 |
-
'dispatch_key' => true,
|
3509 |
'mandatory' => true,
|
3510 |
'value_casei' => 'sameas',
|
3511 |
),
|
@@ -3515,8 +4713,12 @@ class AMP_Allowed_Tags_Generated {
|
|
3515 |
'type' => array(),
|
3516 |
),
|
3517 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
3518 |
'spec_name' => 'link itemprop=sameas',
|
3519 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
3520 |
),
|
3521 |
|
3522 |
),
|
@@ -3539,8 +4741,40 @@ class AMP_Allowed_Tags_Generated {
|
|
3539 |
'type' => array(),
|
3540 |
),
|
3541 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
3542 |
'spec_name' => 'link itemprop=',
|
3543 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3544 |
),
|
3545 |
|
3546 |
),
|
@@ -3575,7 +4809,6 @@ class AMP_Allowed_Tags_Generated {
|
|
3575 |
'attr_spec_list' => array(
|
3576 |
'alignment-baseline' => array(),
|
3577 |
'baseline-shift' => array(),
|
3578 |
-
'class' => array(),
|
3579 |
'clip' => array(),
|
3580 |
'clip-path' => array(),
|
3581 |
'clip-rule' => array(),
|
@@ -3634,24 +4867,31 @@ class AMP_Allowed_Tags_Generated {
|
|
3634 |
'stroke-miterlimit' => array(),
|
3635 |
'stroke-opacity' => array(),
|
3636 |
'stroke-width' => array(),
|
|
|
|
|
|
|
3637 |
'text-anchor' => array(),
|
3638 |
'text-decoration' => array(),
|
3639 |
'text-rendering' => array(),
|
3640 |
'transform' => array(),
|
3641 |
'unicode-bidi' => array(),
|
|
|
3642 |
'viewbox' => array(),
|
3643 |
'visibility' => array(),
|
3644 |
'word-spacing' => array(),
|
3645 |
'writing-mode' => array(),
|
3646 |
-
'xml:base' => array(),
|
3647 |
'xml:lang' => array(),
|
3648 |
'xml:space' => array(),
|
3649 |
'xmlns' => array(),
|
3650 |
'xmlns:xlink' => array(),
|
3651 |
),
|
3652 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
3653 |
'mandatory_ancestor' => 'svg',
|
3654 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
3655 |
),
|
3656 |
|
3657 |
),
|
@@ -3661,7 +4901,6 @@ class AMP_Allowed_Tags_Generated {
|
|
3661 |
'attr_spec_list' => array(
|
3662 |
'alignment-baseline' => array(),
|
3663 |
'baseline-shift' => array(),
|
3664 |
-
'class' => array(),
|
3665 |
'clip' => array(),
|
3666 |
'clip-path' => array(),
|
3667 |
'clip-rule' => array(),
|
@@ -3718,17 +4957,20 @@ class AMP_Allowed_Tags_Generated {
|
|
3718 |
'stroke-miterlimit' => array(),
|
3719 |
'stroke-opacity' => array(),
|
3720 |
'stroke-width' => array(),
|
|
|
|
|
|
|
3721 |
'systemlanguage' => array(),
|
3722 |
'text-anchor' => array(),
|
3723 |
'text-decoration' => array(),
|
3724 |
'text-rendering' => array(),
|
3725 |
'unicode-bidi' => array(),
|
|
|
3726 |
'visibility' => array(),
|
3727 |
'width' => array(),
|
3728 |
'word-spacing' => array(),
|
3729 |
'writing-mode' => array(),
|
3730 |
'x' => array(),
|
3731 |
-
'xml:base' => array(),
|
3732 |
'xml:lang' => array(),
|
3733 |
'xml:space' => array(),
|
3734 |
'xmlns' => array(),
|
@@ -3736,8 +4978,12 @@ class AMP_Allowed_Tags_Generated {
|
|
3736 |
'y' => array(),
|
3737 |
),
|
3738 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
3739 |
'mandatory_ancestor' => 'svg',
|
3740 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
3741 |
),
|
3742 |
|
3743 |
),
|
@@ -3747,16 +4993,26 @@ class AMP_Allowed_Tags_Generated {
|
|
3747 |
'attr_spec_list' => array(
|
3748 |
'content' => array(
|
3749 |
'mandatory' => true,
|
|
|
|
|
|
|
|
|
|
|
|
|
3750 |
),
|
3751 |
'http-equiv' => array(
|
3752 |
-
'dispatch_key' => true,
|
3753 |
'mandatory' => true,
|
3754 |
'value_casei' => 'x-ua-compatible',
|
3755 |
),
|
3756 |
),
|
3757 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
3758 |
'spec_name' => 'meta http-equiv=x-ua-compatible',
|
3759 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
3760 |
),
|
3761 |
|
3762 |
),
|
@@ -3765,11 +5021,15 @@ class AMP_Allowed_Tags_Generated {
|
|
3765 |
'content' => array(),
|
3766 |
'itemprop' => array(),
|
3767 |
'name' => array(
|
3768 |
-
'blacklisted_value_regex' => '(^|\\s)(
|
3769 |
),
|
3770 |
'property' => array(),
|
3771 |
),
|
3772 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
3773 |
'spec_name' => 'meta name= and content=',
|
3774 |
),
|
3775 |
|
@@ -3781,14 +5041,18 @@ class AMP_Allowed_Tags_Generated {
|
|
3781 |
'value_casei' => 'text/html; charset=utf-8',
|
3782 |
),
|
3783 |
'http-equiv' => array(
|
3784 |
-
'dispatch_key' => true,
|
3785 |
'mandatory' => true,
|
3786 |
'value_casei' => 'content-type',
|
3787 |
),
|
3788 |
),
|
3789 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
3790 |
'spec_name' => 'meta http-equiv=content-type',
|
3791 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
3792 |
),
|
3793 |
|
3794 |
),
|
@@ -3798,14 +5062,18 @@ class AMP_Allowed_Tags_Generated {
|
|
3798 |
'mandatory' => true,
|
3799 |
),
|
3800 |
'http-equiv' => array(
|
3801 |
-
'dispatch_key' => true,
|
3802 |
'mandatory' => true,
|
3803 |
'value_casei' => 'content-language',
|
3804 |
),
|
3805 |
),
|
3806 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
3807 |
'spec_name' => 'meta http-equiv=content-language',
|
3808 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
3809 |
),
|
3810 |
|
3811 |
),
|
@@ -3815,14 +5083,18 @@ class AMP_Allowed_Tags_Generated {
|
|
3815 |
'mandatory' => true,
|
3816 |
),
|
3817 |
'http-equiv' => array(
|
3818 |
-
'dispatch_key' => true,
|
3819 |
'mandatory' => true,
|
3820 |
'value_casei' => 'pics-label',
|
3821 |
),
|
3822 |
),
|
3823 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
3824 |
'spec_name' => 'meta http-equiv=pics-label',
|
3825 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
3826 |
),
|
3827 |
|
3828 |
),
|
@@ -3832,14 +5104,18 @@ class AMP_Allowed_Tags_Generated {
|
|
3832 |
'mandatory' => true,
|
3833 |
),
|
3834 |
'http-equiv' => array(
|
3835 |
-
'dispatch_key' => true,
|
3836 |
'mandatory' => true,
|
3837 |
'value_casei' => 'imagetoolbar',
|
3838 |
),
|
3839 |
),
|
3840 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
3841 |
'spec_name' => 'meta http-equiv=imagetoolbar',
|
3842 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
3843 |
),
|
3844 |
|
3845 |
),
|
@@ -3850,14 +5126,18 @@ class AMP_Allowed_Tags_Generated {
|
|
3850 |
'value_casei' => 'text/css',
|
3851 |
),
|
3852 |
'http-equiv' => array(
|
3853 |
-
'dispatch_key' => true,
|
3854 |
'mandatory' => true,
|
3855 |
'value_casei' => 'content-style-type',
|
3856 |
),
|
3857 |
),
|
3858 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
3859 |
'spec_name' => 'meta http-equiv=content-style-type',
|
3860 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
3861 |
),
|
3862 |
|
3863 |
),
|
@@ -3868,14 +5148,39 @@ class AMP_Allowed_Tags_Generated {
|
|
3868 |
'value_casei' => 'text/javascript',
|
3869 |
),
|
3870 |
'http-equiv' => array(
|
3871 |
-
'dispatch_key' => true,
|
3872 |
'mandatory' => true,
|
3873 |
'value_casei' => 'content-script-type',
|
3874 |
),
|
3875 |
),
|
3876 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
3877 |
'spec_name' => 'meta http-equiv=content-script-type',
|
3878 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3879 |
),
|
3880 |
|
3881 |
),
|
@@ -3885,15 +5190,55 @@ class AMP_Allowed_Tags_Generated {
|
|
3885 |
'mandatory' => true,
|
3886 |
),
|
3887 |
'http-equiv' => array(
|
3888 |
-
'dispatch_key' => true,
|
3889 |
'mandatory' => true,
|
3890 |
'value_casei' => 'resource-type',
|
3891 |
),
|
3892 |
),
|
3893 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
3894 |
'spec_name' => 'meta http-equiv=resource-type',
|
3895 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3896 |
),
|
|
|
3897 |
|
3898 |
),
|
3899 |
),
|
@@ -3914,6 +5259,24 @@ class AMP_Allowed_Tags_Generated {
|
|
3914 |
'tag_spec' => array(),
|
3915 |
|
3916 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3917 |
),
|
3918 |
'nextid' => array(
|
3919 |
array(
|
@@ -3983,15 +5346,14 @@ class AMP_Allowed_Tags_Generated {
|
|
3983 |
'optgroup' => array(
|
3984 |
array(
|
3985 |
'attr_spec_list' => array(
|
|
|
|
|
3986 |
'disabled' => array(),
|
3987 |
'label' => array(),
|
3988 |
),
|
3989 |
'tag_spec' => array(
|
3990 |
-
'also_requires_tag' => array(
|
3991 |
-
'amp-form extension .js script',
|
3992 |
-
),
|
3993 |
'mandatory_parent' => 'select',
|
3994 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/
|
3995 |
),
|
3996 |
|
3997 |
),
|
@@ -3999,18 +5361,31 @@ class AMP_Allowed_Tags_Generated {
|
|
3999 |
'option' => array(
|
4000 |
array(
|
4001 |
'attr_spec_list' => array(
|
|
|
|
|
|
|
|
|
4002 |
'disabled' => array(),
|
4003 |
'label' => array(),
|
4004 |
'selected' => array(),
|
4005 |
'value' => array(),
|
4006 |
),
|
4007 |
'tag_spec' => array(
|
4008 |
-
'
|
4009 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4010 |
),
|
4011 |
-
'mandatory_ancestor' => 'form',
|
4012 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-form.html',
|
4013 |
),
|
|
|
4014 |
|
4015 |
),
|
4016 |
),
|
@@ -4028,7 +5403,6 @@ class AMP_Allowed_Tags_Generated {
|
|
4028 |
'attr_spec_list' => array(
|
4029 |
'alignment-baseline' => array(),
|
4030 |
'baseline-shift' => array(),
|
4031 |
-
'class' => array(),
|
4032 |
'clip' => array(),
|
4033 |
'clip-path' => array(),
|
4034 |
'clip-rule' => array(),
|
@@ -4085,24 +5459,31 @@ class AMP_Allowed_Tags_Generated {
|
|
4085 |
'stroke-miterlimit' => array(),
|
4086 |
'stroke-opacity' => array(),
|
4087 |
'stroke-width' => array(),
|
|
|
|
|
|
|
4088 |
'systemlanguage' => array(),
|
4089 |
'text-anchor' => array(),
|
4090 |
'text-decoration' => array(),
|
4091 |
'text-rendering' => array(),
|
4092 |
'transform' => array(),
|
4093 |
'unicode-bidi' => array(),
|
|
|
4094 |
'visibility' => array(),
|
4095 |
'word-spacing' => array(),
|
4096 |
'writing-mode' => array(),
|
4097 |
-
'xml:base' => array(),
|
4098 |
'xml:lang' => array(),
|
4099 |
'xml:space' => array(),
|
4100 |
'xmlns' => array(),
|
4101 |
'xmlns:xlink' => array(),
|
4102 |
),
|
4103 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
4104 |
'mandatory_ancestor' => 'svg',
|
4105 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
4106 |
),
|
4107 |
|
4108 |
),
|
@@ -4112,7 +5493,6 @@ class AMP_Allowed_Tags_Generated {
|
|
4112 |
'attr_spec_list' => array(
|
4113 |
'alignment-baseline' => array(),
|
4114 |
'baseline-shift' => array(),
|
4115 |
-
'class' => array(),
|
4116 |
'clip' => array(),
|
4117 |
'clip-path' => array(),
|
4118 |
'clip-rule' => array(),
|
@@ -4171,11 +5551,15 @@ class AMP_Allowed_Tags_Generated {
|
|
4171 |
'stroke-miterlimit' => array(),
|
4172 |
'stroke-opacity' => array(),
|
4173 |
'stroke-width' => array(),
|
|
|
|
|
|
|
4174 |
'systemlanguage' => array(),
|
4175 |
'text-anchor' => array(),
|
4176 |
'text-decoration' => array(),
|
4177 |
'text-rendering' => array(),
|
4178 |
'unicode-bidi' => array(),
|
|
|
4179 |
'viewbox' => array(),
|
4180 |
'visibility' => array(),
|
4181 |
'width' => array(),
|
@@ -4185,13 +5569,20 @@ class AMP_Allowed_Tags_Generated {
|
|
4185 |
'xlink:actuate' => array(),
|
4186 |
'xlink:arcrole' => array(),
|
4187 |
'xlink:href' => array(
|
4188 |
-
'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4189 |
),
|
4190 |
'xlink:role' => array(),
|
4191 |
'xlink:show' => array(),
|
4192 |
'xlink:title' => array(),
|
4193 |
'xlink:type' => array(),
|
4194 |
-
'xml:base' => array(),
|
4195 |
'xml:lang' => array(),
|
4196 |
'xml:space' => array(),
|
4197 |
'xmlns' => array(),
|
@@ -4199,8 +5590,12 @@ class AMP_Allowed_Tags_Generated {
|
|
4199 |
'y' => array(),
|
4200 |
),
|
4201 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
4202 |
'mandatory_ancestor' => 'svg',
|
4203 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
4204 |
),
|
4205 |
|
4206 |
),
|
@@ -4210,7 +5605,6 @@ class AMP_Allowed_Tags_Generated {
|
|
4210 |
'attr_spec_list' => array(
|
4211 |
'alignment-baseline' => array(),
|
4212 |
'baseline-shift' => array(),
|
4213 |
-
'class' => array(),
|
4214 |
'clip' => array(),
|
4215 |
'clip-path' => array(),
|
4216 |
'clip-rule' => array(),
|
@@ -4266,24 +5660,31 @@ class AMP_Allowed_Tags_Generated {
|
|
4266 |
'stroke-miterlimit' => array(),
|
4267 |
'stroke-opacity' => array(),
|
4268 |
'stroke-width' => array(),
|
|
|
|
|
|
|
4269 |
'systemlanguage' => array(),
|
4270 |
'text-anchor' => array(),
|
4271 |
'text-decoration' => array(),
|
4272 |
'text-rendering' => array(),
|
4273 |
'transform' => array(),
|
4274 |
'unicode-bidi' => array(),
|
|
|
4275 |
'visibility' => array(),
|
4276 |
'word-spacing' => array(),
|
4277 |
'writing-mode' => array(),
|
4278 |
-
'xml:base' => array(),
|
4279 |
'xml:lang' => array(),
|
4280 |
'xml:space' => array(),
|
4281 |
'xmlns' => array(),
|
4282 |
'xmlns:xlink' => array(),
|
4283 |
),
|
4284 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
4285 |
'mandatory_ancestor' => 'svg',
|
4286 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
4287 |
),
|
4288 |
|
4289 |
),
|
@@ -4293,7 +5694,6 @@ class AMP_Allowed_Tags_Generated {
|
|
4293 |
'attr_spec_list' => array(
|
4294 |
'alignment-baseline' => array(),
|
4295 |
'baseline-shift' => array(),
|
4296 |
-
'class' => array(),
|
4297 |
'clip' => array(),
|
4298 |
'clip-path' => array(),
|
4299 |
'clip-rule' => array(),
|
@@ -4349,24 +5749,31 @@ class AMP_Allowed_Tags_Generated {
|
|
4349 |
'stroke-miterlimit' => array(),
|
4350 |
'stroke-opacity' => array(),
|
4351 |
'stroke-width' => array(),
|
|
|
|
|
|
|
4352 |
'systemlanguage' => array(),
|
4353 |
'text-anchor' => array(),
|
4354 |
'text-decoration' => array(),
|
4355 |
'text-rendering' => array(),
|
4356 |
'transform' => array(),
|
4357 |
'unicode-bidi' => array(),
|
|
|
4358 |
'visibility' => array(),
|
4359 |
'word-spacing' => array(),
|
4360 |
'writing-mode' => array(),
|
4361 |
-
'xml:base' => array(),
|
4362 |
'xml:lang' => array(),
|
4363 |
'xml:space' => array(),
|
4364 |
'xmlns' => array(),
|
4365 |
'xmlns:xlink' => array(),
|
4366 |
),
|
4367 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
4368 |
'mandatory_ancestor' => 'svg',
|
4369 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
4370 |
),
|
4371 |
|
4372 |
),
|
@@ -4378,28 +5785,26 @@ class AMP_Allowed_Tags_Generated {
|
|
4378 |
|
4379 |
),
|
4380 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4381 |
'q' => array(
|
4382 |
array(
|
4383 |
'attr_spec_list' => array(
|
4384 |
'cite' => array(
|
4385 |
'blacklisted_value_regex' => '__amp_source_origin',
|
|
|
4386 |
'allow_relative' => true,
|
4387 |
'allowed_protocol' => array(
|
4388 |
-
'fb-messenger',
|
4389 |
-
'ftp',
|
4390 |
'http',
|
4391 |
'https',
|
4392 |
-
'intent',
|
4393 |
-
'mailto',
|
4394 |
-
'skype',
|
4395 |
-
'sms',
|
4396 |
-
'snapchat',
|
4397 |
-
'tel',
|
4398 |
-
'tg',
|
4399 |
-
'threema',
|
4400 |
-
'twitter',
|
4401 |
-
'viber',
|
4402 |
-
'whatsapp',
|
4403 |
),
|
4404 |
),
|
4405 |
),
|
@@ -4412,7 +5817,6 @@ class AMP_Allowed_Tags_Generated {
|
|
4412 |
'attr_spec_list' => array(
|
4413 |
'alignment-baseline' => array(),
|
4414 |
'baseline-shift' => array(),
|
4415 |
-
'class' => array(),
|
4416 |
'clip' => array(),
|
4417 |
'clip-path' => array(),
|
4418 |
'clip-rule' => array(),
|
@@ -4442,6 +5846,7 @@ class AMP_Allowed_Tags_Generated {
|
|
4442 |
'font-style' => array(),
|
4443 |
'font-variant' => array(),
|
4444 |
'font-weight' => array(),
|
|
|
4445 |
'fx' => array(),
|
4446 |
'fy' => array(),
|
4447 |
'glyph-orientation-horizontal' => array(),
|
@@ -4472,31 +5877,46 @@ class AMP_Allowed_Tags_Generated {
|
|
4472 |
'stroke-miterlimit' => array(),
|
4473 |
'stroke-opacity' => array(),
|
4474 |
'stroke-width' => array(),
|
|
|
|
|
|
|
4475 |
'text-anchor' => array(),
|
4476 |
'text-decoration' => array(),
|
4477 |
'text-rendering' => array(),
|
4478 |
'unicode-bidi' => array(),
|
|
|
4479 |
'visibility' => array(),
|
4480 |
'word-spacing' => array(),
|
4481 |
'writing-mode' => array(),
|
4482 |
'xlink:actuate' => array(),
|
4483 |
'xlink:arcrole' => array(),
|
4484 |
'xlink:href' => array(
|
4485 |
-
'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4486 |
),
|
4487 |
'xlink:role' => array(),
|
4488 |
'xlink:show' => array(),
|
4489 |
'xlink:title' => array(),
|
4490 |
'xlink:type' => array(),
|
4491 |
-
'xml:base' => array(),
|
4492 |
'xml:lang' => array(),
|
4493 |
'xml:space' => array(),
|
4494 |
'xmlns' => array(),
|
4495 |
'xmlns:xlink' => array(),
|
4496 |
),
|
4497 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
4498 |
'mandatory_ancestor' => 'svg',
|
4499 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
4500 |
),
|
4501 |
|
4502 |
),
|
@@ -4513,7 +5933,6 @@ class AMP_Allowed_Tags_Generated {
|
|
4513 |
'attr_spec_list' => array(
|
4514 |
'alignment-baseline' => array(),
|
4515 |
'baseline-shift' => array(),
|
4516 |
-
'class' => array(),
|
4517 |
'clip' => array(),
|
4518 |
'clip-path' => array(),
|
4519 |
'clip-rule' => array(),
|
@@ -4571,18 +5990,21 @@ class AMP_Allowed_Tags_Generated {
|
|
4571 |
'stroke-miterlimit' => array(),
|
4572 |
'stroke-opacity' => array(),
|
4573 |
'stroke-width' => array(),
|
|
|
|
|
|
|
4574 |
'systemlanguage' => array(),
|
4575 |
'text-anchor' => array(),
|
4576 |
'text-decoration' => array(),
|
4577 |
'text-rendering' => array(),
|
4578 |
'transform' => array(),
|
4579 |
'unicode-bidi' => array(),
|
|
|
4580 |
'visibility' => array(),
|
4581 |
'width' => array(),
|
4582 |
'word-spacing' => array(),
|
4583 |
'writing-mode' => array(),
|
4584 |
'x' => array(),
|
4585 |
-
'xml:base' => array(),
|
4586 |
'xml:lang' => array(),
|
4587 |
'xml:space' => array(),
|
4588 |
'xmlns' => array(),
|
@@ -4590,8 +6012,12 @@ class AMP_Allowed_Tags_Generated {
|
|
4590 |
'y' => array(),
|
4591 |
),
|
4592 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
4593 |
'mandatory_ancestor' => 'svg',
|
4594 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
4595 |
),
|
4596 |
|
4597 |
),
|
@@ -4641,8 +6067,8 @@ class AMP_Allowed_Tags_Generated {
|
|
4641 |
'script' => array(
|
4642 |
array(
|
4643 |
'attr_spec_list' => array(
|
|
|
4644 |
'type' => array(
|
4645 |
-
'dispatch_key' => true,
|
4646 |
'mandatory' => true,
|
4647 |
'value_casei' => 'application/ld+json',
|
4648 |
),
|
@@ -4655,7 +6081,6 @@ class AMP_Allowed_Tags_Generated {
|
|
4655 |
array(
|
4656 |
'attr_spec_list' => array(
|
4657 |
'type' => array(
|
4658 |
-
'dispatch_key' => true,
|
4659 |
'mandatory' => true,
|
4660 |
'value_casei' => 'application/json',
|
4661 |
),
|
@@ -4663,21 +6088,33 @@ class AMP_Allowed_Tags_Generated {
|
|
4663 |
'tag_spec' => array(
|
4664 |
'html_format' => array(
|
4665 |
'amp',
|
4666 |
-
'amp4ads',
|
4667 |
),
|
4668 |
-
'mandatory_parent' => 'amp-
|
4669 |
-
'spec_name' => 'amp-
|
4670 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-analytics.html',
|
4671 |
),
|
4672 |
|
4673 |
),
|
4674 |
array(
|
4675 |
'attr_spec_list' => array(
|
4676 |
-
'
|
4677 |
-
|
4678 |
'mandatory' => true,
|
4679 |
-
'value' => '',
|
|
|
|
|
|
|
|
|
|
|
4680 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4681 |
'type' => array(
|
4682 |
'mandatory' => true,
|
4683 |
'value_casei' => 'application/json',
|
@@ -4688,16 +6125,30 @@ class AMP_Allowed_Tags_Generated {
|
|
4688 |
'amp',
|
4689 |
'amp4ads',
|
4690 |
),
|
4691 |
-
'mandatory_parent' => '
|
4692 |
-
'spec_name' => 'amp-
|
4693 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4694 |
),
|
4695 |
|
4696 |
),
|
4697 |
array(
|
4698 |
'attr_spec_list' => array(
|
|
|
4699 |
'type' => array(
|
4700 |
-
'dispatch_key' => true,
|
4701 |
'mandatory' => true,
|
4702 |
'value_casei' => 'application/json',
|
4703 |
),
|
@@ -4708,14 +6159,14 @@ class AMP_Allowed_Tags_Generated {
|
|
4708 |
),
|
4709 |
'mandatory_parent' => 'amp-state',
|
4710 |
'spec_name' => 'amp-bind extension .json script',
|
4711 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/
|
4712 |
),
|
4713 |
|
4714 |
),
|
4715 |
array(
|
4716 |
'attr_spec_list' => array(
|
|
|
4717 |
'type' => array(
|
4718 |
-
'dispatch_key' => true,
|
4719 |
'mandatory' => true,
|
4720 |
'value_casei' => 'application/json',
|
4721 |
),
|
@@ -4726,7 +6177,7 @@ class AMP_Allowed_Tags_Generated {
|
|
4726 |
),
|
4727 |
'mandatory_parent' => 'amp-experiment',
|
4728 |
'spec_name' => 'amp-experiment extension .json script',
|
4729 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/
|
4730 |
),
|
4731 |
|
4732 |
),
|
@@ -4748,10 +6199,6 @@ class AMP_Allowed_Tags_Generated {
|
|
4748 |
),
|
4749 |
),
|
4750 |
'tag_spec' => array(
|
4751 |
-
'html_format' => array(
|
4752 |
-
'amp',
|
4753 |
-
'amp4ads',
|
4754 |
-
),
|
4755 |
'mandatory_parent' => 'amp-accordion',
|
4756 |
'spec_name' => 'amp-accordion > section',
|
4757 |
),
|
@@ -4761,19 +6208,35 @@ class AMP_Allowed_Tags_Generated {
|
|
4761 |
'select' => array(
|
4762 |
array(
|
4763 |
'attr_spec_list' => array(
|
|
|
|
|
|
|
|
|
|
|
4764 |
'autofocus' => array(),
|
4765 |
'disabled' => array(),
|
4766 |
'multiple' => array(),
|
4767 |
-
'name' => array(
|
|
|
|
|
4768 |
'required' => array(),
|
4769 |
'size' => array(),
|
4770 |
),
|
4771 |
'tag_spec' => array(
|
4772 |
-
'
|
4773 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4774 |
),
|
4775 |
-
'mandatory_ancestor' => 'form',
|
4776 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-form.html',
|
4777 |
),
|
4778 |
|
4779 |
),
|
@@ -4785,9 +6248,95 @@ class AMP_Allowed_Tags_Generated {
|
|
4785 |
|
4786 |
),
|
4787 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4788 |
'source' => array(
|
4789 |
array(
|
4790 |
'attr_spec_list' => array(
|
|
|
|
|
4791 |
'media' => array(),
|
4792 |
'src' => array(
|
4793 |
'blacklisted_value_regex' => '__amp_source_origin',
|
@@ -4799,14 +6348,20 @@ class AMP_Allowed_Tags_Generated {
|
|
4799 |
'type' => array(),
|
4800 |
),
|
4801 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
4802 |
'mandatory_parent' => 'amp-video',
|
4803 |
'spec_name' => 'amp-video > source',
|
4804 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/amp-video
|
4805 |
),
|
4806 |
|
4807 |
),
|
4808 |
array(
|
4809 |
'attr_spec_list' => array(
|
|
|
|
|
4810 |
'media' => array(),
|
4811 |
'src' => array(
|
4812 |
'blacklisted_value_regex' => '__amp_source_origin',
|
@@ -4818,9 +6373,13 @@ class AMP_Allowed_Tags_Generated {
|
|
4818 |
'type' => array(),
|
4819 |
),
|
4820 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
4821 |
'mandatory_parent' => 'amp-audio',
|
4822 |
'spec_name' => 'amp-audio > source',
|
4823 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/
|
4824 |
),
|
4825 |
|
4826 |
),
|
@@ -4840,9 +6399,13 @@ class AMP_Allowed_Tags_Generated {
|
|
4840 |
),
|
4841 |
),
|
4842 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
4843 |
'mandatory_parent' => 'audio',
|
4844 |
'spec_name' => 'audio > source',
|
4845 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/
|
4846 |
),
|
4847 |
|
4848 |
),
|
@@ -4862,9 +6425,37 @@ class AMP_Allowed_Tags_Generated {
|
|
4862 |
),
|
4863 |
),
|
4864 |
'tag_spec' => array(
|
4865 |
-
'
|
4866 |
-
|
4867 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4868 |
),
|
4869 |
|
4870 |
),
|
@@ -4893,11 +6484,18 @@ class AMP_Allowed_Tags_Generated {
|
|
4893 |
'offset' => array(),
|
4894 |
'stop-color' => array(),
|
4895 |
'stop-opacity' => array(),
|
|
|
|
|
|
|
4896 |
),
|
4897 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
4898 |
'mandatory_ancestor' => 'lineargradient',
|
4899 |
'spec_name' => 'lineargradient > stop',
|
4900 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
4901 |
),
|
4902 |
|
4903 |
),
|
@@ -4906,11 +6504,18 @@ class AMP_Allowed_Tags_Generated {
|
|
4906 |
'offset' => array(),
|
4907 |
'stop-color' => array(),
|
4908 |
'stop-opacity' => array(),
|
|
|
|
|
|
|
4909 |
),
|
4910 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
4911 |
'mandatory_ancestor' => 'radialgradient',
|
4912 |
'spec_name' => 'radialgradient > stop',
|
4913 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
4914 |
),
|
4915 |
|
4916 |
),
|
@@ -4937,19 +6542,17 @@ class AMP_Allowed_Tags_Generated {
|
|
4937 |
array(
|
4938 |
'attr_spec_list' => array(
|
4939 |
'amp-boilerplate' => array(
|
4940 |
-
'dispatch_key' => true,
|
4941 |
'mandatory' => true,
|
4942 |
'value' => '',
|
4943 |
),
|
|
|
4944 |
),
|
4945 |
'tag_spec' => array(
|
4946 |
-
'also_requires_tag' => array(
|
4947 |
-
'head > style[amp-boilerplate]',
|
4948 |
-
),
|
4949 |
'html_format' => array(
|
4950 |
'amp',
|
4951 |
),
|
4952 |
'mandatory_alternatives' => 'noscript > style[amp-boilerplate]',
|
|
|
4953 |
'mandatory_parent' => 'noscript',
|
4954 |
'spec_name' => 'noscript > style[amp-boilerplate]',
|
4955 |
'spec_url' => 'https://github.com/ampproject/amphtml/blob/master/spec/amp-boilerplate.md',
|
@@ -4957,6 +6560,24 @@ class AMP_Allowed_Tags_Generated {
|
|
4957 |
),
|
4958 |
|
4959 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4960 |
),
|
4961 |
'sub' => array(
|
4962 |
array(
|
@@ -4977,7 +6598,6 @@ class AMP_Allowed_Tags_Generated {
|
|
4977 |
'attr_spec_list' => array(
|
4978 |
'alignment-baseline' => array(),
|
4979 |
'baseline-shift' => array(),
|
4980 |
-
'class' => array(),
|
4981 |
'clip' => array(),
|
4982 |
'clip-path' => array(),
|
4983 |
'clip-rule' => array(),
|
@@ -5040,6 +6660,7 @@ class AMP_Allowed_Tags_Generated {
|
|
5040 |
'text-decoration' => array(),
|
5041 |
'text-rendering' => array(),
|
5042 |
'unicode-bidi' => array(),
|
|
|
5043 |
'version' => array(
|
5044 |
'value_regex' => '(1.0|1.1)',
|
5045 |
),
|
@@ -5049,7 +6670,6 @@ class AMP_Allowed_Tags_Generated {
|
|
5049 |
'word-spacing' => array(),
|
5050 |
'writing-mode' => array(),
|
5051 |
'x' => array(),
|
5052 |
-
'xml:base' => array(),
|
5053 |
'xml:lang' => array(),
|
5054 |
'xml:space' => array(),
|
5055 |
'xmlns' => array(),
|
@@ -5058,7 +6678,96 @@ class AMP_Allowed_Tags_Generated {
|
|
5058 |
'zoomandpan' => array(),
|
5059 |
),
|
5060 |
'tag_spec' => array(
|
5061 |
-
'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5062 |
),
|
5063 |
|
5064 |
),
|
@@ -5068,7 +6777,6 @@ class AMP_Allowed_Tags_Generated {
|
|
5068 |
'attr_spec_list' => array(
|
5069 |
'alignment-baseline' => array(),
|
5070 |
'baseline-shift' => array(),
|
5071 |
-
'class' => array(),
|
5072 |
'clip' => array(),
|
5073 |
'clip-path' => array(),
|
5074 |
'clip-rule' => array(),
|
@@ -5121,23 +6829,30 @@ class AMP_Allowed_Tags_Generated {
|
|
5121 |
'stroke-miterlimit' => array(),
|
5122 |
'stroke-opacity' => array(),
|
5123 |
'stroke-width' => array(),
|
|
|
|
|
|
|
5124 |
'text-anchor' => array(),
|
5125 |
'text-decoration' => array(),
|
5126 |
'text-rendering' => array(),
|
5127 |
'unicode-bidi' => array(),
|
|
|
5128 |
'viewbox' => array(),
|
5129 |
'visibility' => array(),
|
5130 |
'word-spacing' => array(),
|
5131 |
'writing-mode' => array(),
|
5132 |
-
'xml:base' => array(),
|
5133 |
'xml:lang' => array(),
|
5134 |
'xml:space' => array(),
|
5135 |
'xmlns' => array(),
|
5136 |
'xmlns:xlink' => array(),
|
5137 |
),
|
5138 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
5139 |
'mandatory_ancestor' => 'svg',
|
5140 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
5141 |
),
|
5142 |
|
5143 |
),
|
@@ -5191,13 +6906,9 @@ class AMP_Allowed_Tags_Generated {
|
|
5191 |
),
|
5192 |
),
|
5193 |
'tag_spec' => array(
|
5194 |
-
'also_requires_tag' => array(
|
5195 |
-
'amp-mustache extension .js script',
|
5196 |
-
),
|
5197 |
'disallowed_ancestor' => array(
|
5198 |
'template',
|
5199 |
),
|
5200 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-mustache.html',
|
5201 |
),
|
5202 |
|
5203 |
),
|
@@ -5207,7 +6918,6 @@ class AMP_Allowed_Tags_Generated {
|
|
5207 |
'attr_spec_list' => array(
|
5208 |
'alignment-baseline' => array(),
|
5209 |
'baseline-shift' => array(),
|
5210 |
-
'class' => array(),
|
5211 |
'clip' => array(),
|
5212 |
'clip-path' => array(),
|
5213 |
'clip-rule' => array(),
|
@@ -5265,6 +6975,9 @@ class AMP_Allowed_Tags_Generated {
|
|
5265 |
'stroke-miterlimit' => array(),
|
5266 |
'stroke-opacity' => array(),
|
5267 |
'stroke-width' => array(),
|
|
|
|
|
|
|
5268 |
'systemlanguage' => array(),
|
5269 |
'text-anchor' => array(),
|
5270 |
'text-decoration' => array(),
|
@@ -5272,11 +6985,11 @@ class AMP_Allowed_Tags_Generated {
|
|
5272 |
'textlength' => array(),
|
5273 |
'transform' => array(),
|
5274 |
'unicode-bidi' => array(),
|
|
|
5275 |
'visibility' => array(),
|
5276 |
'word-spacing' => array(),
|
5277 |
'writing-mode' => array(),
|
5278 |
'x' => array(),
|
5279 |
-
'xml:base' => array(),
|
5280 |
'xml:lang' => array(),
|
5281 |
'xml:space' => array(),
|
5282 |
'xmlns' => array(),
|
@@ -5284,8 +6997,12 @@ class AMP_Allowed_Tags_Generated {
|
|
5284 |
'y' => array(),
|
5285 |
),
|
5286 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
5287 |
'mandatory_ancestor' => 'svg',
|
5288 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
5289 |
),
|
5290 |
|
5291 |
),
|
@@ -5293,13 +7010,30 @@ class AMP_Allowed_Tags_Generated {
|
|
5293 |
'textarea' => array(
|
5294 |
array(
|
5295 |
'attr_spec_list' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5296 |
'autocomplete' => array(),
|
5297 |
'autofocus' => array(),
|
5298 |
'cols' => array(),
|
5299 |
'disabled' => array(),
|
5300 |
'maxlength' => array(),
|
5301 |
'minlength' => array(),
|
5302 |
-
'name' => array(
|
|
|
|
|
5303 |
'placeholder' => array(),
|
5304 |
'readonly' => array(),
|
5305 |
'required' => array(),
|
@@ -5311,11 +7045,7 @@ class AMP_Allowed_Tags_Generated {
|
|
5311 |
'wrap' => array(),
|
5312 |
),
|
5313 |
'tag_spec' => array(
|
5314 |
-
'
|
5315 |
-
'amp-form extension .js script',
|
5316 |
-
),
|
5317 |
-
'mandatory_ancestor' => 'form',
|
5318 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/extended/amp-form.html',
|
5319 |
),
|
5320 |
|
5321 |
),
|
@@ -5325,7 +7055,6 @@ class AMP_Allowed_Tags_Generated {
|
|
5325 |
'attr_spec_list' => array(
|
5326 |
'alignment-baseline' => array(),
|
5327 |
'baseline-shift' => array(),
|
5328 |
-
'class' => array(),
|
5329 |
'clip' => array(),
|
5330 |
'clip-path' => array(),
|
5331 |
'clip-rule' => array(),
|
@@ -5382,32 +7111,47 @@ class AMP_Allowed_Tags_Generated {
|
|
5382 |
'stroke-miterlimit' => array(),
|
5383 |
'stroke-opacity' => array(),
|
5384 |
'stroke-width' => array(),
|
|
|
|
|
|
|
5385 |
'systemlanguage' => array(),
|
5386 |
'text-anchor' => array(),
|
5387 |
'text-decoration' => array(),
|
5388 |
'text-rendering' => array(),
|
5389 |
'unicode-bidi' => array(),
|
|
|
5390 |
'visibility' => array(),
|
5391 |
'word-spacing' => array(),
|
5392 |
'writing-mode' => array(),
|
5393 |
'xlink:actuate' => array(),
|
5394 |
'xlink:arcrole' => array(),
|
5395 |
'xlink:href' => array(
|
5396 |
-
'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5397 |
),
|
5398 |
'xlink:role' => array(),
|
5399 |
'xlink:show' => array(),
|
5400 |
'xlink:title' => array(),
|
5401 |
'xlink:type' => array(),
|
5402 |
-
'xml:base' => array(),
|
5403 |
'xml:lang' => array(),
|
5404 |
'xml:space' => array(),
|
5405 |
'xmlns' => array(),
|
5406 |
'xmlns:xlink' => array(),
|
5407 |
),
|
5408 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
5409 |
'mandatory_ancestor' => 'svg',
|
5410 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
5411 |
),
|
5412 |
|
5413 |
),
|
@@ -5464,17 +7208,22 @@ class AMP_Allowed_Tags_Generated {
|
|
5464 |
),
|
5465 |
array(
|
5466 |
'attr_spec_list' => array(
|
5467 |
-
'
|
5468 |
-
|
|
|
5469 |
'xml:lang' => array(),
|
5470 |
'xml:space' => array(),
|
5471 |
'xmlns' => array(),
|
5472 |
'xmlns:xlink' => array(),
|
5473 |
),
|
5474 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
5475 |
'mandatory_ancestor' => 'svg',
|
5476 |
'spec_name' => 'svg title',
|
5477 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
5478 |
),
|
5479 |
|
5480 |
),
|
@@ -5512,6 +7261,10 @@ class AMP_Allowed_Tags_Generated {
|
|
5512 |
'srclang' => array(),
|
5513 |
),
|
5514 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
5515 |
'mandatory_parent' => 'audio',
|
5516 |
'spec_name' => 'audio > track',
|
5517 |
),
|
@@ -5540,6 +7293,10 @@ class AMP_Allowed_Tags_Generated {
|
|
5540 |
),
|
5541 |
),
|
5542 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
5543 |
'mandatory_parent' => 'audio',
|
5544 |
'spec_name' => 'audio > track[kind=subtitles]',
|
5545 |
),
|
@@ -5565,6 +7322,10 @@ class AMP_Allowed_Tags_Generated {
|
|
5565 |
'srclang' => array(),
|
5566 |
),
|
5567 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
5568 |
'mandatory_parent' => 'video',
|
5569 |
'spec_name' => 'video > track',
|
5570 |
),
|
@@ -5593,6 +7354,10 @@ class AMP_Allowed_Tags_Generated {
|
|
5593 |
),
|
5594 |
),
|
5595 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
5596 |
'mandatory_parent' => 'video',
|
5597 |
'spec_name' => 'video > track[kind=subtitles]',
|
5598 |
),
|
@@ -5600,6 +7365,9 @@ class AMP_Allowed_Tags_Generated {
|
|
5600 |
),
|
5601 |
array(
|
5602 |
'attr_spec_list' => array(
|
|
|
|
|
|
|
5603 |
'default' => array(
|
5604 |
'value' => '',
|
5605 |
),
|
@@ -5618,6 +7386,10 @@ class AMP_Allowed_Tags_Generated {
|
|
5618 |
'srclang' => array(),
|
5619 |
),
|
5620 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
5621 |
'mandatory_parent' => 'amp-audio',
|
5622 |
'spec_name' => 'amp-audio > track',
|
5623 |
),
|
@@ -5625,6 +7397,9 @@ class AMP_Allowed_Tags_Generated {
|
|
5625 |
),
|
5626 |
array(
|
5627 |
'attr_spec_list' => array(
|
|
|
|
|
|
|
5628 |
'default' => array(
|
5629 |
'value' => '',
|
5630 |
),
|
@@ -5646,6 +7421,10 @@ class AMP_Allowed_Tags_Generated {
|
|
5646 |
),
|
5647 |
),
|
5648 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
5649 |
'mandatory_parent' => 'amp-audio',
|
5650 |
'spec_name' => 'amp-audio > track[kind=subtitles]',
|
5651 |
),
|
@@ -5653,6 +7432,9 @@ class AMP_Allowed_Tags_Generated {
|
|
5653 |
),
|
5654 |
array(
|
5655 |
'attr_spec_list' => array(
|
|
|
|
|
|
|
5656 |
'default' => array(
|
5657 |
'value' => '',
|
5658 |
),
|
@@ -5671,6 +7453,10 @@ class AMP_Allowed_Tags_Generated {
|
|
5671 |
'srclang' => array(),
|
5672 |
),
|
5673 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
5674 |
'mandatory_parent' => 'amp-video',
|
5675 |
'spec_name' => 'amp-video > track',
|
5676 |
),
|
@@ -5678,6 +7464,9 @@ class AMP_Allowed_Tags_Generated {
|
|
5678 |
),
|
5679 |
array(
|
5680 |
'attr_spec_list' => array(
|
|
|
|
|
|
|
5681 |
'default' => array(
|
5682 |
'value' => '',
|
5683 |
),
|
@@ -5699,18 +7488,57 @@ class AMP_Allowed_Tags_Generated {
|
|
5699 |
),
|
5700 |
),
|
5701 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
5702 |
'mandatory_parent' => 'amp-video',
|
5703 |
'spec_name' => 'amp-video > track[kind=subtitles]',
|
5704 |
),
|
5705 |
|
5706 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5707 |
),
|
5708 |
'tref' => array(
|
5709 |
array(
|
5710 |
'attr_spec_list' => array(
|
5711 |
'alignment-baseline' => array(),
|
5712 |
'baseline-shift' => array(),
|
5713 |
-
'class' => array(),
|
5714 |
'clip' => array(),
|
5715 |
'clip-path' => array(),
|
5716 |
'clip-rule' => array(),
|
@@ -5764,32 +7592,47 @@ class AMP_Allowed_Tags_Generated {
|
|
5764 |
'stroke-miterlimit' => array(),
|
5765 |
'stroke-opacity' => array(),
|
5766 |
'stroke-width' => array(),
|
|
|
|
|
|
|
5767 |
'systemlanguage' => array(),
|
5768 |
'text-anchor' => array(),
|
5769 |
'text-decoration' => array(),
|
5770 |
'text-rendering' => array(),
|
5771 |
'unicode-bidi' => array(),
|
|
|
5772 |
'visibility' => array(),
|
5773 |
'word-spacing' => array(),
|
5774 |
'writing-mode' => array(),
|
5775 |
'xlink:actuate' => array(),
|
5776 |
'xlink:arcrole' => array(),
|
5777 |
'xlink:href' => array(
|
5778 |
-
'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5779 |
),
|
5780 |
'xlink:role' => array(),
|
5781 |
'xlink:show' => array(),
|
5782 |
'xlink:title' => array(),
|
5783 |
'xlink:type' => array(),
|
5784 |
-
'xml:base' => array(),
|
5785 |
'xml:lang' => array(),
|
5786 |
'xml:space' => array(),
|
5787 |
'xmlns' => array(),
|
5788 |
'xmlns:xlink' => array(),
|
5789 |
),
|
5790 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
5791 |
'mandatory_ancestor' => 'svg',
|
5792 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
5793 |
),
|
5794 |
|
5795 |
),
|
@@ -5799,7 +7642,6 @@ class AMP_Allowed_Tags_Generated {
|
|
5799 |
'attr_spec_list' => array(
|
5800 |
'alignment-baseline' => array(),
|
5801 |
'baseline-shift' => array(),
|
5802 |
-
'class' => array(),
|
5803 |
'clip' => array(),
|
5804 |
'clip-path' => array(),
|
5805 |
'clip-rule' => array(),
|
@@ -5857,17 +7699,20 @@ class AMP_Allowed_Tags_Generated {
|
|
5857 |
'stroke-miterlimit' => array(),
|
5858 |
'stroke-opacity' => array(),
|
5859 |
'stroke-width' => array(),
|
|
|
|
|
|
|
5860 |
'systemlanguage' => array(),
|
5861 |
'text-anchor' => array(),
|
5862 |
'text-decoration' => array(),
|
5863 |
'text-rendering' => array(),
|
5864 |
'textlength' => array(),
|
5865 |
'unicode-bidi' => array(),
|
|
|
5866 |
'visibility' => array(),
|
5867 |
'word-spacing' => array(),
|
5868 |
'writing-mode' => array(),
|
5869 |
'x' => array(),
|
5870 |
-
'xml:base' => array(),
|
5871 |
'xml:lang' => array(),
|
5872 |
'xml:space' => array(),
|
5873 |
'xmlns' => array(),
|
@@ -5875,8 +7720,12 @@ class AMP_Allowed_Tags_Generated {
|
|
5875 |
'y' => array(),
|
5876 |
),
|
5877 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
5878 |
'mandatory_ancestor' => 'svg',
|
5879 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
5880 |
),
|
5881 |
|
5882 |
),
|
@@ -5911,7 +7760,6 @@ class AMP_Allowed_Tags_Generated {
|
|
5911 |
'attr_spec_list' => array(
|
5912 |
'alignment-baseline' => array(),
|
5913 |
'baseline-shift' => array(),
|
5914 |
-
'class' => array(),
|
5915 |
'clip' => array(),
|
5916 |
'clip-path' => array(),
|
5917 |
'clip-rule' => array(),
|
@@ -5966,12 +7814,16 @@ class AMP_Allowed_Tags_Generated {
|
|
5966 |
'stroke-miterlimit' => array(),
|
5967 |
'stroke-opacity' => array(),
|
5968 |
'stroke-width' => array(),
|
|
|
|
|
|
|
5969 |
'systemlanguage' => array(),
|
5970 |
'text-anchor' => array(),
|
5971 |
'text-decoration' => array(),
|
5972 |
'text-rendering' => array(),
|
5973 |
'transform' => array(),
|
5974 |
'unicode-bidi' => array(),
|
|
|
5975 |
'visibility' => array(),
|
5976 |
'width' => array(),
|
5977 |
'word-spacing' => array(),
|
@@ -5980,13 +7832,20 @@ class AMP_Allowed_Tags_Generated {
|
|
5980 |
'xlink:actuate' => array(),
|
5981 |
'xlink:arcrole' => array(),
|
5982 |
'xlink:href' => array(
|
5983 |
-
'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5984 |
),
|
5985 |
'xlink:role' => array(),
|
5986 |
'xlink:show' => array(),
|
5987 |
'xlink:title' => array(),
|
5988 |
'xlink:type' => array(),
|
5989 |
-
'xml:base' => array(),
|
5990 |
'xml:lang' => array(),
|
5991 |
'xml:space' => array(),
|
5992 |
'xmlns' => array(),
|
@@ -5994,8 +7853,12 @@ class AMP_Allowed_Tags_Generated {
|
|
5994 |
'y' => array(),
|
5995 |
),
|
5996 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
5997 |
'mandatory_ancestor' => 'svg',
|
5998 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
5999 |
),
|
6000 |
|
6001 |
),
|
@@ -6015,6 +7878,7 @@ class AMP_Allowed_Tags_Generated {
|
|
6015 |
'height' => array(),
|
6016 |
'loop' => array(),
|
6017 |
'muted' => array(),
|
|
|
6018 |
'poster' => array(),
|
6019 |
'preload' => array(),
|
6020 |
'src' => array(
|
@@ -6033,7 +7897,7 @@ class AMP_Allowed_Tags_Generated {
|
|
6033 |
),
|
6034 |
'mandatory_ancestor' => 'noscript',
|
6035 |
'mandatory_ancestor_suggested_alternative' => 'amp-video',
|
6036 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/amp-video
|
6037 |
),
|
6038 |
|
6039 |
),
|
@@ -6043,9 +7907,11 @@ class AMP_Allowed_Tags_Generated {
|
|
6043 |
'attr_spec_list' => array(
|
6044 |
'externalresourcesrequired' => array(),
|
6045 |
'preserveaspectratio' => array(),
|
|
|
|
|
|
|
6046 |
'viewbox' => array(),
|
6047 |
'viewtarget' => array(),
|
6048 |
-
'xml:base' => array(),
|
6049 |
'xml:lang' => array(),
|
6050 |
'xml:space' => array(),
|
6051 |
'xmlns' => array(),
|
@@ -6053,8 +7919,12 @@ class AMP_Allowed_Tags_Generated {
|
|
6053 |
'zoomandpan' => array(),
|
6054 |
),
|
6055 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
6056 |
'mandatory_ancestor' => 'svg',
|
6057 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
6058 |
),
|
6059 |
|
6060 |
),
|
@@ -6065,17 +7935,23 @@ class AMP_Allowed_Tags_Generated {
|
|
6065 |
'g1' => array(),
|
6066 |
'g2' => array(),
|
6067 |
'k' => array(),
|
|
|
|
|
|
|
6068 |
'u1' => array(),
|
6069 |
'u2' => array(),
|
6070 |
-
'xml:base' => array(),
|
6071 |
'xml:lang' => array(),
|
6072 |
'xml:space' => array(),
|
6073 |
'xmlns' => array(),
|
6074 |
'xmlns:xlink' => array(),
|
6075 |
),
|
6076 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
6077 |
'mandatory_ancestor' => 'svg',
|
6078 |
-
'spec_url' => 'https://www.ampproject.org/docs/reference/spec
|
6079 |
),
|
6080 |
|
6081 |
),
|
@@ -6101,6 +7977,8 @@ class AMP_Allowed_Tags_Generated {
|
|
6101 |
);
|
6102 |
|
6103 |
private static $layout_allowed_attrs = array(
|
|
|
|
|
6104 |
'height' => array(),
|
6105 |
'heights' => array(),
|
6106 |
'layout' => array(),
|
@@ -6111,6 +7989,45 @@ class AMP_Allowed_Tags_Generated {
|
|
6111 |
|
6112 |
|
6113 |
private static $globally_allowed_attrs = array(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6114 |
'accesskey' => array(),
|
6115 |
'amp-access' => array(),
|
6116 |
'amp-access-behavior' => array(),
|
@@ -6129,6 +8046,7 @@ class AMP_Allowed_Tags_Generated {
|
|
6129 |
'aria-busy' => array(),
|
6130 |
'aria-checked' => array(),
|
6131 |
'aria-controls' => array(),
|
|
|
6132 |
'aria-describedby' => array(),
|
6133 |
'aria-disabled' => array(),
|
6134 |
'aria-dropeffect' => array(),
|
@@ -6161,15 +8079,21 @@ class AMP_Allowed_Tags_Generated {
|
|
6161 |
'class' => array(
|
6162 |
'blacklisted_value_regex' => '(^|\\w)i-amphtml-',
|
6163 |
),
|
|
|
|
|
6164 |
'dir' => array(),
|
6165 |
'draggable' => array(),
|
6166 |
'fallback' => array(
|
6167 |
'value' => '',
|
6168 |
),
|
|
|
|
|
|
|
6169 |
'i-amp-access-id' => array(),
|
6170 |
'id' => array(
|
6171 |
-
'blacklisted_value_regex' => '
|
6172 |
),
|
|
|
6173 |
'itemid' => array(),
|
6174 |
'itemprop' => array(),
|
6175 |
'itemref' => array(),
|
@@ -6182,14 +8106,23 @@ class AMP_Allowed_Tags_Generated {
|
|
6182 |
'placeholder' => array(
|
6183 |
'value' => '',
|
6184 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6185 |
'role' => array(),
|
6186 |
'tabindex' => array(),
|
6187 |
'title' => array(),
|
6188 |
'translate' => array(),
|
|
|
6189 |
'validation-for' => array(),
|
6190 |
'visible-when-invalid' => array(
|
6191 |
'value_regex' => '(badinput|customerror|patternmismatch|rangeoverflow|rangeunderflow|stepmismatch|toolong|typemismatch|valuemissing)',
|
6192 |
),
|
|
|
6193 |
|
6194 |
);
|
6195 |
|
1 |
<?php
|
2 |
/**
|
3 |
+
* Generated by amphtml-update.py - do not edit.
|
4 |
*
|
5 |
* This is a list of HTML tags and attributes that are allowed by the
|
6 |
* AMP specification. Note that tag names have been converted to lowercase.
|
11 |
*/
|
12 |
class AMP_Allowed_Tags_Generated {
|
13 |
|
14 |
+
private static $spec_file_revision = 527;
|
15 |
+
private static $minimum_validator_revision_required = 265;
|
16 |
|
17 |
private static $allowed_tags = array(
|
18 |
'a' => array(
|
19 |
array(
|
20 |
'attr_spec_list' => array(
|
21 |
+
'[href]' => array(),
|
22 |
'border' => array(),
|
23 |
'download' => array(),
|
24 |
'href' => array(
|
25 |
'blacklisted_value_regex' => '__amp_source_origin',
|
26 |
+
'allow_empty' => true,
|
27 |
'allow_relative' => true,
|
28 |
'allowed_protocol' => array(
|
29 |
'bbmi',
|
61 |
),
|
62 |
),
|
63 |
'tag_spec' => array(
|
64 |
+
'html_format' => array(
|
65 |
+
'amp',
|
66 |
+
'amp4ads',
|
67 |
+
),
|
68 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#links',
|
69 |
),
|
70 |
|
71 |
),
|
95 |
|
96 |
),
|
97 |
),
|
98 |
+
'amp-3q-player' => array(
|
99 |
+
array(
|
100 |
+
'attr_spec_list' => array(
|
101 |
+
'autoplay' => array(
|
102 |
+
'value' => '',
|
103 |
+
),
|
104 |
+
'data-id' => array(
|
105 |
+
'mandatory' => true,
|
106 |
+
),
|
107 |
+
'media' => array(),
|
108 |
+
'noloading' => array(
|
109 |
+
'value' => '',
|
110 |
+
),
|
111 |
+
),
|
112 |
+
'tag_spec' => array(
|
113 |
+
'html_format' => array(
|
114 |
+
'amp',
|
115 |
+
),
|
116 |
+
),
|
117 |
+
|
118 |
+
),
|
119 |
+
),
|
120 |
'amp-accordion' => array(
|
121 |
array(
|
122 |
'attr_spec_list' => array(
|
125 |
),
|
126 |
),
|
127 |
'tag_spec' => array(
|
128 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-accordion',
|
129 |
+
),
|
130 |
+
|
131 |
+
),
|
132 |
+
),
|
133 |
+
'amp-ad' => array(
|
134 |
+
array(
|
135 |
+
'attr_spec_list' => array(
|
136 |
+
'alt' => array(),
|
137 |
+
'json' => array(),
|
138 |
+
'media' => array(),
|
139 |
+
'noloading' => array(
|
140 |
+
'value' => '',
|
141 |
+
),
|
142 |
+
'src' => array(
|
143 |
+
'blacklisted_value_regex' => '__amp_source_origin',
|
144 |
+
'allow_relative' => true,
|
145 |
+
'allowed_protocol' => array(
|
146 |
+
'https',
|
147 |
+
),
|
148 |
+
),
|
149 |
+
'type' => array(
|
150 |
+
'mandatory' => true,
|
151 |
+
),
|
152 |
+
),
|
153 |
+
'tag_spec' => array(
|
154 |
+
'disallowed_ancestor' => array(
|
155 |
+
'amp-app-banner',
|
156 |
),
|
157 |
'html_format' => array(
|
158 |
'amp',
|
|
|
159 |
),
|
160 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad',
|
161 |
),
|
162 |
|
163 |
),
|
|
|
|
|
164 |
array(
|
165 |
'attr_spec_list' => array(
|
166 |
'alt' => array(),
|
167 |
+
'data-multi-size' => array(
|
168 |
+
'mandatory' => true,
|
169 |
+
),
|
170 |
'json' => array(),
|
171 |
'media' => array(),
|
172 |
'noloading' => array(
|
186 |
'tag_spec' => array(
|
187 |
'disallowed_ancestor' => array(
|
188 |
'amp-app-banner',
|
189 |
+
'amp-carousel',
|
190 |
+
'amp-fx-flying-carpet',
|
191 |
+
'amp-lightbox',
|
192 |
+
'amp-sticky-ad',
|
193 |
),
|
194 |
'html_format' => array(
|
195 |
'amp',
|
196 |
),
|
197 |
+
'spec_name' => 'amp-ad with data-multi-size attribute',
|
198 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad',
|
199 |
+
),
|
200 |
+
|
201 |
+
),
|
202 |
+
),
|
203 |
+
'amp-ad-exit' => array(
|
204 |
+
array(
|
205 |
+
'attr_spec_list' => array(
|
206 |
+
'id' => array(
|
207 |
+
'mandatory' => true,
|
208 |
+
),
|
209 |
+
'media' => array(),
|
210 |
+
'noloading' => array(
|
211 |
+
'value' => '',
|
212 |
+
),
|
213 |
+
),
|
214 |
+
'tag_spec' => array(
|
215 |
+
'html_format' => array(
|
216 |
+
'amp4ads',
|
217 |
+
),
|
218 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad-exit',
|
219 |
),
|
220 |
|
221 |
),
|
225 |
'attr_spec_list' => array(
|
226 |
'config' => array(
|
227 |
'blacklisted_value_regex' => '__amp_source_origin',
|
228 |
+
'allow_empty' => true,
|
229 |
'allow_relative' => true,
|
230 |
'allowed_protocol' => array(
|
231 |
'https',
|
234 |
'type' => array(),
|
235 |
),
|
236 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
237 |
'html_format' => array(
|
238 |
'amp',
|
239 |
'amp4ads',
|
240 |
),
|
241 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-analytics',
|
242 |
),
|
243 |
|
244 |
),
|
248 |
'attr_spec_list' => array(
|
249 |
'alt' => array(),
|
250 |
'attribution' => array(),
|
|
|
|
|
|
|
251 |
'controls' => array(),
|
252 |
'media' => array(),
|
253 |
'noloading' => array(
|
268 |
),
|
269 |
),
|
270 |
'tag_spec' => array(
|
271 |
+
'html_format' => array(
|
272 |
+
'amp',
|
273 |
+
'amp4ads',
|
274 |
),
|
275 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-anim',
|
276 |
+
),
|
277 |
+
|
278 |
+
),
|
279 |
+
),
|
280 |
+
'amp-animation' => array(
|
281 |
+
array(
|
282 |
+
'attr_spec_list' => array(
|
283 |
+
'media' => array(),
|
284 |
+
'noloading' => array(
|
285 |
+
'value' => '',
|
286 |
+
),
|
287 |
+
'trigger' => array(
|
288 |
+
'value' => 'visibility',
|
289 |
),
|
290 |
+
),
|
291 |
+
'tag_spec' => array(
|
292 |
'html_format' => array(
|
293 |
'amp',
|
294 |
'amp4ads',
|
295 |
),
|
|
|
296 |
),
|
297 |
|
298 |
),
|
312 |
),
|
313 |
),
|
314 |
'tag_spec' => array(
|
|
|
|
|
|
|
315 |
'html_format' => array(
|
316 |
'amp',
|
317 |
),
|
318 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-apester-media',
|
319 |
),
|
320 |
|
321 |
),
|
332 |
),
|
333 |
),
|
334 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
335 |
'html_format' => array(
|
336 |
'amp',
|
337 |
),
|
338 |
'mandatory_parent' => 'body',
|
339 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-app-banner',
|
|
|
340 |
'unique' => true,
|
341 |
),
|
342 |
|
345 |
'amp-audio' => array(
|
346 |
array(
|
347 |
'attr_spec_list' => array(
|
348 |
+
'album' => array(),
|
349 |
+
'artist' => array(),
|
350 |
+
'artwork' => array(),
|
351 |
'autoplay' => array(
|
352 |
+
'value' => '',
|
353 |
),
|
354 |
'controls' => array(),
|
355 |
+
'controlslist' => array(),
|
356 |
'loop' => array(
|
357 |
'value' => '',
|
358 |
),
|
372 |
),
|
373 |
),
|
374 |
'tag_spec' => array(
|
|
|
|
|
|
|
375 |
'disallowed_ancestor' => array(
|
376 |
+
'amp-story',
|
377 |
),
|
378 |
'html_format' => array(
|
379 |
'amp',
|
380 |
),
|
381 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-audio',
|
382 |
),
|
383 |
|
384 |
),
|
385 |
array(
|
386 |
'attr_spec_list' => array(
|
387 |
+
'album' => array(),
|
388 |
+
'artist' => array(),
|
389 |
+
'artwork' => array(),
|
390 |
+
'autoplay' => array(
|
391 |
+
'mandatory' => true,
|
392 |
+
'value' => '',
|
393 |
+
),
|
394 |
'controls' => array(),
|
395 |
+
'controlslist' => array(),
|
396 |
'loop' => array(
|
397 |
'value' => '',
|
398 |
),
|
412 |
),
|
413 |
),
|
414 |
'tag_spec' => array(
|
415 |
+
'html_format' => array(
|
416 |
+
'amp',
|
417 |
),
|
418 |
+
'mandatory_ancestor' => 'amp-story',
|
419 |
+
'spec_name' => 'amp-story >> amp-audio',
|
420 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-audio',
|
421 |
+
),
|
422 |
+
|
423 |
+
),
|
424 |
+
array(
|
425 |
+
'attr_spec_list' => array(
|
426 |
+
'album' => array(),
|
427 |
+
'artist' => array(),
|
428 |
+
'artwork' => array(),
|
429 |
+
'controls' => array(),
|
430 |
+
'controlslist' => array(),
|
431 |
+
'loop' => array(
|
432 |
+
'value' => '',
|
433 |
+
),
|
434 |
+
'media' => array(),
|
435 |
+
'muted' => array(
|
436 |
+
'value' => '',
|
437 |
+
),
|
438 |
+
'noloading' => array(
|
439 |
+
'value' => '',
|
440 |
+
),
|
441 |
+
'src' => array(
|
442 |
+
'blacklisted_value_regex' => '__amp_source_origin',
|
443 |
+
'allow_relative' => true,
|
444 |
+
'allowed_protocol' => array(
|
445 |
+
'https',
|
446 |
+
),
|
447 |
),
|
448 |
+
),
|
449 |
+
'tag_spec' => array(
|
450 |
'html_format' => array(
|
451 |
'amp4ads',
|
452 |
),
|
453 |
'spec_name' => 'amp-audio (a4a)',
|
454 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-audio',
|
455 |
),
|
456 |
|
457 |
),
|
471 |
'html_format' => array(
|
472 |
'amp',
|
473 |
),
|
474 |
+
'mandatory_parent' => 'body',
|
475 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-auto-ads',
|
476 |
),
|
477 |
|
478 |
),
|
480 |
'amp-brid-player' => array(
|
481 |
array(
|
482 |
'attr_spec_list' => array(
|
483 |
+
'autoplay' => array(),
|
484 |
+
'data-outstream' => array(
|
485 |
+
'value_regex' => '[0-9]+',
|
486 |
+
),
|
487 |
'data-partner' => array(
|
488 |
'mandatory' => true,
|
489 |
'value_regex' => '[0-9]+',
|
504 |
),
|
505 |
),
|
506 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
507 |
'html_format' => array(
|
508 |
'amp',
|
|
|
509 |
),
|
510 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-brid-player',
|
511 |
),
|
512 |
|
513 |
),
|
515 |
'amp-brightcove' => array(
|
516 |
array(
|
517 |
'attr_spec_list' => array(
|
518 |
+
'[data-account]' => array(),
|
519 |
+
'[data-embed]' => array(),
|
520 |
+
'[data-player-id]' => array(),
|
521 |
+
'[data-player]' => array(),
|
522 |
+
'[data-playlist-id]' => array(),
|
523 |
+
'[data-video-id]' => array(),
|
524 |
'data-account' => array(
|
525 |
'mandatory' => true,
|
526 |
),
|
|
|
|
|
|
|
|
|
527 |
'media' => array(),
|
528 |
'noloading' => array(
|
529 |
'value' => '',
|
530 |
),
|
531 |
),
|
532 |
'tag_spec' => array(
|
533 |
+
'html_format' => array(
|
534 |
+
'amp',
|
535 |
),
|
536 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-brightcove',
|
537 |
+
),
|
538 |
+
|
539 |
+
),
|
540 |
+
),
|
541 |
+
'amp-call-tracking' => array(
|
542 |
+
array(
|
543 |
+
'attr_spec_list' => array(
|
544 |
+
'config' => array(
|
545 |
+
'blacklisted_value_regex' => '__amp_source_origin',
|
546 |
+
'mandatory' => true,
|
547 |
+
'allow_relative' => false,
|
548 |
+
'allowed_protocol' => array(
|
549 |
+
'https',
|
550 |
+
),
|
551 |
+
),
|
552 |
+
'media' => array(),
|
553 |
+
'noloading' => array(
|
554 |
+
'value' => '',
|
555 |
),
|
556 |
+
),
|
557 |
+
'tag_spec' => array(
|
558 |
'html_format' => array(
|
559 |
'amp',
|
|
|
560 |
),
|
561 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-call-tracking',
|
562 |
),
|
563 |
|
564 |
),
|
566 |
'amp-carousel' => array(
|
567 |
array(
|
568 |
'attr_spec_list' => array(
|
569 |
+
'[slide]' => array(),
|
570 |
'arrows' => array(
|
571 |
'value' => '',
|
572 |
),
|
592 |
),
|
593 |
),
|
594 |
'tag_spec' => array(
|
595 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-carousel',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
596 |
),
|
597 |
|
598 |
),
|
600 |
'amp-dailymotion' => array(
|
601 |
array(
|
602 |
'attr_spec_list' => array(
|
603 |
+
'autoplay' => array(),
|
604 |
'data-endscreen-enable' => array(
|
605 |
'value_regex' => 'true|false',
|
606 |
),
|
632 |
),
|
633 |
),
|
634 |
'tag_spec' => array(
|
635 |
+
'html_format' => array(
|
636 |
+
'amp',
|
637 |
+
),
|
638 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-dailymotion',
|
639 |
+
),
|
640 |
+
|
641 |
+
),
|
642 |
+
),
|
643 |
+
'amp-embed' => array(
|
644 |
+
array(
|
645 |
+
'attr_spec_list' => array(
|
646 |
+
'alt' => array(),
|
647 |
+
'json' => array(),
|
648 |
+
'media' => array(),
|
649 |
+
'noloading' => array(
|
650 |
+
'value' => '',
|
651 |
+
),
|
652 |
+
'src' => array(
|
653 |
+
'blacklisted_value_regex' => '__amp_source_origin',
|
654 |
+
'allow_relative' => true,
|
655 |
+
'allowed_protocol' => array(
|
656 |
+
'https',
|
657 |
+
),
|
658 |
),
|
659 |
+
'type' => array(
|
660 |
+
'mandatory' => true,
|
661 |
+
),
|
662 |
+
),
|
663 |
+
'tag_spec' => array(
|
664 |
'disallowed_ancestor' => array(
|
665 |
+
'amp-app-banner',
|
666 |
),
|
667 |
'html_format' => array(
|
668 |
'amp',
|
|
|
669 |
),
|
670 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad',
|
671 |
),
|
672 |
|
673 |
),
|
|
|
|
|
674 |
array(
|
675 |
'attr_spec_list' => array(
|
676 |
'alt' => array(),
|
677 |
+
'data-multi-size' => array(
|
678 |
+
'mandatory' => true,
|
679 |
+
'value' => '',
|
680 |
+
),
|
681 |
'json' => array(),
|
682 |
'media' => array(),
|
683 |
'noloading' => array(
|
696 |
),
|
697 |
'tag_spec' => array(
|
698 |
'disallowed_ancestor' => array(
|
699 |
+
'amp-app-banner',
|
700 |
+
'amp-carousel',
|
701 |
+
'amp-fx-flying-carpet',
|
702 |
+
'amp-lightbox',
|
703 |
+
'amp-sticky-ad',
|
704 |
),
|
705 |
'html_format' => array(
|
706 |
'amp',
|
707 |
),
|
708 |
+
'spec_name' => 'amp-embed with data-multi-size attribute',
|
709 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad',
|
710 |
),
|
711 |
|
712 |
),
|
715 |
array(
|
716 |
'attr_spec_list' => array(),
|
717 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
718 |
'html_format' => array(
|
719 |
'amp',
|
720 |
),
|
721 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-experiment',
|
722 |
'unique' => true,
|
723 |
),
|
724 |
|
736 |
),
|
737 |
),
|
738 |
'tag_spec' => array(
|
739 |
+
'html_format' => array(
|
740 |
+
'amp',
|
741 |
),
|
742 |
+
),
|
743 |
+
|
744 |
+
),
|
745 |
+
),
|
746 |
+
'amp-facebook-comments' => array(
|
747 |
+
array(
|
748 |
+
'attr_spec_list' => array(
|
749 |
+
'data-href' => array(
|
750 |
+
'mandatory' => true,
|
751 |
+
),
|
752 |
+
'media' => array(),
|
753 |
+
'noloading' => array(
|
754 |
+
'value' => '',
|
755 |
),
|
756 |
+
),
|
757 |
+
'tag_spec' => array(
|
758 |
'html_format' => array(
|
759 |
'amp',
|
|
|
760 |
),
|
|
|
761 |
),
|
762 |
|
763 |
),
|
764 |
),
|
765 |
+
'amp-facebook-like' => array(
|
766 |
array(
|
767 |
'attr_spec_list' => array(
|
768 |
+
'data-href' => array(
|
769 |
+
'mandatory' => true,
|
770 |
+
'allow_relative' => false,
|
771 |
+
'allowed_protocol' => array(
|
772 |
+
'http',
|
773 |
+
'https',
|
774 |
+
),
|
775 |
+
),
|
776 |
'media' => array(),
|
|
|
777 |
'noloading' => array(
|
778 |
'value' => '',
|
779 |
),
|
780 |
),
|
781 |
'tag_spec' => array(
|
|
|
|
|
|
|
782 |
'html_format' => array(
|
783 |
'amp',
|
|
|
784 |
),
|
|
|
785 |
),
|
786 |
|
787 |
),
|
788 |
),
|
789 |
+
'amp-fit-text' => array(
|
790 |
+
array(
|
791 |
+
'attr_spec_list' => array(
|
792 |
+
'max-font-size' => array(),
|
793 |
+
'media' => array(),
|
794 |
+
'min-font-size' => array(),
|
795 |
+
'noloading' => array(
|
796 |
+
'value' => '',
|
797 |
+
),
|
798 |
+
),
|
799 |
+
'tag_spec' => array(),
|
800 |
+
|
801 |
+
),
|
802 |
+
),
|
803 |
'amp-font' => array(
|
804 |
array(
|
805 |
'attr_spec_list' => array(
|
822 |
),
|
823 |
),
|
824 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
825 |
'html_format' => array(
|
826 |
'amp',
|
827 |
'amp4ads',
|
828 |
),
|
|
|
829 |
),
|
830 |
|
831 |
),
|
842 |
),
|
843 |
),
|
844 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
845 |
'html_format' => array(
|
846 |
'amp',
|
|
|
847 |
),
|
|
|
848 |
),
|
849 |
|
850 |
),
|
864 |
),
|
865 |
),
|
866 |
'tag_spec' => array(
|
867 |
+
'html_format' => array(
|
868 |
+
'amp',
|
869 |
),
|
870 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-gfycat',
|
871 |
+
),
|
872 |
+
|
873 |
+
),
|
874 |
+
),
|
875 |
+
'amp-gist' => array(
|
876 |
+
array(
|
877 |
+
'attr_spec_list' => array(
|
878 |
+
'data-gistid' => array(
|
879 |
+
'mandatory' => true,
|
880 |
+
),
|
881 |
+
'media' => array(),
|
882 |
+
'noloading' => array(
|
883 |
+
'value' => '',
|
884 |
),
|
885 |
+
),
|
886 |
+
'tag_spec' => array(
|
887 |
'html_format' => array(
|
888 |
'amp',
|
889 |
+
),
|
890 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-gist',
|
891 |
+
),
|
892 |
+
|
893 |
+
),
|
894 |
+
),
|
895 |
+
'amp-gwd-animation' => array(
|
896 |
+
array(
|
897 |
+
'attr_spec_list' => array(
|
898 |
+
'media' => array(),
|
899 |
+
'noloading' => array(
|
900 |
+
'value' => '',
|
901 |
+
),
|
902 |
+
'timeline-event-prefix' => array(
|
903 |
+
'value' => '',
|
904 |
+
),
|
905 |
+
),
|
906 |
+
'tag_spec' => array(
|
907 |
+
'html_format' => array(
|
908 |
'amp4ads',
|
909 |
),
|
|
|
910 |
),
|
911 |
|
912 |
),
|
923 |
),
|
924 |
),
|
925 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
926 |
'html_format' => array(
|
927 |
'amp',
|
|
|
928 |
),
|
929 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-hulu',
|
930 |
),
|
931 |
|
932 |
),
|
934 |
'amp-iframe' => array(
|
935 |
array(
|
936 |
'attr_spec_list' => array(
|
937 |
+
'[src]' => array(),
|
938 |
+
'allow' => array(
|
939 |
+
'value_regex' => 'geolocation|fullscreen|payment|transparency',
|
940 |
+
),
|
941 |
'allowfullscreen' => array(
|
942 |
'value' => '',
|
943 |
),
|
944 |
+
'allowpaymentrequest' => array(
|
945 |
+
'value' => '',
|
946 |
+
),
|
947 |
'allowtransparency' => array(
|
948 |
'value' => '',
|
949 |
),
|
973 |
'srcdoc' => array(),
|
974 |
),
|
975 |
'tag_spec' => array(
|
976 |
+
'html_format' => array(
|
977 |
+
'amp',
|
978 |
),
|
979 |
+
),
|
980 |
+
|
981 |
+
),
|
982 |
+
),
|
983 |
+
'amp-ima-video' => array(
|
984 |
+
array(
|
985 |
+
'attr_spec_list' => array(
|
986 |
+
'data-src' => array(
|
987 |
+
'blacklisted_value_regex' => '__amp_source_origin',
|
988 |
+
'allow_relative' => true,
|
989 |
+
'allowed_protocol' => array(
|
990 |
+
'https',
|
991 |
+
),
|
992 |
+
),
|
993 |
+
'data-tag' => array(
|
994 |
+
'mandatory' => true,
|
995 |
+
'allow_relative' => true,
|
996 |
+
'allowed_protocol' => array(
|
997 |
+
'https',
|
998 |
+
),
|
999 |
),
|
1000 |
+
'media' => array(),
|
1001 |
+
'noloading' => array(
|
1002 |
+
'value' => '',
|
1003 |
+
),
|
1004 |
+
),
|
1005 |
+
'tag_spec' => array(
|
1006 |
'html_format' => array(
|
1007 |
'amp',
|
1008 |
),
|
1009 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ima-video',
|
1010 |
),
|
1011 |
|
1012 |
),
|
1021 |
),
|
1022 |
),
|
1023 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
1024 |
'html_format' => array(
|
1025 |
'amp',
|
|
|
1026 |
),
|
|
|
1027 |
),
|
1028 |
|
1029 |
),
|
1031 |
'amp-img' => array(
|
1032 |
array(
|
1033 |
'attr_spec_list' => array(
|
1034 |
+
'[alt]' => array(),
|
1035 |
+
'[attribution]' => array(),
|
1036 |
+
'[src]' => array(),
|
1037 |
+
'[srcset]' => array(),
|
1038 |
'alt' => array(),
|
1039 |
'attribution' => array(),
|
1040 |
'media' => array(),
|
1061 |
'amp',
|
1062 |
'amp4ads',
|
1063 |
),
|
1064 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-img',
|
1065 |
+
),
|
1066 |
+
|
1067 |
+
),
|
1068 |
+
),
|
1069 |
+
'amp-imgur' => array(
|
1070 |
+
array(
|
1071 |
+
'attr_spec_list' => array(
|
1072 |
+
'data-imgur-id' => array(
|
1073 |
+
'mandatory' => true,
|
1074 |
+
),
|
1075 |
+
'media' => array(),
|
1076 |
+
'noloading' => array(
|
1077 |
+
'value' => '',
|
1078 |
+
),
|
1079 |
+
),
|
1080 |
+
'tag_spec' => array(
|
1081 |
+
'html_format' => array(
|
1082 |
+
'amp',
|
1083 |
+
),
|
1084 |
),
|
1085 |
|
1086 |
),
|
1098 |
),
|
1099 |
),
|
1100 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
1101 |
'html_format' => array(
|
1102 |
'amp',
|
|
|
1103 |
),
|
|
|
1104 |
),
|
1105 |
|
1106 |
),
|
1108 |
'amp-install-serviceworker' => array(
|
1109 |
array(
|
1110 |
'attr_spec_list' => array(
|
1111 |
+
'data-iframe-src' => array(
|
1112 |
+
'blacklisted_value_regex' => '__amp_source_origin',
|
1113 |
+
'allow_relative' => true,
|
1114 |
+
'allowed_protocol' => array(
|
1115 |
+
'https',
|
1116 |
+
),
|
1117 |
+
),
|
1118 |
'src' => array(
|
1119 |
'blacklisted_value_regex' => '__amp_source_origin',
|
1120 |
'mandatory' => true,
|
1125 |
),
|
1126 |
),
|
1127 |
'tag_spec' => array(
|
1128 |
+
'html_format' => array(
|
1129 |
+
'amp',
|
1130 |
),
|
1131 |
+
),
|
1132 |
+
|
1133 |
+
),
|
1134 |
+
),
|
1135 |
+
'amp-izlesene' => array(
|
1136 |
+
array(
|
1137 |
+
'attr_spec_list' => array(
|
1138 |
+
'data-videoid' => array(
|
1139 |
+
'mandatory' => true,
|
1140 |
+
'value_regex' => '[0-9]+',
|
1141 |
+
),
|
1142 |
+
'media' => array(),
|
1143 |
+
'noloading' => array(
|
1144 |
+
'value' => '',
|
1145 |
),
|
1146 |
+
),
|
1147 |
+
'tag_spec' => array(
|
1148 |
'html_format' => array(
|
1149 |
'amp',
|
1150 |
),
|
|
|
1151 |
),
|
1152 |
|
1153 |
),
|
1167 |
),
|
1168 |
),
|
1169 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
1170 |
'html_format' => array(
|
1171 |
'amp',
|
|
|
1172 |
),
|
|
|
1173 |
),
|
1174 |
|
1175 |
),
|
1186 |
),
|
1187 |
),
|
1188 |
'tag_spec' => array(
|
1189 |
+
'html_format' => array(
|
1190 |
+
'amp',
|
1191 |
),
|
1192 |
+
),
|
1193 |
+
|
1194 |
+
),
|
1195 |
+
),
|
1196 |
+
'amp-layout' => array(
|
1197 |
+
array(
|
1198 |
+
'attr_spec_list' => array(
|
1199 |
+
'media' => array(),
|
1200 |
+
'noloading' => array(
|
1201 |
+
'value' => '',
|
1202 |
),
|
1203 |
+
),
|
1204 |
+
'tag_spec' => array(
|
1205 |
'html_format' => array(
|
1206 |
'amp',
|
1207 |
'amp4ads',
|
1208 |
),
|
1209 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-layout',
|
1210 |
),
|
1211 |
|
1212 |
),
|
1223 |
'scrollable' => array(),
|
1224 |
),
|
1225 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
1226 |
'html_format' => array(
|
1227 |
'amp',
|
|
|
1228 |
),
|
|
|
1229 |
),
|
1230 |
|
1231 |
),
|
1233 |
'amp-list' => array(
|
1234 |
array(
|
1235 |
'attr_spec_list' => array(
|
1236 |
+
'[src]' => array(),
|
1237 |
+
'[state]' => array(),
|
1238 |
'credentials' => array(),
|
1239 |
+
'items' => array(),
|
1240 |
+
'max-items' => array(),
|
1241 |
'media' => array(),
|
1242 |
'noloading' => array(
|
1243 |
'value' => '',
|
1244 |
),
|
1245 |
+
'single-item' => array(),
|
1246 |
'src' => array(
|
1247 |
'blacklisted_value_regex' => '__amp_source_origin',
|
1248 |
'mandatory' => true,
|
1254 |
'template' => array(),
|
1255 |
),
|
1256 |
'tag_spec' => array(
|
|
|
|
|
|
|
1257 |
'html_format' => array(
|
1258 |
'amp',
|
|
|
1259 |
),
|
|
|
1260 |
),
|
1261 |
|
1262 |
),
|
1279 |
),
|
1280 |
),
|
1281 |
'tag_spec' => array(
|
1282 |
+
'html_format' => array(
|
1283 |
+
'amp',
|
1284 |
+
),
|
1285 |
+
),
|
1286 |
+
|
1287 |
+
),
|
1288 |
+
),
|
1289 |
+
'amp-nexxtv-player' => array(
|
1290 |
+
array(
|
1291 |
+
'attr_spec_list' => array(
|
1292 |
+
'data-client' => array(
|
1293 |
+
'mandatory' => true,
|
1294 |
+
),
|
1295 |
+
'data-mediaid' => array(
|
1296 |
+
'mandatory' => true,
|
1297 |
+
'value_regex' => '[^=/?:]+',
|
1298 |
+
),
|
1299 |
+
'data-mode' => array(
|
1300 |
+
'value_regex' => 'api|static',
|
1301 |
+
),
|
1302 |
+
'data-origin' => array(
|
1303 |
+
'allow_empty' => true,
|
1304 |
+
'allowed_protocol' => array(
|
1305 |
+
'http',
|
1306 |
+
'https',
|
1307 |
+
),
|
1308 |
+
),
|
1309 |
+
'data-seek-to' => array(),
|
1310 |
+
'data-streamtype' => array(
|
1311 |
+
'value_regex' => 'album|audio|live|playlist|playlist-marked|video',
|
1312 |
+
),
|
1313 |
+
'media' => array(),
|
1314 |
+
'noloading' => array(
|
1315 |
+
'value' => '',
|
1316 |
),
|
1317 |
+
),
|
1318 |
+
'tag_spec' => array(
|
1319 |
'html_format' => array(
|
1320 |
'amp',
|
|
|
1321 |
),
|
|
|
1322 |
),
|
1323 |
|
1324 |
),
|
1329 |
'data-bcid' => array(
|
1330 |
'mandatory' => true,
|
1331 |
),
|
|
|
1332 |
'data-pid' => array(
|
1333 |
'mandatory' => true,
|
1334 |
),
|
|
|
1335 |
'media' => array(),
|
1336 |
'noloading' => array(
|
1337 |
'value' => '',
|
1338 |
),
|
1339 |
),
|
1340 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
1341 |
'html_format' => array(
|
1342 |
'amp',
|
|
|
1343 |
),
|
|
|
1344 |
),
|
1345 |
|
1346 |
),
|
1348 |
'amp-ooyala-player' => array(
|
1349 |
array(
|
1350 |
'attr_spec_list' => array(
|
|
|
1351 |
'data-embedcode' => array(
|
1352 |
'mandatory' => true,
|
1353 |
),
|
1357 |
'data-playerid' => array(
|
1358 |
'mandatory' => true,
|
1359 |
),
|
|
|
1360 |
'media' => array(),
|
1361 |
'noloading' => array(
|
1362 |
'value' => '',
|
1363 |
),
|
1364 |
),
|
1365 |
'tag_spec' => array(
|
|
|
|
|
|
|
1366 |
'html_format' => array(
|
1367 |
'amp',
|
|
|
1368 |
),
|
|
|
1369 |
),
|
1370 |
|
1371 |
),
|
1382 |
),
|
1383 |
),
|
1384 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
1385 |
'html_format' => array(
|
1386 |
'amp',
|
|
|
1387 |
),
|
1388 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-pinterest',
|
1389 |
),
|
1390 |
|
1391 |
),
|
1397 |
'noloading' => array(
|
1398 |
'value' => '',
|
1399 |
),
|
1400 |
+
'referrerpolicy' => array(
|
1401 |
+
'value' => 'no-referrer',
|
1402 |
+
),
|
1403 |
'src' => array(
|
1404 |
'blacklisted_value_regex' => '__amp_source_origin',
|
1405 |
'mandatory' => true,
|
1406 |
+
'allow_empty' => true,
|
1407 |
'allow_relative' => true,
|
1408 |
'allowed_protocol' => array(
|
1409 |
'https',
|
1411 |
),
|
1412 |
),
|
1413 |
'tag_spec' => array(
|
|
|
|
|
|
|
1414 |
'html_format' => array(
|
1415 |
'amp',
|
1416 |
'amp4ads',
|
1417 |
),
|
1418 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-pixel',
|
1419 |
),
|
1420 |
|
1421 |
),
|
1426 |
'data-comments' => array(
|
1427 |
'value_regex_casei' => '(false|true)',
|
1428 |
),
|
1429 |
+
'data-item' => array(),
|
1430 |
'data-item-info' => array(
|
1431 |
'value_regex_casei' => '(false|true)',
|
1432 |
),
|
1437 |
'noloading' => array(
|
1438 |
'value' => '',
|
1439 |
),
|
1440 |
+
'src' => array(),
|
|
|
|
|
1441 |
),
|
1442 |
'tag_spec' => array(
|
1443 |
+
'html_format' => array(
|
1444 |
+
'amp',
|
1445 |
+
),
|
1446 |
+
),
|
1447 |
+
|
1448 |
+
),
|
1449 |
+
),
|
1450 |
+
'amp-position-observer' => array(
|
1451 |
+
array(
|
1452 |
+
'attr_spec_list' => array(
|
1453 |
+
'intersection-ratios' => array(
|
1454 |
+
'value_regex' => '^([0]*?\\.\\d*$|1$|0$)|([0]*?\\.\\d*|1|0)\\s{1}([0]*?\\.\\d*$|1$|0$)',
|
1455 |
+
),
|
1456 |
+
'media' => array(),
|
1457 |
+
'noloading' => array(
|
1458 |
+
'value' => '',
|
1459 |
),
|
1460 |
+
'target' => array(),
|
1461 |
+
'viewport-margins' => array(
|
1462 |
+
'value_regex' => '^(\\d+$|\\d+px$|\\d+vh$)|((\\d+|\\d+px|\\d+vh)\\s{1}(\\d+$|\\d+px$|\\d+vh$))',
|
1463 |
+
),
|
1464 |
+
),
|
1465 |
+
'tag_spec' => array(
|
1466 |
'html_format' => array(
|
1467 |
'amp',
|
1468 |
'amp4ads',
|
1469 |
),
|
|
|
1470 |
),
|
1471 |
|
1472 |
),
|
1484 |
),
|
1485 |
),
|
1486 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
1487 |
'html_format' => array(
|
1488 |
'amp',
|
|
|
1489 |
),
|
|
|
1490 |
),
|
1491 |
|
1492 |
),
|
1513 |
),
|
1514 |
),
|
1515 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
1516 |
'html_format' => array(
|
1517 |
'amp',
|
|
|
1518 |
),
|
|
|
1519 |
),
|
1520 |
|
1521 |
),
|
1523 |
'amp-selector' => array(
|
1524 |
array(
|
1525 |
'attr_spec_list' => array(
|
1526 |
+
'[selected]' => array(),
|
1527 |
'disabled' => array(
|
1528 |
'value' => '',
|
1529 |
),
|
1530 |
'form' => array(),
|
1531 |
+
'keyboard-select-mode' => array(
|
1532 |
+
'value_regex_casei' => 'focus|none|select',
|
1533 |
+
),
|
1534 |
'media' => array(),
|
1535 |
'multiple' => array(
|
1536 |
'value' => '',
|
1537 |
),
|
1538 |
+
'name' => array(
|
1539 |
+
'blacklisted_value_regex' => '(^|\\s)(__amp_\\s*|__count__|__definegetter__|__definesetter__|__lookupgetter__|__lookupsetter__|__nosuchmethod__|__parent__|__proto__|__amp_\\s*|\\$p|\\$proxy|acceptcharset|addeventlistener|appendchild|assignedslot|attachshadow|baseuri|checkvalidity|childelementcount|childnodes|classlist|classname|clientheight|clientleft|clienttop|clientwidth|comparedocumentposition|computedname|computedrole|contenteditable|createshadowroot|enqueaction|firstchild|firstelementchild|getanimations|getattribute|getattributens|getattributenode|getattributenodens|getboundingclientrect|getclientrects|getdestinationinsertionpoints|getelementsbyclassname|getelementsbytagname|getelementsbytagnamens|getrootnode|hasattribute|hasattributens|hasattributes|haschildnodes|haspointercapture|innerhtml|innertext|inputmode|insertadjacentelement|insertadjacenthtml|insertadjacenttext|iscontenteditable|isdefaultnamespace|isequalnode|issamenode|lastchild|lastelementchild|lookupnamespaceuri|namespaceuri|nextelementsibling|nextsibling|nodename|nodetype|nodevalue|offsetheight|offsetleft|offsetparent|offsettop|offsetwidth|outerhtml|outertext|ownerdocument|parentelement|parentnode|previouselementsibling|previoussibling|queryselector|queryselectorall|releasepointercapture|removeattribute|removeattributens|removeattributenode|removechild|removeeventlistener|replacechild|reportvalidity|requestpointerlock|scrollheight|scrollintoview|scrollintoviewifneeded|scrollleft|scrollwidth|setattribute|setattributens|setattributenode|setattributenodens|setpointercapture|shadowroot|stylemap|tabindex|tagname|textcontent|tostring|valueof|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)matchesselector|(webkit|moz|ms|o)requestfullscreen|(webkit|moz|ms|o)requestfullscreen)(\\s|$)',
|
1540 |
+
),
|
1541 |
'noloading' => array(
|
1542 |
'value' => '',
|
1543 |
),
|
1544 |
),
|
1545 |
'tag_spec' => array(
|
|
|
|
|
|
|
1546 |
'disallowed_ancestor' => array(
|
1547 |
'amp-selector',
|
|
|
1548 |
),
|
1549 |
'html_format' => array(
|
1550 |
'amp',
|
|
|
1551 |
),
|
|
|
1552 |
),
|
1553 |
|
1554 |
),
|
1565 |
),
|
1566 |
),
|
1567 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
1568 |
'html_format' => array(
|
1569 |
'amp',
|
1570 |
),
|
1571 |
'mandatory_parent' => 'body',
|
|
|
|
|
1572 |
),
|
1573 |
|
1574 |
),
|
1607 |
),
|
1608 |
),
|
1609 |
'tag_spec' => array(
|
|
|
|
|
|
|
1610 |
'html_format' => array(
|
1611 |
'amp',
|
1612 |
'amp4ads',
|
1613 |
),
|
|
|
1614 |
),
|
1615 |
|
1616 |
),
|
1621 |
'data-color' => array(
|
1622 |
'value_regex_casei' => '([0-9a-f]{3}){1,2}',
|
1623 |
),
|
1624 |
+
'data-playlistid' => array(
|
1625 |
+
'value_regex' => '[0-9]+',
|
1626 |
+
),
|
1627 |
'data-secret-token' => array(
|
1628 |
'value_regex' => '[a-za-z0-9_-]+',
|
1629 |
),
|
1630 |
'data-trackid' => array(
|
|
|
1631 |
'value_regex' => '[0-9]+',
|
1632 |
),
|
1633 |
'data-visual' => array(
|
1639 |
),
|
1640 |
),
|
1641 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
1642 |
'html_format' => array(
|
1643 |
'amp',
|
|
|
1644 |
),
|
|
|
1645 |
),
|
1646 |
|
1647 |
),
|
1676 |
),
|
1677 |
),
|
1678 |
'tag_spec' => array(
|
1679 |
+
'html_format' => array(
|
1680 |
+
'amp',
|
1681 |
),
|
1682 |
+
),
|
1683 |
+
|
1684 |
+
),
|
1685 |
+
),
|
1686 |
+
'amp-state' => array(
|
1687 |
+
array(
|
1688 |
+
'attr_spec_list' => array(
|
1689 |
+
'[src]' => array(),
|
1690 |
+
'credentials' => array(),
|
1691 |
+
'id' => array(
|
1692 |
+
'mandatory' => true,
|
1693 |
+
),
|
1694 |
+
'src' => array(
|
1695 |
+
'blacklisted_value_regex' => '__amp_source_origin',
|
1696 |
+
'allow_relative' => true,
|
1697 |
+
'allowed_protocol' => array(
|
1698 |
+
'https',
|
1699 |
+
),
|
1700 |
),
|
1701 |
+
),
|
1702 |
+
'tag_spec' => array(
|
1703 |
'html_format' => array(
|
1704 |
'amp',
|
|
|
1705 |
),
|
1706 |
+
'spec_name' => 'amp-state',
|
1707 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-bind',
|
1708 |
),
|
1709 |
|
1710 |
),
|
1718 |
),
|
1719 |
),
|
1720 |
'tag_spec' => array(
|
|
|
|
|
|
|
1721 |
'disallowed_ancestor' => array(
|
1722 |
'amp-app-banner',
|
|
|
1723 |
),
|
1724 |
'html_format' => array(
|
1725 |
'amp',
|
1726 |
),
|
|
|
1727 |
'unique' => true,
|
1728 |
),
|
1729 |
|
1730 |
),
|
1731 |
),
|
1732 |
+
'amp-story' => array(
|
1733 |
array(
|
1734 |
'attr_spec_list' => array(
|
1735 |
+
'background-audio' => array(
|
1736 |
+
'allowed_protocol' => array(
|
1737 |
+
'http',
|
1738 |
+
'https',
|
1739 |
+
),
|
1740 |
+
),
|
1741 |
+
'bookend-config-src' => array(
|
1742 |
+
'allowed_protocol' => array(
|
1743 |
+
'http',
|
1744 |
+
'https',
|
1745 |
+
),
|
1746 |
+
),
|
1747 |
+
'standalone' => array(
|
1748 |
+
'mandatory' => true,
|
1749 |
+
'value' => '',
|
1750 |
+
),
|
1751 |
+
),
|
1752 |
+
'tag_spec' => array(
|
1753 |
+
'html_format' => array(
|
1754 |
+
'amp',
|
1755 |
+
),
|
1756 |
+
'mandatory_parent' => 'body',
|
1757 |
+
),
|
1758 |
+
|
1759 |
+
),
|
1760 |
+
),
|
1761 |
+
'amp-story-grid-layer' => array(
|
1762 |
+
array(
|
1763 |
+
'attr_spec_list' => array(
|
1764 |
+
'template' => array(
|
1765 |
+
'mandatory' => true,
|
1766 |
+
'value_regex' => '(fill|horizontal|vertical|thirds)',
|
1767 |
+
),
|
1768 |
+
),
|
1769 |
+
'tag_spec' => array(
|
1770 |
+
'html_format' => array(
|
1771 |
+
'amp',
|
1772 |
+
),
|
1773 |
+
'mandatory_ancestor' => 'amp-story-page',
|
1774 |
+
),
|
1775 |
+
|
1776 |
+
),
|
1777 |
+
),
|
1778 |
+
'amp-story-page' => array(
|
1779 |
+
array(
|
1780 |
+
'attr_spec_list' => array(
|
1781 |
+
'auto-advance-after' => array(),
|
1782 |
+
'background-audio' => array(
|
1783 |
+
'allowed_protocol' => array(
|
1784 |
+
'http',
|
1785 |
+
'https',
|
1786 |
+
),
|
1787 |
+
),
|
1788 |
+
'id' => array(
|
1789 |
+
'mandatory' => true,
|
1790 |
+
),
|
1791 |
+
),
|
1792 |
+
'tag_spec' => array(
|
1793 |
+
'html_format' => array(
|
1794 |
+
'amp',
|
1795 |
+
),
|
1796 |
+
'mandatory_parent' => 'amp-story',
|
1797 |
+
),
|
1798 |
+
|
1799 |
+
),
|
1800 |
+
),
|
1801 |
+
'amp-timeago' => array(
|
1802 |
+
array(
|
1803 |
+
'attr_spec_list' => array(
|
1804 |
+
'cutoff' => array(
|
1805 |
+
'value_regex' => '\\d+',
|
1806 |
+
),
|
1807 |
+
'datetime' => array(
|
1808 |
+
'mandatory' => true,
|
1809 |
+
'value_regex' => '\\d{4}-[01]\\d-[0-3]\\dt[0-2]\\d:[0-5]\\d(:[0-5]\\d(\\.\\d+)?)?(z|[+-][0-1][0-9]:[0-5][0-9])',
|
1810 |
),
|
1811 |
+
'locale' => array(),
|
1812 |
'media' => array(),
|
1813 |
'noloading' => array(
|
1814 |
'value' => '',
|
1815 |
),
|
1816 |
),
|
1817 |
'tag_spec' => array(
|
1818 |
+
'html_format' => array(
|
1819 |
+
'amp',
|
1820 |
),
|
1821 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-timeago',
|
1822 |
+
),
|
1823 |
+
|
1824 |
+
),
|
1825 |
+
),
|
1826 |
+
'amp-twitter' => array(
|
1827 |
+
array(
|
1828 |
+
'attr_spec_list' => array(
|
1829 |
+
'data-tweetid' => array(
|
1830 |
+
'mandatory' => true,
|
1831 |
),
|
1832 |
+
'media' => array(),
|
1833 |
+
'noloading' => array(
|
1834 |
+
'value' => '',
|
1835 |
+
),
|
1836 |
+
),
|
1837 |
+
'tag_spec' => array(
|
1838 |
'html_format' => array(
|
1839 |
'amp',
|
|
|
1840 |
),
|
|
|
1841 |
),
|
1842 |
|
1843 |
),
|
1859 |
'https',
|
1860 |
),
|
1861 |
),
|
1862 |
+
'enctype' => array(
|
1863 |
+
'value' => 'application/x-www-form-urlencoded',
|
1864 |
+
),
|
1865 |
'media' => array(),
|
1866 |
'noloading' => array(
|
1867 |
'value' => '',
|
1868 |
),
|
1869 |
),
|
1870 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1871 |
'html_format' => array(
|
1872 |
'amp',
|
1873 |
),
|
|
|
1874 |
),
|
1875 |
|
1876 |
),
|
1878 |
'amp-video' => array(
|
1879 |
array(
|
1880 |
'attr_spec_list' => array(
|
1881 |
+
'[album]' => array(),
|
1882 |
+
'[alt]' => array(),
|
1883 |
+
'[artist]' => array(),
|
1884 |
+
'[artwork]' => array(),
|
1885 |
+
'[attribution]' => array(),
|
1886 |
+
'[controls]' => array(),
|
1887 |
+
'[controlslist]' => array(),
|
1888 |
+
'[loop]' => array(),
|
1889 |
+
'[poster]' => array(),
|
1890 |
+
'[preload]' => array(),
|
1891 |
+
'[src]' => array(),
|
1892 |
+
'[title]' => array(),
|
1893 |
+
'album' => array(),
|
1894 |
'alt' => array(),
|
1895 |
+
'artist' => array(),
|
1896 |
+
'artwork' => array(),
|
1897 |
'attribution' => array(),
|
1898 |
'autoplay' => array(
|
1899 |
'value' => '',
|
1901 |
'controls' => array(
|
1902 |
'value' => '',
|
1903 |
),
|
1904 |
+
'controlslist' => array(),
|
1905 |
+
'crossorigin' => array(),
|
1906 |
+
'disableremoteplayback' => array(
|
1907 |
+
'value' => '',
|
1908 |
+
),
|
1909 |
'loop' => array(
|
1910 |
'value' => '',
|
1911 |
),
|
1931 |
),
|
1932 |
'tag_spec' => array(
|
1933 |
'disallowed_ancestor' => array(
|
1934 |
+
'amp-story',
|
1935 |
+
),
|
1936 |
+
'html_format' => array(
|
1937 |
+
'amp',
|
1938 |
+
'amp4ads',
|
1939 |
+
),
|
1940 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-video',
|
1941 |
+
),
|
1942 |
+
|
1943 |
+
),
|
1944 |
+
array(
|
1945 |
+
'attr_spec_list' => array(
|
1946 |
+
'[album]' => array(),
|
1947 |
+
'[alt]' => array(),
|
1948 |
+
'[artist]' => array(),
|
1949 |
+
'[artwork]' => array(),
|
1950 |
+
'[attribution]' => array(),
|
1951 |
+
'[controls]' => array(),
|
1952 |
+
'[controlslist]' => array(),
|
1953 |
+
'[loop]' => array(),
|
1954 |
+
'[poster]' => array(),
|
1955 |
+
'[preload]' => array(),
|
1956 |
+
'[src]' => array(),
|
1957 |
+
'[title]' => array(),
|
1958 |
+
'album' => array(),
|
1959 |
+
'alt' => array(),
|
1960 |
+
'artist' => array(),
|
1961 |
+
'artwork' => array(),
|
1962 |
+
'attribution' => array(),
|
1963 |
+
'autoplay' => array(
|
1964 |
+
'value' => '',
|
1965 |
+
),
|
1966 |
+
'controls' => array(
|
1967 |
+
'value' => '',
|
1968 |
+
),
|
1969 |
+
'controlslist' => array(),
|
1970 |
+
'crossorigin' => array(),
|
1971 |
+
'disableremoteplayback' => array(
|
1972 |
+
'value' => '',
|
1973 |
+
),
|
1974 |
+
'loop' => array(
|
1975 |
+
'value' => '',
|
1976 |
+
),
|
1977 |
+
'media' => array(),
|
1978 |
+
'muted' => array(
|
1979 |
+
'value' => '',
|
1980 |
+
),
|
1981 |
+
'noloading' => array(
|
1982 |
+
'value' => '',
|
1983 |
+
),
|
1984 |
+
'placeholder' => array(),
|
1985 |
+
'poster' => array(
|
1986 |
+
'mandatory' => true,
|
1987 |
+
),
|
1988 |
+
'preload' => array(
|
1989 |
+
'value_regex' => '(none|metadata|auto|)',
|
1990 |
),
|
1991 |
+
'src' => array(
|
1992 |
+
'blacklisted_value_regex' => '__amp_source_origin',
|
1993 |
+
'allow_relative' => true,
|
1994 |
+
'allowed_protocol' => array(
|
1995 |
+
'https',
|
1996 |
+
),
|
1997 |
+
),
|
1998 |
+
),
|
1999 |
+
'tag_spec' => array(
|
2000 |
'html_format' => array(
|
2001 |
'amp',
|
2002 |
'amp4ads',
|
2003 |
),
|
2004 |
+
'mandatory_ancestor' => 'amp-story',
|
2005 |
+
'spec_name' => 'amp-story >> amp-video',
|
2006 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-video',
|
2007 |
),
|
2008 |
|
2009 |
),
|
2021 |
),
|
2022 |
),
|
2023 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
2024 |
'html_format' => array(
|
2025 |
'amp',
|
|
|
2026 |
),
|
|
|
2027 |
),
|
2028 |
|
2029 |
),
|
2040 |
),
|
2041 |
),
|
2042 |
'tag_spec' => array(
|
2043 |
+
'html_format' => array(
|
2044 |
+
'amp',
|
2045 |
),
|
2046 |
+
),
|
2047 |
+
|
2048 |
+
),
|
2049 |
+
),
|
2050 |
+
'amp-vk' => array(
|
2051 |
+
array(
|
2052 |
+
'attr_spec_list' => array(
|
2053 |
+
'data-embedtype' => array(
|
2054 |
+
'mandatory' => true,
|
2055 |
),
|
2056 |
+
'media' => array(),
|
2057 |
+
'noloading' => array(
|
2058 |
+
'value' => '',
|
2059 |
+
),
|
2060 |
+
),
|
2061 |
+
'tag_spec' => array(
|
2062 |
'html_format' => array(
|
2063 |
'amp',
|
|
|
2064 |
),
|
|
|
2065 |
),
|
2066 |
|
2067 |
),
|
2068 |
),
|
2069 |
+
'amp-web-push' => array(
|
2070 |
array(
|
2071 |
'attr_spec_list' => array(
|
2072 |
+
'helper-iframe-url' => array(
|
|
|
2073 |
'mandatory' => true,
|
2074 |
+
'allow_relative' => false,
|
2075 |
+
'allowed_protocol' => array(
|
2076 |
+
'https',
|
2077 |
+
),
|
2078 |
+
),
|
2079 |
+
'id' => array(
|
2080 |
+
'mandatory' => true,
|
2081 |
+
'value_regex' => 'amp-web-push',
|
2082 |
),
|
2083 |
'media' => array(),
|
2084 |
'noloading' => array(
|
2085 |
'value' => '',
|
2086 |
),
|
2087 |
+
'permission-dialog-url' => array(
|
2088 |
+
'mandatory' => true,
|
2089 |
+
'allow_relative' => false,
|
2090 |
+
'allowed_protocol' => array(
|
2091 |
+
'https',
|
2092 |
+
),
|
2093 |
+
),
|
2094 |
+
'service-worker-url' => array(
|
2095 |
+
'mandatory' => true,
|
2096 |
+
'allow_relative' => false,
|
2097 |
+
'allowed_protocol' => array(
|
2098 |
+
'https',
|
2099 |
+
),
|
2100 |
+
),
|
2101 |
),
|
2102 |
'tag_spec' => array(
|
2103 |
+
'html_format' => array(
|
2104 |
+
'amp',
|
2105 |
),
|
2106 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-web-push',
|
2107 |
+
),
|
2108 |
+
|
2109 |
+
),
|
2110 |
+
),
|
2111 |
+
'amp-web-push-widget' => array(
|
2112 |
+
array(
|
2113 |
+
'attr_spec_list' => array(
|
2114 |
+
'media' => array(),
|
2115 |
+
'noloading' => array(
|
2116 |
+
'value' => '',
|
2117 |
+
),
|
2118 |
+
'visibility' => array(
|
2119 |
+
'mandatory' => true,
|
2120 |
+
'value_regex' => '(blocked|subscribed|unsubscribed)',
|
2121 |
),
|
2122 |
+
),
|
2123 |
+
'tag_spec' => array(
|
2124 |
'html_format' => array(
|
2125 |
'amp',
|
|
|
2126 |
),
|
2127 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-web-push',
|
2128 |
+
),
|
2129 |
+
|
2130 |
+
),
|
2131 |
+
),
|
2132 |
+
'amp-youtube' => array(
|
2133 |
+
array(
|
2134 |
+
'attr_spec_list' => array(
|
2135 |
+
'[data-videoid]' => array(),
|
2136 |
+
'autoplay' => array(),
|
2137 |
+
'credentials' => array(
|
2138 |
+
'value_regex_casei' => '(include|omit)',
|
2139 |
+
),
|
2140 |
+
'data-videoid' => array(
|
2141 |
+
'mandatory' => true,
|
2142 |
+
'value_regex' => '[^=/?:]+',
|
2143 |
+
),
|
2144 |
+
'media' => array(),
|
2145 |
+
'noloading' => array(
|
2146 |
+
'value' => '',
|
2147 |
+
),
|
2148 |
),
|
2149 |
+
'tag_spec' => array(),
|
2150 |
|
2151 |
),
|
2152 |
),
|
2187 |
),
|
2188 |
'mandatory_ancestor' => 'noscript',
|
2189 |
'mandatory_ancestor_suggested_alternative' => 'amp-audio',
|
2190 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-audio',
|
2191 |
),
|
2192 |
|
2193 |
),
|
2232 |
'align' => array(),
|
2233 |
'cite' => array(
|
2234 |
'blacklisted_value_regex' => '__amp_source_origin',
|
2235 |
+
'allow_empty' => true,
|
2236 |
'allow_relative' => true,
|
2237 |
'allowed_protocol' => array(
|
|
|
|
|
2238 |
'http',
|
2239 |
'https',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2240 |
),
|
2241 |
),
|
2242 |
),
|
2250 |
'tag_spec' => array(
|
2251 |
'mandatory' => true,
|
2252 |
'mandatory_parent' => 'html',
|
2253 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#required-markup',
|
2254 |
'unique' => true,
|
2255 |
),
|
2256 |
|
2266 |
'button' => array(
|
2267 |
array(
|
2268 |
'attr_spec_list' => array(
|
2269 |
+
'[disabled]' => array(),
|
2270 |
+
'[type]' => array(),
|
2271 |
+
'[value]' => array(),
|
2272 |
'disabled' => array(
|
2273 |
'value' => '',
|
2274 |
),
|
2275 |
+
'name' => array(
|
2276 |
+
'blacklisted_value_regex' => '(^|\\s)(__amp_\\s*|__count__|__definegetter__|__definesetter__|__lookupgetter__|__lookupsetter__|__nosuchmethod__|__parent__|__proto__|__amp_\\s*|\\$p|\\$proxy|acceptcharset|addeventlistener|appendchild|assignedslot|attachshadow|baseuri|checkvalidity|childelementcount|childnodes|classlist|classname|clientheight|clientleft|clienttop|clientwidth|comparedocumentposition|computedname|computedrole|contenteditable|createshadowroot|enqueaction|firstchild|firstelementchild|getanimations|getattribute|getattributens|getattributenode|getattributenodens|getboundingclientrect|getclientrects|getdestinationinsertionpoints|getelementsbyclassname|getelementsbytagname|getelementsbytagnamens|getrootnode|hasattribute|hasattributens|hasattributes|haschildnodes|haspointercapture|innerhtml|innertext|inputmode|insertadjacentelement|insertadjacenthtml|insertadjacenttext|iscontenteditable|isdefaultnamespace|isequalnode|issamenode|lastchild|lastelementchild|lookupnamespaceuri|namespaceuri|nextelementsibling|nextsibling|nodename|nodetype|nodevalue|offsetheight|offsetleft|offsetparent|offsettop|offsetwidth|outerhtml|outertext|ownerdocument|parentelement|parentnode|previouselementsibling|previoussibling|queryselector|queryselectorall|releasepointercapture|removeattribute|removeattributens|removeattributenode|removechild|removeeventlistener|replacechild|reportvalidity|requestpointerlock|scrollheight|scrollintoview|scrollintoviewifneeded|scrollleft|scrollwidth|setattribute|setattributens|setattributenode|setattributenodens|setpointercapture|shadowroot|stylemap|tabindex|tagname|textcontent|tostring|valueof|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)matchesselector|(webkit|moz|ms|o)requestfullscreen|(webkit|moz|ms|o)requestfullscreen)(\\s|$)',
|
2277 |
+
),
|
2278 |
'role' => array(),
|
2279 |
'tabindex' => array(),
|
2280 |
'type' => array(),
|
2285 |
),
|
2286 |
array(
|
2287 |
'attr_spec_list' => array(
|
2288 |
+
'name' => array(
|
2289 |
+
'blacklisted_value_regex' => '(^|\\s)(__amp_\\s*|__count__|__definegetter__|__definesetter__|__lookupgetter__|__lookupsetter__|__nosuchmethod__|__parent__|__proto__|__amp_\\s*|\\$p|\\$proxy|acceptcharset|addeventlistener|appendchild|assignedslot|attachshadow|baseuri|checkvalidity|childelementcount|childnodes|classlist|classname|clientheight|clientleft|clienttop|clientwidth|comparedocumentposition|computedname|computedrole|contenteditable|createshadowroot|enqueaction|firstchild|firstelementchild|getanimations|getattribute|getattributens|getattributenode|getattributenodens|getboundingclientrect|getclientrects|getdestinationinsertionpoints|getelementsbyclassname|getelementsbytagname|getelementsbytagnamens|getrootnode|hasattribute|hasattributens|hasattributes|haschildnodes|haspointercapture|innerhtml|innertext|inputmode|insertadjacentelement|insertadjacenthtml|insertadjacenttext|iscontenteditable|isdefaultnamespace|isequalnode|issamenode|lastchild|lastelementchild|lookupnamespaceuri|namespaceuri|nextelementsibling|nextsibling|nodename|nodetype|nodevalue|offsetheight|offsetleft|offsetparent|offsettop|offsetwidth|outerhtml|outertext|ownerdocument|parentelement|parentnode|previouselementsibling|previoussibling|queryselector|queryselectorall|releasepointercapture|removeattribute|removeattributens|removeattributenode|removechild|removeeventlistener|replacechild|reportvalidity|requestpointerlock|scrollheight|scrollintoview|scrollintoviewifneeded|scrollleft|scrollwidth|setattribute|setattributens|setattributenode|setattributenodens|setpointercapture|shadowroot|stylemap|tabindex|tagname|textcontent|tostring|valueof|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)matchesselector|(webkit|moz|ms|o)requestfullscreen|(webkit|moz|ms|o)requestfullscreen)(\\s|$)',
|
2290 |
+
),
|
2291 |
'open-button' => array(
|
2292 |
'value' => '',
|
2293 |
),
|
2297 |
'value' => array(),
|
2298 |
),
|
2299 |
'tag_spec' => array(
|
2300 |
+
'html_format' => array(
|
2301 |
+
'amp',
|
2302 |
+
'amp4ads',
|
2303 |
+
),
|
2304 |
'mandatory_ancestor' => 'amp-app-banner',
|
2305 |
'spec_name' => 'amp-app-banner button[open-button]',
|
2306 |
),
|
2325 |
|
2326 |
),
|
2327 |
),
|
2328 |
+
'circle' => array(
|
2329 |
+
array(
|
2330 |
+
'attr_spec_list' => array(
|
2331 |
+
'alignment-baseline' => array(),
|
2332 |
+
'baseline-shift' => array(),
|
2333 |
+
'clip' => array(),
|
2334 |
+
'clip-path' => array(),
|
2335 |
+
'clip-rule' => array(),
|
2336 |
+
'color' => array(),
|
2337 |
+
'color-interpolation' => array(),
|
2338 |
+
'color-interpolation-filters' => array(),
|
2339 |
+
'color-profile' => array(),
|
2340 |
+
'color-rendering' => array(),
|
2341 |
+
'cursor' => array(),
|
2342 |
+
'cx' => array(),
|
2343 |
+
'cy' => array(),
|
2344 |
+
'direction' => array(),
|
2345 |
+
'display' => array(),
|
2346 |
+
'dominant-baseline' => array(),
|
2347 |
+
'enable-background' => array(),
|
2348 |
+
'externalresourcesrequired' => array(),
|
2349 |
+
'fill' => array(),
|
2350 |
+
'fill-opacity' => array(),
|
2351 |
+
'fill-rule' => array(),
|
2352 |
+
'filter' => array(),
|
2353 |
+
'flood-color' => array(),
|
2354 |
+
'flood-opacity' => array(),
|
2355 |
+
'font-family' => array(),
|
2356 |
+
'font-size' => array(),
|
2357 |
+
'font-size-adjust' => array(),
|
2358 |
+
'font-stretch' => array(),
|
2359 |
+
'font-style' => array(),
|
2360 |
+
'font-variant' => array(),
|
2361 |
+
'font-weight' => array(),
|
2362 |
+
'glyph-orientation-horizontal' => array(),
|
2363 |
+
'glyph-orientation-vertical' => array(),
|
2364 |
+
'image-rendering' => array(),
|
2365 |
+
'kerning' => array(),
|
2366 |
+
'letter-spacing' => array(),
|
2367 |
+
'lighting-color' => array(),
|
2368 |
+
'marker-end' => array(),
|
2369 |
+
'marker-mid' => array(),
|
2370 |
+
'marker-start' => array(),
|
2371 |
+
'mask' => array(),
|
2372 |
+
'opacity' => array(),
|
2373 |
+
'overflow' => array(),
|
2374 |
+
'pointer-events' => array(),
|
2375 |
+
'r' => array(),
|
2376 |
+
'requiredextensions' => array(),
|
2377 |
+
'requiredfeatures' => array(),
|
2378 |
+
'shape-rendering' => array(),
|
2379 |
+
'sketch:type' => array(),
|
2380 |
+
'stop-color' => array(),
|
2381 |
+
'stop-opacity' => array(),
|
2382 |
+
'stroke' => array(),
|
2383 |
+
'stroke-dasharray' => array(),
|
2384 |
+
'stroke-dashoffset' => array(),
|
2385 |
+
'stroke-linecap' => array(),
|
2386 |
+
'stroke-linejoin' => array(),
|
2387 |
+
'stroke-miterlimit' => array(),
|
2388 |
+
'stroke-opacity' => array(),
|
2389 |
+
'stroke-width' => array(),
|
2390 |
+
'style' => array(
|
2391 |
+
'blacklisted_value_regex' => '!important',
|
2392 |
+
),
|
2393 |
+
'systemlanguage' => array(),
|
2394 |
+
'text-anchor' => array(),
|
2395 |
+
'text-decoration' => array(),
|
2396 |
+
'text-rendering' => array(),
|
2397 |
+
'transform' => array(),
|
2398 |
+
'unicode-bidi' => array(),
|
2399 |
+
'vector-effect' => array(),
|
2400 |
+
'visibility' => array(),
|
2401 |
+
'word-spacing' => array(),
|
2402 |
+
'writing-mode' => array(),
|
2403 |
+
'xml:lang' => array(),
|
2404 |
+
'xml:space' => array(),
|
2405 |
+
'xmlns' => array(),
|
2406 |
+
'xmlns:xlink' => array(),
|
2407 |
+
),
|
2408 |
+
'tag_spec' => array(
|
2409 |
+
'html_format' => array(
|
2410 |
+
'amp',
|
2411 |
+
'amp4ads',
|
2412 |
+
),
|
2413 |
+
'mandatory_ancestor' => 'svg',
|
2414 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
2415 |
+
),
|
2416 |
+
|
2417 |
+
),
|
2418 |
+
),
|
2419 |
+
'cite' => array(
|
2420 |
+
array(
|
2421 |
+
'attr_spec_list' => array(),
|
2422 |
+
'tag_spec' => array(),
|
2423 |
+
|
2424 |
+
),
|
2425 |
+
),
|
2426 |
+
'clippath' => array(
|
2427 |
+
array(
|
2428 |
+
'attr_spec_list' => array(
|
2429 |
+
'alignment-baseline' => array(),
|
2430 |
+
'baseline-shift' => array(),
|
2431 |
+
'clip' => array(),
|
2432 |
+
'clip-path' => array(),
|
2433 |
+
'clip-rule' => array(),
|
2434 |
+
'clippathunits' => array(),
|
2435 |
+
'color' => array(),
|
2436 |
+
'color-interpolation' => array(),
|
2437 |
+
'color-interpolation-filters' => array(),
|
2438 |
+
'color-profile' => array(),
|
2439 |
+
'color-rendering' => array(),
|
2440 |
+
'cursor' => array(),
|
2441 |
+
'direction' => array(),
|
2442 |
+
'display' => array(),
|
2443 |
+
'dominant-baseline' => array(),
|
2444 |
+
'enable-background' => array(),
|
2445 |
+
'externalresourcesrequired' => array(),
|
2446 |
+
'fill' => array(),
|
2447 |
+
'fill-opacity' => array(),
|
2448 |
+
'fill-rule' => array(),
|
2449 |
+
'filter' => array(),
|
2450 |
+
'flood-color' => array(),
|
2451 |
+
'flood-opacity' => array(),
|
2452 |
+
'font-family' => array(),
|
2453 |
+
'font-size' => array(),
|
2454 |
+
'font-size-adjust' => array(),
|
2455 |
+
'font-stretch' => array(),
|
2456 |
+
'font-style' => array(),
|
2457 |
+
'font-variant' => array(),
|
2458 |
+
'font-weight' => array(),
|
2459 |
+
'glyph-orientation-horizontal' => array(),
|
2460 |
+
'glyph-orientation-vertical' => array(),
|
2461 |
+
'image-rendering' => array(),
|
2462 |
+
'kerning' => array(),
|
2463 |
+
'letter-spacing' => array(),
|
2464 |
+
'lighting-color' => array(),
|
2465 |
+
'marker-end' => array(),
|
2466 |
+
'marker-mid' => array(),
|
2467 |
+
'marker-start' => array(),
|
2468 |
+
'mask' => array(),
|
2469 |
+
'opacity' => array(),
|
2470 |
+
'overflow' => array(),
|
2471 |
+
'pointer-events' => array(),
|
2472 |
+
'requiredextensions' => array(),
|
2473 |
+
'requiredfeatures' => array(),
|
2474 |
+
'shape-rendering' => array(),
|
2475 |
+
'stop-color' => array(),
|
2476 |
+
'stop-opacity' => array(),
|
2477 |
+
'stroke' => array(),
|
2478 |
+
'stroke-dasharray' => array(),
|
2479 |
+
'stroke-dashoffset' => array(),
|
2480 |
+
'stroke-linecap' => array(),
|
2481 |
+
'stroke-linejoin' => array(),
|
2482 |
+
'stroke-miterlimit' => array(),
|
2483 |
+
'stroke-opacity' => array(),
|
2484 |
+
'stroke-width' => array(),
|
2485 |
+
'style' => array(
|
2486 |
+
'blacklisted_value_regex' => '!important',
|
2487 |
+
),
|
2488 |
+
'systemlanguage' => array(),
|
2489 |
+
'text-anchor' => array(),
|
2490 |
+
'text-decoration' => array(),
|
2491 |
+
'text-rendering' => array(),
|
2492 |
+
'transform' => array(),
|
2493 |
+
'unicode-bidi' => array(),
|
2494 |
+
'vector-effect' => array(),
|
2495 |
+
'visibility' => array(),
|
2496 |
+
'word-spacing' => array(),
|
2497 |
+
'writing-mode' => array(),
|
2498 |
+
'xml:lang' => array(),
|
2499 |
+
'xml:space' => array(),
|
2500 |
+
'xmlns' => array(),
|
2501 |
+
'xmlns:xlink' => array(),
|
2502 |
+
),
|
2503 |
+
'tag_spec' => array(
|
2504 |
+
'html_format' => array(
|
2505 |
+
'amp',
|
2506 |
+
'amp4ads',
|
2507 |
+
),
|
2508 |
+
'mandatory_ancestor' => 'svg',
|
2509 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
2510 |
+
),
|
2511 |
+
|
2512 |
+
),
|
2513 |
+
),
|
2514 |
+
'code' => array(
|
2515 |
+
array(
|
2516 |
+
'attr_spec_list' => array(),
|
2517 |
+
'tag_spec' => array(),
|
2518 |
+
|
2519 |
+
),
|
2520 |
+
),
|
2521 |
+
'col' => array(
|
2522 |
+
array(
|
2523 |
+
'attr_spec_list' => array(
|
2524 |
+
'span' => array(),
|
2525 |
+
),
|
2526 |
+
'tag_spec' => array(),
|
2527 |
+
|
2528 |
+
),
|
2529 |
+
),
|
2530 |
+
'colgroup' => array(
|
2531 |
+
array(
|
2532 |
+
'attr_spec_list' => array(
|
2533 |
+
'span' => array(),
|
2534 |
+
),
|
2535 |
+
'tag_spec' => array(),
|
2536 |
+
|
2537 |
+
),
|
2538 |
+
),
|
2539 |
+
'data' => array(
|
2540 |
+
array(
|
2541 |
+
'attr_spec_list' => array(),
|
2542 |
+
'tag_spec' => array(),
|
2543 |
+
|
2544 |
+
),
|
2545 |
+
),
|
2546 |
+
'datalist' => array(
|
2547 |
+
array(
|
2548 |
+
'attr_spec_list' => array(),
|
2549 |
+
'tag_spec' => array(
|
2550 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form',
|
2551 |
+
),
|
2552 |
+
|
2553 |
+
),
|
2554 |
+
),
|
2555 |
+
'dd' => array(
|
2556 |
+
array(
|
2557 |
+
'attr_spec_list' => array(),
|
2558 |
+
'tag_spec' => array(),
|
2559 |
+
|
2560 |
+
),
|
2561 |
+
),
|
2562 |
+
'defs' => array(
|
2563 |
+
array(
|
2564 |
+
'attr_spec_list' => array(
|
2565 |
+
'alignment-baseline' => array(),
|
2566 |
+
'baseline-shift' => array(),
|
2567 |
+
'clip' => array(),
|
2568 |
+
'clip-path' => array(),
|
2569 |
+
'clip-rule' => array(),
|
2570 |
+
'color' => array(),
|
2571 |
+
'color-interpolation' => array(),
|
2572 |
+
'color-interpolation-filters' => array(),
|
2573 |
+
'color-profile' => array(),
|
2574 |
+
'color-rendering' => array(),
|
2575 |
+
'cursor' => array(),
|
2576 |
+
'direction' => array(),
|
2577 |
+
'display' => array(),
|
2578 |
+
'dominant-baseline' => array(),
|
2579 |
+
'enable-background' => array(),
|
2580 |
+
'externalresourcesrequired' => array(),
|
2581 |
+
'fill' => array(),
|
2582 |
+
'fill-opacity' => array(),
|
2583 |
+
'fill-rule' => array(),
|
2584 |
+
'filter' => array(),
|
2585 |
+
'flood-color' => array(),
|
2586 |
+
'flood-opacity' => array(),
|
2587 |
+
'font-family' => array(),
|
2588 |
+
'font-size' => array(),
|
2589 |
+
'font-size-adjust' => array(),
|
2590 |
+
'font-stretch' => array(),
|
2591 |
+
'font-style' => array(),
|
2592 |
+
'font-variant' => array(),
|
2593 |
+
'font-weight' => array(),
|
2594 |
+
'glyph-orientation-horizontal' => array(),
|
2595 |
+
'glyph-orientation-vertical' => array(),
|
2596 |
+
'image-rendering' => array(),
|
2597 |
+
'kerning' => array(),
|
2598 |
+
'letter-spacing' => array(),
|
2599 |
+
'lighting-color' => array(),
|
2600 |
+
'marker-end' => array(),
|
2601 |
+
'marker-mid' => array(),
|
2602 |
+
'marker-start' => array(),
|
2603 |
+
'mask' => array(),
|
2604 |
+
'opacity' => array(),
|
2605 |
+
'overflow' => array(),
|
2606 |
+
'pointer-events' => array(),
|
2607 |
+
'requiredextensions' => array(),
|
2608 |
+
'requiredfeatures' => array(),
|
2609 |
+
'shape-rendering' => array(),
|
2610 |
+
'stop-color' => array(),
|
2611 |
+
'stop-opacity' => array(),
|
2612 |
+
'stroke' => array(),
|
2613 |
+
'stroke-dasharray' => array(),
|
2614 |
+
'stroke-dashoffset' => array(),
|
2615 |
+
'stroke-linecap' => array(),
|
2616 |
+
'stroke-linejoin' => array(),
|
2617 |
+
'stroke-miterlimit' => array(),
|
2618 |
+
'stroke-opacity' => array(),
|
2619 |
+
'stroke-width' => array(),
|
2620 |
+
'style' => array(
|
2621 |
+
'blacklisted_value_regex' => '!important',
|
2622 |
+
),
|
2623 |
+
'systemlanguage' => array(),
|
2624 |
+
'text-anchor' => array(),
|
2625 |
+
'text-decoration' => array(),
|
2626 |
+
'text-rendering' => array(),
|
2627 |
+
'transform' => array(),
|
2628 |
+
'unicode-bidi' => array(),
|
2629 |
+
'vector-effect' => array(),
|
2630 |
+
'visibility' => array(),
|
2631 |
+
'word-spacing' => array(),
|
2632 |
+
'writing-mode' => array(),
|
2633 |
+
'xml:lang' => array(),
|
2634 |
+
'xml:space' => array(),
|
2635 |
+
'xmlns' => array(),
|
2636 |
+
'xmlns:xlink' => array(),
|
2637 |
+
),
|
2638 |
+
'tag_spec' => array(
|
2639 |
+
'html_format' => array(
|
2640 |
+
'amp',
|
2641 |
+
'amp4ads',
|
2642 |
+
),
|
2643 |
+
'mandatory_ancestor' => 'svg',
|
2644 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
2645 |
+
),
|
2646 |
+
|
2647 |
+
),
|
2648 |
+
),
|
2649 |
+
'del' => array(
|
2650 |
+
array(
|
2651 |
+
'attr_spec_list' => array(
|
2652 |
+
'cite' => array(
|
2653 |
+
'blacklisted_value_regex' => '__amp_source_origin',
|
2654 |
+
'allow_empty' => true,
|
2655 |
+
'allow_relative' => true,
|
2656 |
+
'allowed_protocol' => array(
|
2657 |
+
'http',
|
2658 |
+
'https',
|
2659 |
+
),
|
2660 |
+
),
|
2661 |
+
'datetime' => array(),
|
2662 |
+
),
|
2663 |
+
'tag_spec' => array(),
|
2664 |
+
|
2665 |
+
),
|
2666 |
+
),
|
2667 |
+
'desc' => array(
|
2668 |
+
array(
|
2669 |
+
'attr_spec_list' => array(
|
2670 |
+
'style' => array(
|
2671 |
+
'blacklisted_value_regex' => '!important',
|
2672 |
+
),
|
2673 |
+
'xml:lang' => array(),
|
2674 |
+
'xml:space' => array(),
|
2675 |
+
'xmlns' => array(),
|
2676 |
+
'xmlns:xlink' => array(),
|
2677 |
+
),
|
2678 |
+
'tag_spec' => array(
|
2679 |
+
'html_format' => array(
|
2680 |
+
'amp',
|
2681 |
+
'amp4ads',
|
2682 |
+
),
|
2683 |
+
'mandatory_ancestor' => 'svg',
|
2684 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
2685 |
+
),
|
2686 |
+
|
2687 |
+
),
|
2688 |
+
),
|
2689 |
+
'dfn' => array(
|
2690 |
+
array(
|
2691 |
+
'attr_spec_list' => array(),
|
2692 |
+
'tag_spec' => array(),
|
2693 |
+
|
2694 |
+
),
|
2695 |
+
),
|
2696 |
+
'dir' => array(
|
2697 |
+
array(
|
2698 |
+
'attr_spec_list' => array(),
|
2699 |
+
'tag_spec' => array(
|
2700 |
+
'html_format' => array(
|
2701 |
+
'amp',
|
2702 |
+
),
|
2703 |
+
),
|
2704 |
+
|
2705 |
+
),
|
2706 |
+
),
|
2707 |
+
'div' => array(
|
2708 |
+
array(
|
2709 |
+
'attr_spec_list' => array(
|
2710 |
+
'align' => array(),
|
2711 |
+
),
|
2712 |
+
'tag_spec' => array(),
|
2713 |
+
|
2714 |
+
),
|
2715 |
+
array(
|
2716 |
+
'attr_spec_list' => array(
|
2717 |
+
'align' => array(),
|
2718 |
+
'submitting' => array(
|
2719 |
+
'mandatory' => true,
|
2720 |
+
),
|
2721 |
+
),
|
2722 |
+
'tag_spec' => array(
|
2723 |
+
'mandatory_parent' => 'form',
|
2724 |
+
'spec_name' => 'form > div [submitting]',
|
2725 |
+
),
|
2726 |
+
|
2727 |
+
),
|
2728 |
+
array(
|
2729 |
+
'attr_spec_list' => array(
|
2730 |
+
'align' => array(),
|
2731 |
+
'submit-success' => array(
|
2732 |
+
'mandatory' => true,
|
2733 |
+
),
|
2734 |
+
),
|
2735 |
+
'tag_spec' => array(
|
2736 |
+
'mandatory_parent' => 'form',
|
2737 |
+
'spec_name' => 'form > div [submit-success]',
|
2738 |
+
),
|
2739 |
+
|
2740 |
+
),
|
2741 |
+
array(
|
2742 |
+
'attr_spec_list' => array(
|
2743 |
+
'align' => array(),
|
2744 |
+
'submit-error' => array(
|
2745 |
+
'mandatory' => true,
|
2746 |
+
),
|
2747 |
+
),
|
2748 |
+
'tag_spec' => array(
|
2749 |
+
'mandatory_parent' => 'form',
|
2750 |
+
'spec_name' => 'form > div [submit-error]',
|
2751 |
+
),
|
2752 |
+
|
2753 |
+
),
|
2754 |
+
),
|
2755 |
+
'dl' => array(
|
2756 |
+
array(
|
2757 |
+
'attr_spec_list' => array(),
|
2758 |
+
'tag_spec' => array(),
|
2759 |
+
|
2760 |
+
),
|
2761 |
+
),
|
2762 |
+
'dt' => array(
|
2763 |
+
array(
|
2764 |
+
'attr_spec_list' => array(),
|
2765 |
+
'tag_spec' => array(),
|
2766 |
+
|
2767 |
+
),
|
2768 |
+
),
|
2769 |
+
'ellipse' => array(
|
2770 |
+
array(
|
2771 |
+
'attr_spec_list' => array(
|
2772 |
+
'alignment-baseline' => array(),
|
2773 |
+
'baseline-shift' => array(),
|
2774 |
+
'clip' => array(),
|
2775 |
+
'clip-path' => array(),
|
2776 |
+
'clip-rule' => array(),
|
2777 |
+
'color' => array(),
|
2778 |
+
'color-interpolation' => array(),
|
2779 |
+
'color-interpolation-filters' => array(),
|
2780 |
+
'color-profile' => array(),
|
2781 |
+
'color-rendering' => array(),
|
2782 |
+
'cursor' => array(),
|
2783 |
+
'cx' => array(),
|
2784 |
+
'cy' => array(),
|
2785 |
+
'direction' => array(),
|
2786 |
+
'display' => array(),
|
2787 |
+
'dominant-baseline' => array(),
|
2788 |
+
'enable-background' => array(),
|
2789 |
+
'externalresourcesrequired' => array(),
|
2790 |
+
'fill' => array(),
|
2791 |
+
'fill-opacity' => array(),
|
2792 |
+
'fill-rule' => array(),
|
2793 |
+
'filter' => array(),
|
2794 |
+
'flood-color' => array(),
|
2795 |
+
'flood-opacity' => array(),
|
2796 |
+
'font-family' => array(),
|
2797 |
+
'font-size' => array(),
|
2798 |
+
'font-size-adjust' => array(),
|
2799 |
+
'font-stretch' => array(),
|
2800 |
+
'font-style' => array(),
|
2801 |
+
'font-variant' => array(),
|
2802 |
+
'font-weight' => array(),
|
2803 |
+
'glyph-orientation-horizontal' => array(),
|
2804 |
+
'glyph-orientation-vertical' => array(),
|
2805 |
+
'image-rendering' => array(),
|
2806 |
+
'kerning' => array(),
|
2807 |
+
'letter-spacing' => array(),
|
2808 |
+
'lighting-color' => array(),
|
2809 |
+
'marker-end' => array(),
|
2810 |
+
'marker-mid' => array(),
|
2811 |
+
'marker-start' => array(),
|
2812 |
+
'mask' => array(),
|
2813 |
+
'opacity' => array(),
|
2814 |
+
'overflow' => array(),
|
2815 |
+
'pointer-events' => array(),
|
2816 |
+
'requiredextensions' => array(),
|
2817 |
+
'requiredfeatures' => array(),
|
2818 |
+
'rx' => array(),
|
2819 |
+
'ry' => array(),
|
2820 |
+
'shape-rendering' => array(),
|
2821 |
+
'sketch:type' => array(),
|
2822 |
+
'stop-color' => array(),
|
2823 |
+
'stop-opacity' => array(),
|
2824 |
+
'stroke' => array(),
|
2825 |
+
'stroke-dasharray' => array(),
|
2826 |
+
'stroke-dashoffset' => array(),
|
2827 |
+
'stroke-linecap' => array(),
|
2828 |
+
'stroke-linejoin' => array(),
|
2829 |
+
'stroke-miterlimit' => array(),
|
2830 |
+
'stroke-opacity' => array(),
|
2831 |
+
'stroke-width' => array(),
|
2832 |
+
'style' => array(
|
2833 |
+
'blacklisted_value_regex' => '!important',
|
2834 |
+
),
|
2835 |
+
'systemlanguage' => array(),
|
2836 |
+
'text-anchor' => array(),
|
2837 |
+
'text-decoration' => array(),
|
2838 |
+
'text-rendering' => array(),
|
2839 |
+
'transform' => array(),
|
2840 |
+
'unicode-bidi' => array(),
|
2841 |
+
'vector-effect' => array(),
|
2842 |
+
'visibility' => array(),
|
2843 |
+
'word-spacing' => array(),
|
2844 |
+
'writing-mode' => array(),
|
2845 |
+
'xml:lang' => array(),
|
2846 |
+
'xml:space' => array(),
|
2847 |
+
'xmlns' => array(),
|
2848 |
+
'xmlns:xlink' => array(),
|
2849 |
+
),
|
2850 |
+
'tag_spec' => array(
|
2851 |
+
'html_format' => array(
|
2852 |
+
'amp',
|
2853 |
+
'amp4ads',
|
2854 |
+
),
|
2855 |
+
'mandatory_ancestor' => 'svg',
|
2856 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
2857 |
+
),
|
2858 |
+
|
2859 |
+
),
|
2860 |
+
),
|
2861 |
+
'em' => array(
|
2862 |
+
array(
|
2863 |
+
'attr_spec_list' => array(),
|
2864 |
+
'tag_spec' => array(),
|
2865 |
+
|
2866 |
+
),
|
2867 |
+
),
|
2868 |
+
'fecolormatrix' => array(
|
2869 |
+
array(
|
2870 |
+
'attr_spec_list' => array(
|
2871 |
+
'alignment-baseline' => array(),
|
2872 |
+
'baseline-shift' => array(),
|
2873 |
+
'clip' => array(),
|
2874 |
+
'clip-path' => array(),
|
2875 |
+
'clip-rule' => array(),
|
2876 |
+
'color' => array(),
|
2877 |
+
'color-interpolation' => array(),
|
2878 |
+
'color-interpolation-filters' => array(),
|
2879 |
+
'color-profile' => array(),
|
2880 |
+
'color-rendering' => array(),
|
2881 |
+
'cursor' => array(),
|
2882 |
+
'direction' => array(),
|
2883 |
+
'display' => array(),
|
2884 |
+
'dominant-baseline' => array(),
|
2885 |
+
'enable-background' => array(),
|
2886 |
+
'fill' => array(),
|
2887 |
+
'fill-opacity' => array(),
|
2888 |
+
'fill-rule' => array(),
|
2889 |
+
'filter' => array(),
|
2890 |
+
'flood-color' => array(),
|
2891 |
+
'flood-opacity' => array(),
|
2892 |
+
'font-family' => array(),
|
2893 |
+
'font-size' => array(),
|
2894 |
+
'font-size-adjust' => array(),
|
2895 |
+
'font-stretch' => array(),
|
2896 |
+
'font-style' => array(),
|
2897 |
+
'font-variant' => array(),
|
2898 |
+
'font-weight' => array(),
|
2899 |
+
'glyph-orientation-horizontal' => array(),
|
2900 |
+
'glyph-orientation-vertical' => array(),
|
2901 |
+
'height' => array(),
|
2902 |
+
'image-rendering' => array(),
|
2903 |
+
'in' => array(),
|
2904 |
+
'kerning' => array(),
|
2905 |
+
'letter-spacing' => array(),
|
2906 |
+
'lighting-color' => array(),
|
2907 |
+
'marker-end' => array(),
|
2908 |
+
'marker-mid' => array(),
|
2909 |
+
'marker-start' => array(),
|
2910 |
+
'mask' => array(),
|
2911 |
+
'opacity' => array(),
|
2912 |
+
'overflow' => array(),
|
2913 |
+
'pointer-events' => array(),
|
2914 |
+
'result' => array(),
|
2915 |
+
'shape-rendering' => array(),
|
2916 |
+
'stop-color' => array(),
|
2917 |
+
'stop-opacity' => array(),
|
2918 |
+
'stroke' => array(),
|
2919 |
+
'stroke-dasharray' => array(),
|
2920 |
+
'stroke-dashoffset' => array(),
|
2921 |
+
'stroke-linecap' => array(),
|
2922 |
+
'stroke-linejoin' => array(),
|
2923 |
+
'stroke-miterlimit' => array(),
|
2924 |
+
'stroke-opacity' => array(),
|
2925 |
+
'stroke-width' => array(),
|
2926 |
+
'style' => array(
|
2927 |
+
'blacklisted_value_regex' => '!important',
|
2928 |
+
),
|
2929 |
+
'text-anchor' => array(),
|
2930 |
+
'text-decoration' => array(),
|
2931 |
+
'text-rendering' => array(),
|
2932 |
+
'type' => array(),
|
2933 |
+
'unicode-bidi' => array(),
|
2934 |
+
'values' => array(),
|
2935 |
+
'vector-effect' => array(),
|
2936 |
+
'visibility' => array(),
|
2937 |
+
'width' => array(),
|
2938 |
+
'word-spacing' => array(),
|
2939 |
+
'writing-mode' => array(),
|
2940 |
+
'x' => array(),
|
2941 |
+
'xml:lang' => array(),
|
2942 |
+
'xml:space' => array(),
|
2943 |
+
'xmlns' => array(),
|
2944 |
+
'xmlns:xlink' => array(),
|
2945 |
+
'y' => array(),
|
2946 |
+
),
|
2947 |
+
'tag_spec' => array(
|
2948 |
+
'html_format' => array(
|
2949 |
+
'amp',
|
2950 |
+
'amp4ads',
|
2951 |
+
),
|
2952 |
+
'mandatory_ancestor' => 'svg',
|
2953 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
2954 |
+
),
|
2955 |
+
|
2956 |
+
),
|
2957 |
+
),
|
2958 |
+
'fecomposite' => array(
|
2959 |
+
array(
|
2960 |
+
'attr_spec_list' => array(
|
2961 |
+
'alignment-baseline' => array(),
|
2962 |
+
'baseline-shift' => array(),
|
2963 |
+
'clip' => array(),
|
2964 |
+
'clip-path' => array(),
|
2965 |
+
'clip-rule' => array(),
|
2966 |
+
'color' => array(),
|
2967 |
+
'color-interpolation' => array(),
|
2968 |
+
'color-interpolation-filters' => array(),
|
2969 |
+
'color-profile' => array(),
|
2970 |
+
'color-rendering' => array(),
|
2971 |
+
'cursor' => array(),
|
2972 |
+
'direction' => array(),
|
2973 |
+
'display' => array(),
|
2974 |
+
'dominant-baseline' => array(),
|
2975 |
+
'enable-background' => array(),
|
2976 |
+
'fill' => array(),
|
2977 |
+
'fill-opacity' => array(),
|
2978 |
+
'fill-rule' => array(),
|
2979 |
+
'filter' => array(),
|
2980 |
+
'flood-color' => array(),
|
2981 |
+
'flood-opacity' => array(),
|
2982 |
+
'font-family' => array(),
|
2983 |
+
'font-size' => array(),
|
2984 |
+
'font-size-adjust' => array(),
|
2985 |
+
'font-stretch' => array(),
|
2986 |
+
'font-style' => array(),
|
2987 |
+
'font-variant' => array(),
|
2988 |
+
'font-weight' => array(),
|
2989 |
+
'glyph-orientation-horizontal' => array(),
|
2990 |
+
'glyph-orientation-vertical' => array(),
|
2991 |
+
'height' => array(),
|
2992 |
+
'image-rendering' => array(),
|
2993 |
+
'in' => array(),
|
2994 |
+
'in2' => array(),
|
2995 |
+
'k1' => array(),
|
2996 |
+
'k2' => array(),
|
2997 |
+
'k3' => array(),
|
2998 |
+
'k4' => array(),
|
2999 |
+
'kerning' => array(),
|
3000 |
+
'letter-spacing' => array(),
|
3001 |
+
'lighting-color' => array(),
|
3002 |
+
'marker-end' => array(),
|
3003 |
+
'marker-mid' => array(),
|
3004 |
+
'marker-start' => array(),
|
3005 |
+
'mask' => array(),
|
3006 |
+
'opacity' => array(),
|
3007 |
+
'operator' => array(),
|
3008 |
+
'overflow' => array(),
|
3009 |
+
'pointer-events' => array(),
|
3010 |
+
'result' => array(),
|
3011 |
+
'shape-rendering' => array(),
|
3012 |
+
'stop-color' => array(),
|
3013 |
+
'stop-opacity' => array(),
|
3014 |
+
'stroke' => array(),
|
3015 |
+
'stroke-dasharray' => array(),
|
3016 |
+
'stroke-dashoffset' => array(),
|
3017 |
+
'stroke-linecap' => array(),
|
3018 |
+
'stroke-linejoin' => array(),
|
3019 |
+
'stroke-miterlimit' => array(),
|
3020 |
+
'stroke-opacity' => array(),
|
3021 |
+
'stroke-width' => array(),
|
3022 |
+
'style' => array(
|
3023 |
+
'blacklisted_value_regex' => '!important',
|
3024 |
+
),
|
3025 |
+
'text-anchor' => array(),
|
3026 |
+
'text-decoration' => array(),
|
3027 |
+
'text-rendering' => array(),
|
3028 |
+
'unicode-bidi' => array(),
|
3029 |
+
'vector-effect' => array(),
|
3030 |
+
'visibility' => array(),
|
3031 |
+
'width' => array(),
|
3032 |
+
'word-spacing' => array(),
|
3033 |
+
'writing-mode' => array(),
|
3034 |
+
'x' => array(),
|
3035 |
+
'xml:lang' => array(),
|
3036 |
+
'xml:space' => array(),
|
3037 |
+
'xmlns' => array(),
|
3038 |
+
'xmlns:xlink' => array(),
|
3039 |
+
'y' => array(),
|
3040 |
+
),
|
3041 |
+
'tag_spec' => array(
|
3042 |
+
'html_format' => array(
|
3043 |
+
'amp',
|
3044 |
+
'amp4ads',
|
3045 |
+
),
|
3046 |
+
'mandatory_ancestor' => 'svg',
|
3047 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
3048 |
+
),
|
3049 |
+
|
3050 |
+
),
|
3051 |
+
),
|
3052 |
+
'feflood' => array(
|
3053 |
array(
|
3054 |
'attr_spec_list' => array(
|
3055 |
'alignment-baseline' => array(),
|
3056 |
'baseline-shift' => array(),
|
|
|
3057 |
'clip' => array(),
|
3058 |
'clip-path' => array(),
|
3059 |
'clip-rule' => array(),
|
3063 |
'color-profile' => array(),
|
3064 |
'color-rendering' => array(),
|
3065 |
'cursor' => array(),
|
|
|
|
|
3066 |
'direction' => array(),
|
3067 |
'display' => array(),
|
3068 |
'dominant-baseline' => array(),
|
3069 |
'enable-background' => array(),
|
|
|
3070 |
'fill' => array(),
|
3071 |
'fill-opacity' => array(),
|
3072 |
'fill-rule' => array(),
|
3082 |
'font-weight' => array(),
|
3083 |
'glyph-orientation-horizontal' => array(),
|
3084 |
'glyph-orientation-vertical' => array(),
|
3085 |
+
'height' => array(),
|
3086 |
'image-rendering' => array(),
|
3087 |
'kerning' => array(),
|
3088 |
'letter-spacing' => array(),
|
3094 |
'opacity' => array(),
|
3095 |
'overflow' => array(),
|
3096 |
'pointer-events' => array(),
|
3097 |
+
'result' => array(),
|
|
|
|
|
3098 |
'shape-rendering' => array(),
|
|
|
3099 |
'stop-color' => array(),
|
3100 |
'stop-opacity' => array(),
|
3101 |
'stroke' => array(),
|
3106 |
'stroke-miterlimit' => array(),
|
3107 |
'stroke-opacity' => array(),
|
3108 |
'stroke-width' => array(),
|
3109 |
+
'style' => array(
|
3110 |
+
'blacklisted_value_regex' => '!important',
|
3111 |
+
),
|
3112 |
'text-anchor' => array(),
|
3113 |
'text-decoration' => array(),
|
3114 |
'text-rendering' => array(),
|
|
|
3115 |
'unicode-bidi' => array(),
|
3116 |
+
'vector-effect' => array(),
|
3117 |
'visibility' => array(),
|
3118 |
+
'width' => array(),
|
3119 |
'word-spacing' => array(),
|
3120 |
'writing-mode' => array(),
|
3121 |
+
'x' => array(),
|
3122 |
'xml:lang' => array(),
|
3123 |
'xml:space' => array(),
|
3124 |
'xmlns' => array(),
|
3125 |
'xmlns:xlink' => array(),
|
3126 |
+
'y' => array(),
|
3127 |
),
|
3128 |
'tag_spec' => array(
|
3129 |
+
'html_format' => array(
|
3130 |
+
'amp',
|
3131 |
+
'amp4ads',
|
3132 |
+
),
|
3133 |
'mandatory_ancestor' => 'svg',
|
3134 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
3135 |
),
|
3136 |
|
3137 |
),
|
3138 |
),
|
3139 |
+
'fegaussianblur' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3140 |
array(
|
3141 |
'attr_spec_list' => array(
|
3142 |
'alignment-baseline' => array(),
|
3143 |
'baseline-shift' => array(),
|
|
|
3144 |
'clip' => array(),
|
3145 |
'clip-path' => array(),
|
3146 |
'clip-rule' => array(),
|
|
|
3147 |
'color' => array(),
|
3148 |
'color-interpolation' => array(),
|
3149 |
'color-interpolation-filters' => array(),
|
3153 |
'direction' => array(),
|
3154 |
'display' => array(),
|
3155 |
'dominant-baseline' => array(),
|
3156 |
+
'edgemode' => array(),
|
3157 |
'enable-background' => array(),
|
|
|
3158 |
'fill' => array(),
|
3159 |
'fill-opacity' => array(),
|
3160 |
'fill-rule' => array(),
|
3170 |
'font-weight' => array(),
|
3171 |
'glyph-orientation-horizontal' => array(),
|
3172 |
'glyph-orientation-vertical' => array(),
|
3173 |
+
'height' => array(),
|
3174 |
'image-rendering' => array(),
|
3175 |
+
'in' => array(),
|
3176 |
'kerning' => array(),
|
3177 |
'letter-spacing' => array(),
|
3178 |
'lighting-color' => array(),
|
3183 |
'opacity' => array(),
|
3184 |
'overflow' => array(),
|
3185 |
'pointer-events' => array(),
|
3186 |
+
'result' => array(),
|
|
|
3187 |
'shape-rendering' => array(),
|
3188 |
+
'stddeviation' => array(),
|
3189 |
'stop-color' => array(),
|
3190 |
'stop-opacity' => array(),
|
3191 |
'stroke' => array(),
|
3196 |
'stroke-miterlimit' => array(),
|
3197 |
'stroke-opacity' => array(),
|
3198 |
'stroke-width' => array(),
|
3199 |
+
'style' => array(
|
3200 |
+
'blacklisted_value_regex' => '!important',
|
3201 |
+
),
|
3202 |
'text-anchor' => array(),
|
3203 |
'text-decoration' => array(),
|
3204 |
'text-rendering' => array(),
|
|
|
3205 |
'unicode-bidi' => array(),
|
3206 |
+
'vector-effect' => array(),
|
3207 |
'visibility' => array(),
|
3208 |
+
'width' => array(),
|
3209 |
'word-spacing' => array(),
|
3210 |
'writing-mode' => array(),
|
3211 |
+
'x' => array(),
|
3212 |
'xml:lang' => array(),
|
3213 |
'xml:space' => array(),
|
3214 |
'xmlns' => array(),
|
3215 |
'xmlns:xlink' => array(),
|
3216 |
+
'y' => array(),
|
3217 |
),
|
3218 |
'tag_spec' => array(
|
3219 |
+
'html_format' => array(
|
3220 |
+
'amp',
|
3221 |
+
'amp4ads',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3222 |
),
|
3223 |
+
'mandatory_ancestor' => 'svg',
|
3224 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
3225 |
),
|
3226 |
|
3227 |
),
|
3228 |
),
|
3229 |
+
'femerge' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3230 |
array(
|
3231 |
'attr_spec_list' => array(
|
3232 |
'alignment-baseline' => array(),
|
3233 |
'baseline-shift' => array(),
|
|
|
3234 |
'clip' => array(),
|
3235 |
'clip-path' => array(),
|
3236 |
'clip-rule' => array(),
|
3244 |
'display' => array(),
|
3245 |
'dominant-baseline' => array(),
|
3246 |
'enable-background' => array(),
|
|
|
3247 |
'fill' => array(),
|
3248 |
'fill-opacity' => array(),
|
3249 |
'fill-rule' => array(),
|
3259 |
'font-weight' => array(),
|
3260 |
'glyph-orientation-horizontal' => array(),
|
3261 |
'glyph-orientation-vertical' => array(),
|
3262 |
+
'height' => array(),
|
3263 |
'image-rendering' => array(),
|
3264 |
'kerning' => array(),
|
3265 |
'letter-spacing' => array(),
|
3271 |
'opacity' => array(),
|
3272 |
'overflow' => array(),
|
3273 |
'pointer-events' => array(),
|
3274 |
+
'result' => array(),
|
|
|
3275 |
'shape-rendering' => array(),
|
3276 |
'stop-color' => array(),
|
3277 |
'stop-opacity' => array(),
|
3283 |
'stroke-miterlimit' => array(),
|
3284 |
'stroke-opacity' => array(),
|
3285 |
'stroke-width' => array(),
|
3286 |
+
'style' => array(
|
3287 |
+
'blacklisted_value_regex' => '!important',
|
3288 |
+
),
|
3289 |
'text-anchor' => array(),
|
3290 |
'text-decoration' => array(),
|
3291 |
'text-rendering' => array(),
|
|
|
3292 |
'unicode-bidi' => array(),
|
3293 |
+
'vector-effect' => array(),
|
3294 |
'visibility' => array(),
|
3295 |
+
'width' => array(),
|
3296 |
'word-spacing' => array(),
|
3297 |
'writing-mode' => array(),
|
3298 |
+
'x' => array(),
|
3299 |
'xml:lang' => array(),
|
3300 |
'xml:space' => array(),
|
3301 |
'xmlns' => array(),
|
3302 |
'xmlns:xlink' => array(),
|
3303 |
+
'y' => array(),
|
3304 |
),
|
3305 |
'tag_spec' => array(
|
3306 |
+
'html_format' => array(
|
3307 |
+
'amp',
|
3308 |
+
'amp4ads',
|
3309 |
+
),
|
3310 |
'mandatory_ancestor' => 'svg',
|
3311 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
3312 |
),
|
3313 |
|
3314 |
),
|
3315 |
),
|
3316 |
+
'femergenode' => array(
|
3317 |
array(
|
3318 |
'attr_spec_list' => array(
|
3319 |
+
'in' => array(),
|
3320 |
+
'style' => array(
|
3321 |
+
'blacklisted_value_regex' => '!important',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3322 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3323 |
'xml:lang' => array(),
|
3324 |
'xml:space' => array(),
|
3325 |
'xmlns' => array(),
|
3326 |
'xmlns:xlink' => array(),
|
3327 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3328 |
'tag_spec' => array(
|
3329 |
'html_format' => array(
|
3330 |
'amp',
|
3331 |
+
'amp4ads',
|
3332 |
),
|
3333 |
+
'mandatory_ancestor' => 'svg',
|
3334 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
3335 |
),
|
3336 |
|
3337 |
),
|
3338 |
),
|
3339 |
+
'feoffset' => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3340 |
array(
|
3341 |
'attr_spec_list' => array(
|
3342 |
'alignment-baseline' => array(),
|
3343 |
'baseline-shift' => array(),
|
|
|
3344 |
'clip' => array(),
|
3345 |
'clip-path' => array(),
|
3346 |
'clip-rule' => array(),
|
3350 |
'color-profile' => array(),
|
3351 |
'color-rendering' => array(),
|
3352 |
'cursor' => array(),
|
|
|
|
|
3353 |
'direction' => array(),
|
3354 |
'display' => array(),
|
3355 |
'dominant-baseline' => array(),
|
3356 |
+
'dx' => array(),
|
3357 |
+
'dy' => array(),
|
3358 |
'enable-background' => array(),
|
|
|
3359 |
'fill' => array(),
|
3360 |
'fill-opacity' => array(),
|
3361 |
'fill-rule' => array(),
|
3371 |
'font-weight' => array(),
|
3372 |
'glyph-orientation-horizontal' => array(),
|
3373 |
'glyph-orientation-vertical' => array(),
|
3374 |
+
'height' => array(),
|
3375 |
'image-rendering' => array(),
|
3376 |
+
'in' => array(),
|
3377 |
'kerning' => array(),
|
3378 |
'letter-spacing' => array(),
|
3379 |
'lighting-color' => array(),
|
3384 |
'opacity' => array(),
|
3385 |
'overflow' => array(),
|
3386 |
'pointer-events' => array(),
|
3387 |
+
'result' => array(),
|
|
|
|
|
|
|
3388 |
'shape-rendering' => array(),
|
|
|
3389 |
'stop-color' => array(),
|
3390 |
'stop-opacity' => array(),
|
3391 |
'stroke' => array(),
|
3396 |
'stroke-miterlimit' => array(),
|
3397 |
'stroke-opacity' => array(),
|
3398 |
'stroke-width' => array(),
|
3399 |
+
'style' => array(
|
3400 |
+
'blacklisted_value_regex' => '!important',
|
3401 |
+
),
|
3402 |
'text-anchor' => array(),
|
3403 |
'text-decoration' => array(),
|
3404 |
'text-rendering' => array(),
|
|
|
3405 |
'unicode-bidi' => array(),
|
3406 |
+
'vector-effect' => array(),
|
3407 |
'visibility' => array(),
|
3408 |
+
'width' => array(),
|
3409 |
'word-spacing' => array(),
|
3410 |
'writing-mode' => array(),
|
3411 |
+
'x' => array(),
|
3412 |
'xml:lang' => array(),
|
3413 |
'xml:space' => array(),
|
3414 |
'xmlns' => array(),
|
3415 |
'xmlns:xlink' => array(),
|
3416 |
+
'y' => array(),
|
3417 |
),
|
3418 |
'tag_spec' => array(
|
3419 |
+
'html_format' => array(
|
3420 |
+
'amp',
|
3421 |
+
'amp4ads',
|
3422 |
+
),
|
3423 |
'mandatory_ancestor' => 'svg',
|
3424 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
3425 |
),
|
3426 |
|
3427 |
),
|
3428 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3429 |
'fieldset' => array(
|
3430 |
array(
|
3431 |
'attr_spec_list' => array(
|
3432 |
+
'[disabled]' => array(),
|
3433 |
'disabled' => array(),
|
3434 |
+
'name' => array(
|
3435 |
+
'blacklisted_value_regex' => '(^|\\s)(__amp_\\s*|__count__|__definegetter__|__definesetter__|__lookupgetter__|__lookupsetter__|__nosuchmethod__|__parent__|__proto__|__amp_\\s*|\\$p|\\$proxy|acceptcharset|addeventlistener|appendchild|assignedslot|attachshadow|baseuri|checkvalidity|childelementcount|childnodes|classlist|classname|clientheight|clientleft|clienttop|clientwidth|comparedocumentposition|computedname|computedrole|contenteditable|createshadowroot|enqueaction|firstchild|firstelementchild|getanimations|getattribute|getattributens|getattributenode|getattributenodens|getboundingclientrect|getclientrects|getdestinationinsertionpoints|getelementsbyclassname|getelementsbytagname|getelementsbytagnamens|getrootnode|hasattribute|hasattributens|hasattributes|haschildnodes|haspointercapture|innerhtml|innertext|inputmode|insertadjacentelement|insertadjacenthtml|insertadjacenttext|iscontenteditable|isdefaultnamespace|isequalnode|issamenode|lastchild|lastelementchild|lookupnamespaceuri|namespaceuri|nextelementsibling|nextsibling|nodename|nodetype|nodevalue|offsetheight|offsetleft|offsetparent|offsettop|offsetwidth|outerhtml|outertext|ownerdocument|parentelement|parentnode|previouselementsibling|previoussibling|queryselector|queryselectorall|releasepointercapture|removeattribute|removeattributens|removeattributenode|removechild|removeeventlistener|replacechild|reportvalidity|requestpointerlock|scrollheight|scrollintoview|scrollintoviewifneeded|scrollleft|scrollwidth|setattribute|setattributens|setattributenode|setattributenodens|setpointercapture|shadowroot|stylemap|tabindex|tagname|textcontent|tostring|valueof|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)matchesselector|(webkit|moz|ms|o)requestfullscreen|(webkit|moz|ms|o)requestfullscreen)(\\s|$)',
|
3436 |
+
),
|
3437 |
),
|
3438 |
'tag_spec' => array(),
|
3439 |
|
3458 |
'attr_spec_list' => array(
|
3459 |
'alignment-baseline' => array(),
|
3460 |
'baseline-shift' => array(),
|
|
|
3461 |
'clip' => array(),
|
3462 |
'clip-path' => array(),
|
3463 |
'clip-rule' => array(),
|
3513 |
'stroke-miterlimit' => array(),
|
3514 |
'stroke-opacity' => array(),
|
3515 |
'stroke-width' => array(),
|
3516 |
+
'style' => array(
|
3517 |
+
'blacklisted_value_regex' => '!important',
|
3518 |
+
),
|
3519 |
'text-anchor' => array(),
|
3520 |
'text-decoration' => array(),
|
3521 |
'text-rendering' => array(),
|
3522 |
'unicode-bidi' => array(),
|
3523 |
+
'vector-effect' => array(),
|
3524 |
'visibility' => array(),
|
3525 |
'width' => array(),
|
3526 |
'word-spacing' => array(),
|
3529 |
'xlink:actuate' => array(),
|
3530 |
'xlink:arcrole' => array(),
|
3531 |
'xlink:href' => array(
|
3532 |
+
'alternative_names' => array(
|
3533 |
+
'href',
|
3534 |
+
),
|
3535 |
+
'allow_empty' => false,
|
3536 |
+
'allow_relative' => true,
|
3537 |
+
'allowed_protocol' => array(
|
3538 |
+
'http',
|
3539 |
+
'https',
|
3540 |
+
),
|
3541 |
),
|
3542 |
'xlink:role' => array(),
|
3543 |
'xlink:show' => array(),
|
3544 |
'xlink:title' => array(),
|
3545 |
'xlink:type' => array(),
|
|
|
3546 |
'xml:lang' => array(),
|
3547 |
'xml:space' => array(),
|
3548 |
'xmlns' => array(),
|
3550 |
'y' => array(),
|
3551 |
),
|
3552 |
'tag_spec' => array(
|
3553 |
+
'html_format' => array(
|
3554 |
+
'amp',
|
3555 |
+
'amp4ads',
|
3556 |
+
),
|
3557 |
'mandatory_ancestor' => 'svg',
|
3558 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
3559 |
),
|
3560 |
|
3561 |
),
|
3572 |
'attr_spec_list' => array(
|
3573 |
'alignment-baseline' => array(),
|
3574 |
'baseline-shift' => array(),
|
|
|
3575 |
'clip' => array(),
|
3576 |
'clip-path' => array(),
|
3577 |
'clip-rule' => array(),
|
3626 |
'stroke-miterlimit' => array(),
|
3627 |
'stroke-opacity' => array(),
|
3628 |
'stroke-width' => array(),
|
3629 |
+
'style' => array(
|
3630 |
+
'blacklisted_value_regex' => '!important',
|
3631 |
+
),
|
3632 |
'systemlanguage' => array(),
|
3633 |
'text-anchor' => array(),
|
3634 |
'text-decoration' => array(),
|
3635 |
'text-rendering' => array(),
|
3636 |
'transform' => array(),
|
3637 |
'unicode-bidi' => array(),
|
3638 |
+
'vector-effect' => array(),
|
3639 |
'visibility' => array(),
|
3640 |
'width' => array(),
|
3641 |
'word-spacing' => array(),
|
3642 |
'writing-mode' => array(),
|
3643 |
'x' => array(),
|
|
|
3644 |
'xml:lang' => array(),
|
3645 |
'xml:space' => array(),
|
3646 |
'xmlns' => array(),
|
3648 |
'y' => array(),
|
3649 |
),
|
3650 |
'tag_spec' => array(
|
3651 |
+
'html_format' => array(
|
3652 |
+
'amp',
|
3653 |
+
'amp4ads',
|
3654 |
+
),
|
3655 |
'mandatory_ancestor' => 'svg',
|
3656 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
3657 |
),
|
3658 |
|
3659 |
),
|
3670 |
'allowed_protocol' => array(
|
3671 |
'https',
|
3672 |
),
|
|
|
|
|
|
|
3673 |
),
|
3674 |
'action-xhr' => array(
|
3675 |
'blacklisted_value_regex' => '__amp_source_origin',
|
3677 |
'allowed_protocol' => array(
|
3678 |
'https',
|
3679 |
),
|
|
|
|
|
|
|
3680 |
),
|
3681 |
'autocomplete' => array(),
|
3682 |
'custom-validation-reporting' => array(
|
3683 |
+
'value_regex' => '(show-first-on-submit|show-all-on-submit|as-you-go|interact-and-submit)',
|
3684 |
),
|
3685 |
'enctype' => array(),
|
3686 |
'method' => array(
|
3692 |
'mandatory' => true,
|
3693 |
'value_regex_casei' => '(_blank|_top)',
|
3694 |
),
|
3695 |
+
'verify-xhr' => array(
|
3696 |
+
'blacklisted_value_regex' => '__amp_source_origin',
|
3697 |
+
'allow_relative' => true,
|
3698 |
+
'allowed_protocol' => array(
|
3699 |
+
'https',
|
3700 |
+
),
|
3701 |
+
),
|
3702 |
),
|
3703 |
'tag_spec' => array(
|
|
|
|
|
|
|
3704 |
'disallowed_ancestor' => array(
|
3705 |
'amp-app-banner',
|
3706 |
),
|
3707 |
+
'html_format' => array(
|
3708 |
+
'amp',
|
3709 |
+
'amp4ads',
|
3710 |
+
),
|
3711 |
'spec_name' => 'form [method=get]',
|
|
|
3712 |
),
|
3713 |
|
3714 |
),
|
3723 |
'allowed_protocol' => array(
|
3724 |
'https',
|
3725 |
),
|
|
|
|
|
|
|
3726 |
),
|
3727 |
'autocomplete' => array(),
|
3728 |
'custom-validation-reporting' => array(
|
3730 |
),
|
3731 |
'enctype' => array(),
|
3732 |
'method' => array(
|
|
|
3733 |
'mandatory' => true,
|
3734 |
'value_casei' => 'post',
|
3735 |
),
|
3739 |
'mandatory' => true,
|
3740 |
'value_regex_casei' => '(_blank|_top)',
|
3741 |
),
|
3742 |
+
'verify-xhr' => array(
|
3743 |
+
'blacklisted_value_regex' => '__amp_source_origin',
|
3744 |
+
'allow_relative' => true,
|
3745 |
+
'allowed_protocol' => array(
|
3746 |
+
'https',
|
3747 |
+
),
|
3748 |
+
),
|
3749 |
),
|
3750 |
'tag_spec' => array(
|
|
|
|
|
|
|
3751 |
'disallowed_ancestor' => array(
|
3752 |
'amp-app-banner',
|
3753 |
),
|
3754 |
+
'html_format' => array(
|
3755 |
+
'amp',
|
3756 |
+
'amp4ads',
|
3757 |
+
),
|
3758 |
'spec_name' => 'form [method=post]',
|
|
|
3759 |
),
|
3760 |
|
3761 |
),
|
3765 |
'attr_spec_list' => array(
|
3766 |
'alignment-baseline' => array(),
|
3767 |
'baseline-shift' => array(),
|
|
|
3768 |
'clip' => array(),
|
3769 |
'clip-path' => array(),
|
3770 |
'clip-rule' => array(),
|
3818 |
'stroke-miterlimit' => array(),
|
3819 |
'stroke-opacity' => array(),
|
3820 |
'stroke-width' => array(),
|
3821 |
+
'style' => array(
|
3822 |
+
'blacklisted_value_regex' => '!important',
|
3823 |
+
),
|
3824 |
'systemlanguage' => array(),
|
3825 |
'text-anchor' => array(),
|
3826 |
'text-decoration' => array(),
|
3827 |
'text-rendering' => array(),
|
3828 |
'transform' => array(),
|
3829 |
'unicode-bidi' => array(),
|
3830 |
+
'vector-effect' => array(),
|
3831 |
'visibility' => array(),
|
3832 |
'word-spacing' => array(),
|
3833 |
'writing-mode' => array(),
|
|
|
3834 |
'xml:lang' => array(),
|
3835 |
'xml:space' => array(),
|
3836 |
'xmlns' => array(),
|
3837 |
'xmlns:xlink' => array(),
|
3838 |
),
|
3839 |
'tag_spec' => array(
|
3840 |
+
'html_format' => array(
|
3841 |
+
'amp',
|
3842 |
+
'amp4ads',
|
3843 |
+
),
|
3844 |
'mandatory_ancestor' => 'svg',
|
3845 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
3846 |
),
|
3847 |
|
3848 |
),
|
3853 |
'alignment-baseline' => array(),
|
3854 |
'arabic-form' => array(),
|
3855 |
'baseline-shift' => array(),
|
|
|
3856 |
'clip' => array(),
|
3857 |
'clip-path' => array(),
|
3858 |
'clip-rule' => array(),
|
3907 |
'stroke-miterlimit' => array(),
|
3908 |
'stroke-opacity' => array(),
|
3909 |
'stroke-width' => array(),
|
3910 |
+
'style' => array(
|
3911 |
+
'blacklisted_value_regex' => '!important',
|
3912 |
+
),
|
3913 |
'text-anchor' => array(),
|
3914 |
'text-decoration' => array(),
|
3915 |
'text-rendering' => array(),
|
3916 |
'unicode' => array(),
|
3917 |
'unicode-bidi' => array(),
|
3918 |
+
'vector-effect' => array(),
|
3919 |
'vert-adv-y' => array(),
|
3920 |
'vert-origin-x' => array(),
|
3921 |
'vert-origin-y' => array(),
|
3922 |
'visibility' => array(),
|
3923 |
'word-spacing' => array(),
|
3924 |
'writing-mode' => array(),
|
|
|
3925 |
'xml:lang' => array(),
|
3926 |
'xml:space' => array(),
|
3927 |
'xmlns' => array(),
|
3928 |
'xmlns:xlink' => array(),
|
3929 |
),
|
3930 |
'tag_spec' => array(
|
3931 |
+
'html_format' => array(
|
3932 |
+
'amp',
|
3933 |
+
'amp4ads',
|
3934 |
+
),
|
3935 |
'mandatory_ancestor' => 'svg',
|
3936 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
3937 |
),
|
3938 |
|
3939 |
),
|
3943 |
'attr_spec_list' => array(
|
3944 |
'alignment-baseline' => array(),
|
3945 |
'baseline-shift' => array(),
|
|
|
3946 |
'clip' => array(),
|
3947 |
'clip-path' => array(),
|
3948 |
'clip-rule' => array(),
|
3997 |
'stroke-miterlimit' => array(),
|
3998 |
'stroke-opacity' => array(),
|
3999 |
'stroke-width' => array(),
|
4000 |
+
'style' => array(
|
4001 |
+
'blacklisted_value_regex' => '!important',
|
4002 |
+
),
|
4003 |
'text-anchor' => array(),
|
4004 |
'text-decoration' => array(),
|
4005 |
'text-rendering' => array(),
|
4006 |
'unicode-bidi' => array(),
|
4007 |
+
'vector-effect' => array(),
|
4008 |
'visibility' => array(),
|
4009 |
'word-spacing' => array(),
|
4010 |
'writing-mode' => array(),
|
4012 |
'xlink:actuate' => array(),
|
4013 |
'xlink:arcrole' => array(),
|
4014 |
'xlink:href' => array(
|
4015 |
+
'alternative_names' => array(
|
4016 |
+
'href',
|
4017 |
+
),
|
4018 |
+
'allow_empty' => false,
|
4019 |
+
'allow_relative' => true,
|
4020 |
+
'allowed_protocol' => array(
|
4021 |
+
'http',
|
4022 |
+
'https',
|
4023 |
+
),
|
4024 |
),
|
4025 |
'xlink:role' => array(),
|
4026 |
'xlink:show' => array(),
|
4027 |
'xlink:title' => array(),
|
4028 |
'xlink:type' => array(),
|
|
|
4029 |
'xml:lang' => array(),
|
4030 |
'xml:space' => array(),
|
4031 |
'xmlns' => array(),
|
4033 |
'y' => array(),
|
4034 |
),
|
4035 |
'tag_spec' => array(
|
4036 |
+
'html_format' => array(
|
4037 |
+
'amp',
|
4038 |
+
'amp4ads',
|
4039 |
+
),
|
4040 |
'mandatory_ancestor' => 'svg',
|
4041 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
4042 |
),
|
4043 |
|
4044 |
),
|
4121 |
'g1' => array(),
|
4122 |
'g2' => array(),
|
4123 |
'k' => array(),
|
4124 |
+
'style' => array(
|
4125 |
+
'blacklisted_value_regex' => '!important',
|
4126 |
+
),
|
4127 |
'u1' => array(),
|
4128 |
'u2' => array(),
|
|
|
4129 |
'xml:lang' => array(),
|
4130 |
'xml:space' => array(),
|
4131 |
'xmlns' => array(),
|
4132 |
'xmlns:xlink' => array(),
|
4133 |
),
|
4134 |
'tag_spec' => array(
|
4135 |
+
'html_format' => array(
|
4136 |
+
'amp',
|
4137 |
+
'amp4ads',
|
4138 |
+
),
|
4139 |
'mandatory_ancestor' => 'svg',
|
4140 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
4141 |
),
|
4142 |
|
4143 |
),
|
4156 |
|
4157 |
),
|
4158 |
),
|
4159 |
+
'iframe' => array(
|
4160 |
+
array(
|
4161 |
+
'attr_spec_list' => array(
|
4162 |
+
'frameborder' => array(
|
4163 |
+
'value_regex' => '0|1',
|
4164 |
+
),
|
4165 |
+
'height' => array(),
|
4166 |
+
'name' => array(),
|
4167 |
+
'referrerpolicy' => array(),
|
4168 |
+
'resizable' => array(
|
4169 |
+
'value' => '',
|
4170 |
+
),
|
4171 |
+
'sandbox' => array(),
|
4172 |
+
'scrolling' => array(
|
4173 |
+
'value_regex' => 'auto|yes|no',
|
4174 |
+
),
|
4175 |
+
'src' => array(
|
4176 |
+
'blacklisted_value_regex' => '__amp_source_origin',
|
4177 |
+
'allow_relative' => false,
|
4178 |
+
'allowed_protocol' => array(
|
4179 |
+
'data',
|
4180 |
+
'https',
|
4181 |
+
),
|
4182 |
+
),
|
4183 |
+
'srcdoc' => array(),
|
4184 |
+
'width' => array(),
|
4185 |
+
),
|
4186 |
+
'tag_spec' => array(
|
4187 |
+
'html_format' => array(
|
4188 |
+
'amp',
|
4189 |
+
),
|
4190 |
+
'mandatory_ancestor' => 'noscript',
|
4191 |
+
'mandatory_ancestor_suggested_alternative' => 'amp-iframe',
|
4192 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-iframe',
|
4193 |
+
),
|
4194 |
+
|
4195 |
+
),
|
4196 |
+
),
|
4197 |
'image' => array(
|
4198 |
array(
|
4199 |
'attr_spec_list' => array(
|
4200 |
'alignment-baseline' => array(),
|
4201 |
'baseline-shift' => array(),
|
|
|
4202 |
'clip' => array(),
|
4203 |
'clip-path' => array(),
|
4204 |
'clip-rule' => array(),
|
4254 |
'stroke-miterlimit' => array(),
|
4255 |
'stroke-opacity' => array(),
|
4256 |
'stroke-width' => array(),
|
4257 |
+
'style' => array(
|
4258 |
+
'blacklisted_value_regex' => '!important',
|
4259 |
+
),
|
4260 |
'systemlanguage' => array(),
|
4261 |
'text-anchor' => array(),
|
4262 |
'text-decoration' => array(),
|
4263 |
'text-rendering' => array(),
|
4264 |
'transform' => array(),
|
4265 |
'unicode-bidi' => array(),
|
4266 |
+
'vector-effect' => array(),
|
4267 |
'visibility' => array(),
|
4268 |
'width' => array(),
|
4269 |
'word-spacing' => array(),
|
4272 |
'xlink:actuate' => array(),
|
4273 |
'xlink:arcrole' => array(),
|
4274 |
'xlink:href' => array(
|
4275 |
+
'alternative_names' => array(
|
4276 |
+
'href',
|
4277 |
+
),
|
4278 |
'blacklisted_value_regex' => '(^|\\s)data:image\\/svg\\+xml',
|
4279 |
'allow_empty' => false,
|
4280 |
+
'allow_relative' => true,
|
4281 |
'allowed_protocol' => array(
|
4282 |
'data',
|
4283 |
+
'http',
|
4284 |
+
'https',
|
4285 |
),
|
4286 |
),
|
4287 |
'xlink:role' => array(),
|
4288 |
'xlink:show' => array(),
|
4289 |
'xlink:title' => array(),
|
4290 |
'xlink:type' => array(),
|
|
|
4291 |
'xml:lang' => array(),
|
4292 |
'xml:space' => array(),
|
4293 |
'xmlns' => array(),
|
4295 |
'y' => array(),
|
4296 |
),
|
4297 |
'tag_spec' => array(
|
4298 |
+
'html_format' => array(
|
4299 |
+
'amp',
|
4300 |
+
'amp4ads',
|
4301 |
+
),
|
4302 |
'mandatory_ancestor' => 'svg',
|
4303 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
4304 |
),
|
4305 |
|
4306 |
),
|
4340 |
),
|
4341 |
'mandatory_ancestor' => 'noscript',
|
4342 |
'mandatory_ancestor_suggested_alternative' => 'amp-img',
|
4343 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-img',
|
4344 |
),
|
4345 |
|
4346 |
),
|
4348 |
'input' => array(
|
4349 |
array(
|
4350 |
'attr_spec_list' => array(
|
4351 |
+
'[accept]' => array(),
|
4352 |
+
'[accesskey]' => array(),
|
4353 |
+
'[autocomplete]' => array(),
|
4354 |
+
'[checked]' => array(),
|
4355 |
+
'[disabled]' => array(),
|
4356 |
+
'[height]' => array(),
|
4357 |
+
'[inputmode]' => array(),
|
4358 |
+
'[max]' => array(),
|
4359 |
+
'[maxlength]' => array(),
|
4360 |
+
'[min]' => array(),
|
4361 |
+
'[minlength]' => array(),
|
4362 |
+
'[multiple]' => array(),
|
4363 |
+
'[pattern]' => array(),
|
4364 |
+
'[placeholder]' => array(),
|
4365 |
+
'[readonly]' => array(),
|
4366 |
+
'[required]' => array(),
|
4367 |
+
'[selectiondirection]' => array(),
|
4368 |
+
'[size]' => array(),
|
4369 |
+
'[spellcheck]' => array(),
|
4370 |
+
'[step]' => array(),
|
4371 |
+
'[type]' => array(),
|
4372 |
+
'[value]' => array(),
|
4373 |
+
'[width]' => array(),
|
4374 |
'accept' => array(),
|
4375 |
'accesskey' => array(),
|
4376 |
'autocomplete' => array(),
|
4377 |
'autofocus' => array(),
|
4378 |
'checked' => array(),
|
|
|
4379 |
'disabled' => array(),
|
4380 |
'height' => array(),
|
4381 |
'inputmode' => array(),
|
4386 |
'minlength' => array(),
|
4387 |
'multiple' => array(),
|
4388 |
'name' => array(
|
4389 |
+
'blacklisted_value_regex' => '(^|\\s)(__amp_\\s*|__count__|__definegetter__|__definesetter__|__lookupgetter__|__lookupsetter__|__nosuchmethod__|__parent__|__proto__|__amp_\\s*|\\$p|\\$proxy|acceptcharset|addeventlistener|appendchild|assignedslot|attachshadow|baseuri|checkvalidity|childelementcount|childnodes|classlist|classname|clientheight|clientleft|clienttop|clientwidth|comparedocumentposition|computedname|computedrole|contenteditable|createshadowroot|enqueaction|firstchild|firstelementchild|getanimations|getattribute|getattributens|getattributenode|getattributenodens|getboundingclientrect|getclientrects|getdestinationinsertionpoints|getelementsbyclassname|getelementsbytagname|getelementsbytagnamens|getrootnode|hasattribute|hasattributens|hasattributes|haschildnodes|haspointercapture|innerhtml|innertext|inputmode|insertadjacentelement|insertadjacenthtml|insertadjacenttext|iscontenteditable|isdefaultnamespace|isequalnode|issamenode|lastchild|lastelementchild|lookupnamespaceuri|namespaceuri|nextelementsibling|nextsibling|nodename|nodetype|nodevalue|offsetheight|offsetleft|offsetparent|offsettop|offsetwidth|outerhtml|outertext|ownerdocument|parentelement|parentnode|previouselementsibling|previoussibling|queryselector|queryselectorall|releasepointercapture|removeattribute|removeattributens|removeattributenode|removechild|removeeventlistener|replacechild|reportvalidity|requestpointerlock|scrollheight|scrollintoview|scrollintoviewifneeded|scrollleft|scrollwidth|setattribute|setattributens|setattributenode|setattributenodens|setpointercapture|shadowroot|stylemap|tabindex|tagname|textcontent|tostring|valueof|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)matchesselector|(webkit|moz|ms|o)requestfullscreen|(webkit|moz|ms|o)requestfullscreen)(\\s|$)',
|
4390 |
),
|
4391 |
'pattern' => array(),
|
4392 |
'placeholder' => array(),
|
4404 |
'width' => array(),
|
4405 |
),
|
4406 |
'tag_spec' => array(
|
4407 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form',
|
4408 |
),
|
4409 |
|
4410 |
),
|
4414 |
'attr_spec_list' => array(
|
4415 |
'cite' => array(
|
4416 |
'blacklisted_value_regex' => '__amp_source_origin',
|
4417 |
+
'allow_empty' => true,
|
4418 |
'allow_relative' => true,
|
4419 |
'allowed_protocol' => array(
|
|
|
|
|
4420 |
'http',
|
4421 |
'https',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4422 |
),
|
4423 |
),
|
4424 |
'datetime' => array(),
|
4440 |
'for' => array(),
|
4441 |
),
|
4442 |
'tag_spec' => array(
|
4443 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form',
|
4444 |
),
|
4445 |
|
4446 |
),
|
4468 |
'attr_spec_list' => array(
|
4469 |
'alignment-baseline' => array(),
|
4470 |
'baseline-shift' => array(),
|
|
|
4471 |
'clip' => array(),
|
4472 |
'clip-path' => array(),
|
4473 |
'clip-rule' => array(),
|
4522 |
'stroke-miterlimit' => array(),
|
4523 |
'stroke-opacity' => array(),
|
4524 |
'stroke-width' => array(),
|
4525 |
+
'style' => array(
|
4526 |
+
'blacklisted_value_regex' => '!important',
|
4527 |
+
),
|
4528 |
'systemlanguage' => array(),
|
4529 |
'text-anchor' => array(),
|
4530 |
'text-decoration' => array(),
|
4531 |
'text-rendering' => array(),
|
4532 |
'transform' => array(),
|
4533 |
'unicode-bidi' => array(),
|
4534 |
+
'vector-effect' => array(),
|
4535 |
'visibility' => array(),
|
4536 |
'word-spacing' => array(),
|
4537 |
'writing-mode' => array(),
|
4538 |
'x1' => array(),
|
4539 |
'x2' => array(),
|
|
|
4540 |
'xml:lang' => array(),
|
4541 |
'xml:space' => array(),
|
4542 |
'xmlns' => array(),
|
4545 |
'y2' => array(),
|
4546 |
),
|
4547 |
'tag_spec' => array(
|
4548 |
+
'html_format' => array(
|
4549 |
+
'amp',
|
4550 |
+
'amp4ads',
|
4551 |
+
),
|
4552 |
'mandatory_ancestor' => 'svg',
|
4553 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
4554 |
),
|
4555 |
|
4556 |
),
|
4560 |
'attr_spec_list' => array(
|
4561 |
'alignment-baseline' => array(),
|
4562 |
'baseline-shift' => array(),
|
|
|
4563 |
'clip' => array(),
|
4564 |
'clip-path' => array(),
|
4565 |
'clip-rule' => array(),
|
4614 |
'stroke-miterlimit' => array(),
|
4615 |
'stroke-opacity' => array(),
|
4616 |
'stroke-width' => array(),
|
4617 |
+
'style' => array(
|
4618 |
+
'blacklisted_value_regex' => '!important',
|
4619 |
+
),
|
4620 |
'text-anchor' => array(),
|
4621 |
'text-decoration' => array(),
|
4622 |
'text-rendering' => array(),
|
4623 |
'unicode-bidi' => array(),
|
4624 |
+
'vector-effect' => array(),
|
4625 |
'visibility' => array(),
|
4626 |
'word-spacing' => array(),
|
4627 |
'writing-mode' => array(),
|
4630 |
'xlink:actuate' => array(),
|
4631 |
'xlink:arcrole' => array(),
|
4632 |
'xlink:href' => array(
|
4633 |
+
'alternative_names' => array(
|
4634 |
+
'href',
|
4635 |
+
),
|
4636 |
+
'allow_empty' => false,
|
4637 |
+
'allow_relative' => true,
|
4638 |
+
'allowed_protocol' => array(
|
4639 |
+
'http',
|
4640 |
+
'https',
|
4641 |
+
),
|
4642 |
),
|
4643 |
'xlink:role' => array(),
|
4644 |
'xlink:show' => array(),
|
4645 |
'xlink:title' => array(),
|
4646 |
'xlink:type' => array(),
|
|
|
4647 |
'xml:lang' => array(),
|
4648 |
'xml:space' => array(),
|
4649 |
'xmlns' => array(),
|
4652 |
'y2' => array(),
|
4653 |
),
|
4654 |
'tag_spec' => array(
|
4655 |
+
'html_format' => array(
|
4656 |
+
'amp',
|
4657 |
+
'amp4ads',
|
4658 |
+
),
|
4659 |
'mandatory_ancestor' => 'svg',
|
4660 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
4661 |
),
|
4662 |
|
4663 |
),
|
4684 |
'disallowed_ancestor' => array(
|
4685 |
'template',
|
4686 |
),
|
4687 |
+
'html_format' => array(
|
4688 |
+
'amp',
|
4689 |
+
'amp4ads',
|
4690 |
+
),
|
4691 |
'spec_name' => 'link rel=',
|
4692 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
|
4693 |
),
|
4694 |
|
4695 |
),
|
4704 |
),
|
4705 |
'hreflang' => array(),
|
4706 |
'itemprop' => array(
|
|
|
4707 |
'mandatory' => true,
|
4708 |
'value_casei' => 'sameas',
|
4709 |
),
|
4713 |
'type' => array(),
|
4714 |
),
|
4715 |
'tag_spec' => array(
|
4716 |
+
'html_format' => array(
|
4717 |
+
'amp',
|
4718 |
+
'amp4ads',
|
4719 |
+
),
|
4720 |
'spec_name' => 'link itemprop=sameas',
|
4721 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
|
4722 |
),
|
4723 |
|
4724 |
),
|
4741 |
'type' => array(),
|
4742 |
),
|
4743 |
'tag_spec' => array(
|
4744 |
+
'html_format' => array(
|
4745 |
+
'amp',
|
4746 |
+
'amp4ads',
|
4747 |
+
),
|
4748 |
'spec_name' => 'link itemprop=',
|
4749 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
|
4750 |
+
),
|
4751 |
+
|
4752 |
+
),
|
4753 |
+
array(
|
4754 |
+
'attr_spec_list' => array(
|
4755 |
+
'charset' => array(
|
4756 |
+
'value_casei' => 'utf-8',
|
4757 |
+
),
|
4758 |
+
'color' => array(),
|
4759 |
+
'href' => array(
|
4760 |
+
'mandatory' => true,
|
4761 |
+
),
|
4762 |
+
'hreflang' => array(),
|
4763 |
+
'media' => array(),
|
4764 |
+
'property' => array(
|
4765 |
+
'mandatory' => true,
|
4766 |
+
),
|
4767 |
+
'sizes' => array(),
|
4768 |
+
'target' => array(),
|
4769 |
+
'type' => array(),
|
4770 |
+
),
|
4771 |
+
'tag_spec' => array(
|
4772 |
+
'html_format' => array(
|
4773 |
+
'amp',
|
4774 |
+
'amp4ads',
|
4775 |
+
),
|
4776 |
+
'spec_name' => 'link property=',
|
4777 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
|
4778 |
),
|
4779 |
|
4780 |
),
|
4809 |
'attr_spec_list' => array(
|
4810 |
'alignment-baseline' => array(),
|
4811 |
'baseline-shift' => array(),
|
|
|
4812 |
'clip' => array(),
|
4813 |
'clip-path' => array(),
|
4814 |
'clip-rule' => array(),
|
4867 |
'stroke-miterlimit' => array(),
|
4868 |
'stroke-opacity' => array(),
|
4869 |
'stroke-width' => array(),
|
4870 |
+
'style' => array(
|
4871 |
+
'blacklisted_value_regex' => '!important',
|
4872 |
+
),
|
4873 |
'text-anchor' => array(),
|
4874 |
'text-decoration' => array(),
|
4875 |
'text-rendering' => array(),
|
4876 |
'transform' => array(),
|
4877 |
'unicode-bidi' => array(),
|
4878 |
+
'vector-effect' => array(),
|
4879 |
'viewbox' => array(),
|
4880 |
'visibility' => array(),
|
4881 |
'word-spacing' => array(),
|
4882 |
'writing-mode' => array(),
|
|
|
4883 |
'xml:lang' => array(),
|
4884 |
'xml:space' => array(),
|
4885 |
'xmlns' => array(),
|
4886 |
'xmlns:xlink' => array(),
|
4887 |
),
|
4888 |
'tag_spec' => array(
|
4889 |
+
'html_format' => array(
|
4890 |
+
'amp',
|
4891 |
+
'amp4ads',
|
4892 |
+
),
|
4893 |
'mandatory_ancestor' => 'svg',
|
4894 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
4895 |
),
|
4896 |
|
4897 |
),
|
4901 |
'attr_spec_list' => array(
|
4902 |
'alignment-baseline' => array(),
|
4903 |
'baseline-shift' => array(),
|
|
|
4904 |
'clip' => array(),
|
4905 |
'clip-path' => array(),
|
4906 |
'clip-rule' => array(),
|
4957 |
'stroke-miterlimit' => array(),
|
4958 |
'stroke-opacity' => array(),
|
4959 |
'stroke-width' => array(),
|
4960 |
+
'style' => array(
|
4961 |
+
'blacklisted_value_regex' => '!important',
|
4962 |
+
),
|
4963 |
'systemlanguage' => array(),
|
4964 |
'text-anchor' => array(),
|
4965 |
'text-decoration' => array(),
|
4966 |
'text-rendering' => array(),
|
4967 |
'unicode-bidi' => array(),
|
4968 |
+
'vector-effect' => array(),
|
4969 |
'visibility' => array(),
|
4970 |
'width' => array(),
|
4971 |
'word-spacing' => array(),
|
4972 |
'writing-mode' => array(),
|
4973 |
'x' => array(),
|
|
|
4974 |
'xml:lang' => array(),
|
4975 |
'xml:space' => array(),
|
4976 |
'xmlns' => array(),
|
4978 |
'y' => array(),
|
4979 |
),
|
4980 |
'tag_spec' => array(
|
4981 |
+
'html_format' => array(
|
4982 |
+
'amp',
|
4983 |
+
'amp4ads',
|
4984 |
+
),
|
4985 |
'mandatory_ancestor' => 'svg',
|
4986 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
4987 |
),
|
4988 |
|
4989 |
),
|
4993 |
'attr_spec_list' => array(
|
4994 |
'content' => array(
|
4995 |
'mandatory' => true,
|
4996 |
+
'chrome' => array(
|
4997 |
+
'value',
|
4998 |
+
),
|
4999 |
+
'ie' => array(
|
5000 |
+
'value',
|
5001 |
+
),
|
5002 |
),
|
5003 |
'http-equiv' => array(
|
|
|
5004 |
'mandatory' => true,
|
5005 |
'value_casei' => 'x-ua-compatible',
|
5006 |
),
|
5007 |
),
|
5008 |
'tag_spec' => array(
|
5009 |
+
'html_format' => array(
|
5010 |
+
'amp',
|
5011 |
+
'amp4ads',
|
5012 |
+
),
|
5013 |
+
'mandatory_ancestor' => 'head',
|
5014 |
'spec_name' => 'meta http-equiv=x-ua-compatible',
|
5015 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
|
5016 |
),
|
5017 |
|
5018 |
),
|
5021 |
'content' => array(),
|
5022 |
'itemprop' => array(),
|
5023 |
'name' => array(
|
5024 |
+
'blacklisted_value_regex' => '(^|\\s)(amp-.*|amp4ads-.*|apple-itunes-app|content-disposition|revisit-after|viewport)(\\s|$)',
|
5025 |
),
|
5026 |
'property' => array(),
|
5027 |
),
|
5028 |
'tag_spec' => array(
|
5029 |
+
'html_format' => array(
|
5030 |
+
'amp',
|
5031 |
+
'amp4ads',
|
5032 |
+
),
|
5033 |
'spec_name' => 'meta name= and content=',
|
5034 |
),
|
5035 |
|
5041 |
'value_casei' => 'text/html; charset=utf-8',
|
5042 |
),
|
5043 |
'http-equiv' => array(
|
|
|
5044 |
'mandatory' => true,
|
5045 |
'value_casei' => 'content-type',
|
5046 |
),
|
5047 |
),
|
5048 |
'tag_spec' => array(
|
5049 |
+
'html_format' => array(
|
5050 |
+
'amp',
|
5051 |
+
'amp4ads',
|
5052 |
+
),
|
5053 |
+
'mandatory_ancestor' => 'head',
|
5054 |
'spec_name' => 'meta http-equiv=content-type',
|
5055 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
|
5056 |
),
|
5057 |
|
5058 |
),
|
5062 |
'mandatory' => true,
|
5063 |
),
|
5064 |
'http-equiv' => array(
|
|
|
5065 |
'mandatory' => true,
|
5066 |
'value_casei' => 'content-language',
|
5067 |
),
|
5068 |
),
|
5069 |
'tag_spec' => array(
|
5070 |
+
'html_format' => array(
|
5071 |
+
'amp',
|
5072 |
+
'amp4ads',
|
5073 |
+
),
|
5074 |
+
'mandatory_ancestor' => 'head',
|
5075 |
'spec_name' => 'meta http-equiv=content-language',
|
5076 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
|
5077 |
),
|
5078 |
|
5079 |
),
|
5083 |
'mandatory' => true,
|
5084 |
),
|
5085 |
'http-equiv' => array(
|
|
|
5086 |
'mandatory' => true,
|
5087 |
'value_casei' => 'pics-label',
|
5088 |
),
|
5089 |
),
|
5090 |
'tag_spec' => array(
|
5091 |
+
'html_format' => array(
|
5092 |
+
'amp',
|
5093 |
+
'amp4ads',
|
5094 |
+
),
|
5095 |
+
'mandatory_ancestor' => 'head',
|
5096 |
'spec_name' => 'meta http-equiv=pics-label',
|
5097 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
|
5098 |
),
|
5099 |
|
5100 |
),
|
5104 |
'mandatory' => true,
|
5105 |
),
|
5106 |
'http-equiv' => array(
|
|
|
5107 |
'mandatory' => true,
|
5108 |
'value_casei' => 'imagetoolbar',
|
5109 |
),
|
5110 |
),
|
5111 |
'tag_spec' => array(
|
5112 |
+
'html_format' => array(
|
5113 |
+
'amp',
|
5114 |
+
'amp4ads',
|
5115 |
+
),
|
5116 |
+
'mandatory_ancestor' => 'head',
|
5117 |
'spec_name' => 'meta http-equiv=imagetoolbar',
|
5118 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
|
5119 |
),
|
5120 |
|
5121 |
),
|
5126 |
'value_casei' => 'text/css',
|
5127 |
),
|
5128 |
'http-equiv' => array(
|
|
|
5129 |
'mandatory' => true,
|
5130 |
'value_casei' => 'content-style-type',
|
5131 |
),
|
5132 |
),
|
5133 |
'tag_spec' => array(
|
5134 |
+
'html_format' => array(
|
5135 |
+
'amp',
|
5136 |
+
'amp4ads',
|
5137 |
+
),
|
5138 |
+
'mandatory_ancestor' => 'head',
|
5139 |
'spec_name' => 'meta http-equiv=content-style-type',
|
5140 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
|
5141 |
),
|
5142 |
|
5143 |
),
|
5148 |
'value_casei' => 'text/javascript',
|
5149 |
),
|
5150 |
'http-equiv' => array(
|
|
|
5151 |
'mandatory' => true,
|
5152 |
'value_casei' => 'content-script-type',
|
5153 |
),
|
5154 |
),
|
5155 |
'tag_spec' => array(
|
5156 |
+
'html_format' => array(
|
5157 |
+
'amp',
|
5158 |
+
'amp4ads',
|
5159 |
+
),
|
5160 |
+
'mandatory_ancestor' => 'head',
|
5161 |
'spec_name' => 'meta http-equiv=content-script-type',
|
5162 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
|
5163 |
+
),
|
5164 |
+
|
5165 |
+
),
|
5166 |
+
array(
|
5167 |
+
'attr_spec_list' => array(
|
5168 |
+
'content' => array(
|
5169 |
+
'mandatory' => true,
|
5170 |
+
),
|
5171 |
+
'http-equiv' => array(
|
5172 |
+
'mandatory' => true,
|
5173 |
+
'value_casei' => 'origin-trial',
|
5174 |
+
),
|
5175 |
+
),
|
5176 |
+
'tag_spec' => array(
|
5177 |
+
'html_format' => array(
|
5178 |
+
'amp',
|
5179 |
+
'amp4ads',
|
5180 |
+
),
|
5181 |
+
'mandatory_ancestor' => 'head',
|
5182 |
+
'spec_name' => 'meta http-equiv=origin-trial',
|
5183 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
|
5184 |
),
|
5185 |
|
5186 |
),
|
5190 |
'mandatory' => true,
|
5191 |
),
|
5192 |
'http-equiv' => array(
|
|
|
5193 |
'mandatory' => true,
|
5194 |
'value_casei' => 'resource-type',
|
5195 |
),
|
5196 |
),
|
5197 |
'tag_spec' => array(
|
5198 |
+
'html_format' => array(
|
5199 |
+
'amp',
|
5200 |
+
'amp4ads',
|
5201 |
+
),
|
5202 |
+
'mandatory_ancestor' => 'head',
|
5203 |
'spec_name' => 'meta http-equiv=resource-type',
|
5204 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
|
5205 |
+
),
|
5206 |
+
|
5207 |
+
),
|
5208 |
+
),
|
5209 |
+
'metadata' => array(
|
5210 |
+
array(
|
5211 |
+
'attr_spec_list' => array(
|
5212 |
+
'style' => array(
|
5213 |
+
'blacklisted_value_regex' => '!important',
|
5214 |
+
),
|
5215 |
+
'xml:lang' => array(),
|
5216 |
+
'xml:space' => array(),
|
5217 |
+
'xmlns' => array(),
|
5218 |
+
'xmlns:xlink' => array(),
|
5219 |
+
),
|
5220 |
+
'tag_spec' => array(
|
5221 |
+
'html_format' => array(
|
5222 |
+
'amp',
|
5223 |
+
'amp4ads',
|
5224 |
+
),
|
5225 |
+
'mandatory_ancestor' => 'svg',
|
5226 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
5227 |
+
),
|
5228 |
+
|
5229 |
+
),
|
5230 |
+
),
|
5231 |
+
'meter' => array(
|
5232 |
+
array(
|
5233 |
+
'attr_spec_list' => array(
|
5234 |
+
'high' => array(),
|
5235 |
+
'low' => array(),
|
5236 |
+
'max' => array(),
|
5237 |
+
'min' => array(),
|
5238 |
+
'optimum' => array(),
|
5239 |
+
'value' => array(),
|
5240 |
),
|
5241 |
+
'tag_spec' => array(),
|
5242 |
|
5243 |
),
|
5244 |
),
|
5259 |
'tag_spec' => array(),
|
5260 |
|
5261 |
),
|
5262 |
+
array(
|
5263 |
+
'attr_spec_list' => array(
|
5264 |
+
'toolbar' => array(
|
5265 |
+
'mandatory' => true,
|
5266 |
+
),
|
5267 |
+
'toolbar-target' => array(
|
5268 |
+
'mandatory' => true,
|
5269 |
+
),
|
5270 |
+
),
|
5271 |
+
'tag_spec' => array(
|
5272 |
+
'html_format' => array(
|
5273 |
+
'amp',
|
5274 |
+
),
|
5275 |
+
'mandatory_parent' => 'amp-sidebar',
|
5276 |
+
'spec_name' => 'amp-sidebar > nav',
|
5277 |
+
),
|
5278 |
+
|
5279 |
+
),
|
5280 |
),
|
5281 |
'nextid' => array(
|
5282 |
array(
|
5346 |
'optgroup' => array(
|
5347 |
array(
|
5348 |
'attr_spec_list' => array(
|
5349 |
+
'[disabled]' => array(),
|
5350 |
+
'[label]' => array(),
|
5351 |
'disabled' => array(),
|
5352 |
'label' => array(),
|
5353 |
),
|
5354 |
'tag_spec' => array(
|
|
|
|
|
|
|
5355 |
'mandatory_parent' => 'select',
|
5356 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form',
|
5357 |
),
|
5358 |
|
5359 |
),
|
5361 |
'option' => array(
|
5362 |
array(
|
5363 |
'attr_spec_list' => array(
|
5364 |
+
'[disabled]' => array(),
|
5365 |
+
'[label]' => array(),
|
5366 |
+
'[selected]' => array(),
|
5367 |
+
'[value]' => array(),
|
5368 |
'disabled' => array(),
|
5369 |
'label' => array(),
|
5370 |
'selected' => array(),
|
5371 |
'value' => array(),
|
5372 |
),
|
5373 |
'tag_spec' => array(
|
5374 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form',
|
5375 |
+
),
|
5376 |
+
|
5377 |
+
),
|
5378 |
+
),
|
5379 |
+
'output' => array(
|
5380 |
+
array(
|
5381 |
+
'attr_spec_list' => array(
|
5382 |
+
'for' => array(),
|
5383 |
+
'form' => array(),
|
5384 |
+
'name' => array(
|
5385 |
+
'blacklisted_value_regex' => '(^|\\s)(__amp_\\s*|__count__|__definegetter__|__definesetter__|__lookupgetter__|__lookupsetter__|__nosuchmethod__|__parent__|__proto__|__amp_\\s*|\\$p|\\$proxy|acceptcharset|addeventlistener|appendchild|assignedslot|attachshadow|baseuri|checkvalidity|childelementcount|childnodes|classlist|classname|clientheight|clientleft|clienttop|clientwidth|comparedocumentposition|computedname|computedrole|contenteditable|createshadowroot|enqueaction|firstchild|firstelementchild|getanimations|getattribute|getattributens|getattributenode|getattributenodens|getboundingclientrect|getclientrects|getdestinationinsertionpoints|getelementsbyclassname|getelementsbytagname|getelementsbytagnamens|getrootnode|hasattribute|hasattributens|hasattributes|haschildnodes|haspointercapture|innerhtml|innertext|inputmode|insertadjacentelement|insertadjacenthtml|insertadjacenttext|iscontenteditable|isdefaultnamespace|isequalnode|issamenode|lastchild|lastelementchild|lookupnamespaceuri|namespaceuri|nextelementsibling|nextsibling|nodename|nodetype|nodevalue|offsetheight|offsetleft|offsetparent|offsettop|offsetwidth|outerhtml|outertext|ownerdocument|parentelement|parentnode|previouselementsibling|previoussibling|queryselector|queryselectorall|releasepointercapture|removeattribute|removeattributens|removeattributenode|removechild|removeeventlistener|replacechild|reportvalidity|requestpointerlock|scrollheight|scrollintoview|scrollintoviewifneeded|scrollleft|scrollwidth|setattribute|setattributens|setattributenode|setattributenodens|setpointercapture|shadowroot|stylemap|tabindex|tagname|textcontent|tostring|valueof|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)matchesselector|(webkit|moz|ms|o)requestfullscreen|(webkit|moz|ms|o)requestfullscreen)(\\s|$)',
|
5386 |
),
|
|
|
|
|
5387 |
),
|
5388 |
+
'tag_spec' => array(),
|
5389 |
|
5390 |
),
|
5391 |
),
|
5403 |
'attr_spec_list' => array(
|
5404 |
'alignment-baseline' => array(),
|
5405 |
'baseline-shift' => array(),
|
|
|
5406 |
'clip' => array(),
|
5407 |
'clip-path' => array(),
|
5408 |
'clip-rule' => array(),
|
5459 |
'stroke-miterlimit' => array(),
|
5460 |
'stroke-opacity' => array(),
|
5461 |
'stroke-width' => array(),
|
5462 |
+
'style' => array(
|
5463 |
+
'blacklisted_value_regex' => '!important',
|
5464 |
+
),
|
5465 |
'systemlanguage' => array(),
|
5466 |
'text-anchor' => array(),
|
5467 |
'text-decoration' => array(),
|
5468 |
'text-rendering' => array(),
|
5469 |
'transform' => array(),
|
5470 |
'unicode-bidi' => array(),
|
5471 |
+
'vector-effect' => array(),
|
5472 |
'visibility' => array(),
|
5473 |
'word-spacing' => array(),
|
5474 |
'writing-mode' => array(),
|
|
|
5475 |
'xml:lang' => array(),
|
5476 |
'xml:space' => array(),
|
5477 |
'xmlns' => array(),
|
5478 |
'xmlns:xlink' => array(),
|
5479 |
),
|
5480 |
'tag_spec' => array(
|
5481 |
+
'html_format' => array(
|
5482 |
+
'amp',
|
5483 |
+
'amp4ads',
|
5484 |
+
),
|
5485 |
'mandatory_ancestor' => 'svg',
|
5486 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
5487 |
),
|
5488 |
|
5489 |
),
|
5493 |
'attr_spec_list' => array(
|
5494 |
'alignment-baseline' => array(),
|
5495 |
'baseline-shift' => array(),
|
|
|
5496 |
'clip' => array(),
|
5497 |
'clip-path' => array(),
|
5498 |
'clip-rule' => array(),
|
5551 |
'stroke-miterlimit' => array(),
|
5552 |
'stroke-opacity' => array(),
|
5553 |
'stroke-width' => array(),
|
5554 |
+
'style' => array(
|
5555 |
+
'blacklisted_value_regex' => '!important',
|
5556 |
+
),
|
5557 |
'systemlanguage' => array(),
|
5558 |
'text-anchor' => array(),
|
5559 |
'text-decoration' => array(),
|
5560 |
'text-rendering' => array(),
|
5561 |
'unicode-bidi' => array(),
|
5562 |
+
'vector-effect' => array(),
|
5563 |
'viewbox' => array(),
|
5564 |
'visibility' => array(),
|
5565 |
'width' => array(),
|
5569 |
'xlink:actuate' => array(),
|
5570 |
'xlink:arcrole' => array(),
|
5571 |
'xlink:href' => array(
|
5572 |
+
'alternative_names' => array(
|
5573 |
+
'href',
|
5574 |
+
),
|
5575 |
+
'allow_empty' => false,
|
5576 |
+
'allow_relative' => true,
|
5577 |
+
'allowed_protocol' => array(
|
5578 |
+
'http',
|
5579 |
+
'https',
|
5580 |
+
),
|
5581 |
),
|
5582 |
'xlink:role' => array(),
|
5583 |
'xlink:show' => array(),
|
5584 |
'xlink:title' => array(),
|
5585 |
'xlink:type' => array(),
|
|
|
5586 |
'xml:lang' => array(),
|
5587 |
'xml:space' => array(),
|
5588 |
'xmlns' => array(),
|
5590 |
'y' => array(),
|
5591 |
),
|
5592 |
'tag_spec' => array(
|
5593 |
+
'html_format' => array(
|
5594 |
+
'amp',
|
5595 |
+
'amp4ads',
|
5596 |
+
),
|
5597 |
'mandatory_ancestor' => 'svg',
|
5598 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
5599 |
),
|
5600 |
|
5601 |
),
|
5605 |
'attr_spec_list' => array(
|
5606 |
'alignment-baseline' => array(),
|
5607 |
'baseline-shift' => array(),
|
|
|
5608 |
'clip' => array(),
|
5609 |
'clip-path' => array(),
|
5610 |
'clip-rule' => array(),
|
5660 |
'stroke-miterlimit' => array(),
|
5661 |
'stroke-opacity' => array(),
|
5662 |
'stroke-width' => array(),
|
5663 |
+
'style' => array(
|
5664 |
+
'blacklisted_value_regex' => '!important',
|
5665 |
+
),
|
5666 |
'systemlanguage' => array(),
|
5667 |
'text-anchor' => array(),
|
5668 |
'text-decoration' => array(),
|
5669 |
'text-rendering' => array(),
|
5670 |
'transform' => array(),
|
5671 |
'unicode-bidi' => array(),
|
5672 |
+
'vector-effect' => array(),
|
5673 |
'visibility' => array(),
|
5674 |
'word-spacing' => array(),
|
5675 |
'writing-mode' => array(),
|
|
|
5676 |
'xml:lang' => array(),
|
5677 |
'xml:space' => array(),
|
5678 |
'xmlns' => array(),
|
5679 |
'xmlns:xlink' => array(),
|
5680 |
),
|
5681 |
'tag_spec' => array(
|
5682 |
+
'html_format' => array(
|
5683 |
+
'amp',
|
5684 |
+
'amp4ads',
|
5685 |
+
),
|
5686 |
'mandatory_ancestor' => 'svg',
|
5687 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
5688 |
),
|
5689 |
|
5690 |
),
|
5694 |
'attr_spec_list' => array(
|
5695 |
'alignment-baseline' => array(),
|
5696 |
'baseline-shift' => array(),
|
|
|
5697 |
'clip' => array(),
|
5698 |
'clip-path' => array(),
|
5699 |
'clip-rule' => array(),
|
5749 |
'stroke-miterlimit' => array(),
|
5750 |
'stroke-opacity' => array(),
|
5751 |
'stroke-width' => array(),
|
5752 |
+
'style' => array(
|
5753 |
+
'blacklisted_value_regex' => '!important',
|
5754 |
+
),
|
5755 |
'systemlanguage' => array(),
|
5756 |
'text-anchor' => array(),
|
5757 |
'text-decoration' => array(),
|
5758 |
'text-rendering' => array(),
|
5759 |
'transform' => array(),
|
5760 |
'unicode-bidi' => array(),
|
5761 |
+
'vector-effect' => array(),
|
5762 |
'visibility' => array(),
|
5763 |
'word-spacing' => array(),
|
5764 |
'writing-mode' => array(),
|
|
|
5765 |
'xml:lang' => array(),
|
5766 |
'xml:space' => array(),
|
5767 |
'xmlns' => array(),
|
5768 |
'xmlns:xlink' => array(),
|
5769 |
),
|
5770 |
'tag_spec' => array(
|
5771 |
+
'html_format' => array(
|
5772 |
+
'amp',
|
5773 |
+
'amp4ads',
|
5774 |
+
),
|
5775 |
'mandatory_ancestor' => 'svg',
|
5776 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
5777 |
),
|
5778 |
|
5779 |
),
|
5785 |
|
5786 |
),
|
5787 |
),
|
5788 |
+
'progress' => array(
|
5789 |
+
array(
|
5790 |
+
'attr_spec_list' => array(
|
5791 |
+
'max' => array(),
|
5792 |
+
'value' => array(),
|
5793 |
+
),
|
5794 |
+
'tag_spec' => array(),
|
5795 |
+
|
5796 |
+
),
|
5797 |
+
),
|
5798 |
'q' => array(
|
5799 |
array(
|
5800 |
'attr_spec_list' => array(
|
5801 |
'cite' => array(
|
5802 |
'blacklisted_value_regex' => '__amp_source_origin',
|
5803 |
+
'allow_empty' => true,
|
5804 |
'allow_relative' => true,
|
5805 |
'allowed_protocol' => array(
|
|
|
|
|
5806 |
'http',
|
5807 |
'https',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5808 |
),
|
5809 |
),
|
5810 |
),
|
5817 |
'attr_spec_list' => array(
|
5818 |
'alignment-baseline' => array(),
|
5819 |
'baseline-shift' => array(),
|
|
|
5820 |
'clip' => array(),
|
5821 |
'clip-path' => array(),
|
5822 |
'clip-rule' => array(),
|
5846 |
'font-style' => array(),
|
5847 |
'font-variant' => array(),
|
5848 |
'font-weight' => array(),
|
5849 |
+
'fr' => array(),
|
5850 |
'fx' => array(),
|
5851 |
'fy' => array(),
|
5852 |
'glyph-orientation-horizontal' => array(),
|
5877 |
'stroke-miterlimit' => array(),
|
5878 |
'stroke-opacity' => array(),
|
5879 |
'stroke-width' => array(),
|
5880 |
+
'style' => array(
|
5881 |
+
'blacklisted_value_regex' => '!important',
|
5882 |
+
),
|
5883 |
'text-anchor' => array(),
|
5884 |
'text-decoration' => array(),
|
5885 |
'text-rendering' => array(),
|
5886 |
'unicode-bidi' => array(),
|
5887 |
+
'vector-effect' => array(),
|
5888 |
'visibility' => array(),
|
5889 |
'word-spacing' => array(),
|
5890 |
'writing-mode' => array(),
|
5891 |
'xlink:actuate' => array(),
|
5892 |
'xlink:arcrole' => array(),
|
5893 |
'xlink:href' => array(
|
5894 |
+
'alternative_names' => array(
|
5895 |
+
'href',
|
5896 |
+
),
|
5897 |
+
'allow_empty' => false,
|
5898 |
+
'allow_relative' => true,
|
5899 |
+
'allowed_protocol' => array(
|
5900 |
+
'http',
|
5901 |
+
'https',
|
5902 |
+
),
|
5903 |
),
|
5904 |
'xlink:role' => array(),
|
5905 |
'xlink:show' => array(),
|
5906 |
'xlink:title' => array(),
|
5907 |
'xlink:type' => array(),
|
|
|
5908 |
'xml:lang' => array(),
|
5909 |
'xml:space' => array(),
|
5910 |
'xmlns' => array(),
|
5911 |
'xmlns:xlink' => array(),
|
5912 |
),
|
5913 |
'tag_spec' => array(
|
5914 |
+
'html_format' => array(
|
5915 |
+
'amp',
|
5916 |
+
'amp4ads',
|
5917 |
+
),
|
5918 |
'mandatory_ancestor' => 'svg',
|
5919 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
5920 |
),
|
5921 |
|
5922 |
),
|
5933 |
'attr_spec_list' => array(
|
5934 |
'alignment-baseline' => array(),
|
5935 |
'baseline-shift' => array(),
|
|
|
5936 |
'clip' => array(),
|
5937 |
'clip-path' => array(),
|
5938 |
'clip-rule' => array(),
|
5990 |
'stroke-miterlimit' => array(),
|
5991 |
'stroke-opacity' => array(),
|
5992 |
'stroke-width' => array(),
|
5993 |
+
'style' => array(
|
5994 |
+
'blacklisted_value_regex' => '!important',
|
5995 |
+
),
|
5996 |
'systemlanguage' => array(),
|
5997 |
'text-anchor' => array(),
|
5998 |
'text-decoration' => array(),
|
5999 |
'text-rendering' => array(),
|
6000 |
'transform' => array(),
|
6001 |
'unicode-bidi' => array(),
|
6002 |
+
'vector-effect' => array(),
|
6003 |
'visibility' => array(),
|
6004 |
'width' => array(),
|
6005 |
'word-spacing' => array(),
|
6006 |
'writing-mode' => array(),
|
6007 |
'x' => array(),
|
|
|
6008 |
'xml:lang' => array(),
|
6009 |
'xml:space' => array(),
|
6010 |
'xmlns' => array(),
|
6012 |
'y' => array(),
|
6013 |
),
|
6014 |
'tag_spec' => array(
|
6015 |
+
'html_format' => array(
|
6016 |
+
'amp',
|
6017 |
+
'amp4ads',
|
6018 |
+
),
|
6019 |
'mandatory_ancestor' => 'svg',
|
6020 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
6021 |
),
|
6022 |
|
6023 |
),
|
6067 |
'script' => array(
|
6068 |
array(
|
6069 |
'attr_spec_list' => array(
|
6070 |
+
'nonce' => array(),
|
6071 |
'type' => array(
|
|
|
6072 |
'mandatory' => true,
|
6073 |
'value_casei' => 'application/ld+json',
|
6074 |
),
|
6081 |
array(
|
6082 |
'attr_spec_list' => array(
|
6083 |
'type' => array(
|
|
|
6084 |
'mandatory' => true,
|
6085 |
'value_casei' => 'application/json',
|
6086 |
),
|
6088 |
'tag_spec' => array(
|
6089 |
'html_format' => array(
|
6090 |
'amp',
|
|
|
6091 |
),
|
6092 |
+
'mandatory_parent' => 'amp-ima-video',
|
6093 |
+
'spec_name' => 'amp-ima-video > script[type=application/json]',
|
|
|
6094 |
),
|
6095 |
|
6096 |
),
|
6097 |
array(
|
6098 |
'attr_spec_list' => array(
|
6099 |
+
'nonce' => array(),
|
6100 |
+
'type' => array(
|
6101 |
'mandatory' => true,
|
6102 |
+
'value' => 'application/json',
|
6103 |
+
),
|
6104 |
+
),
|
6105 |
+
'tag_spec' => array(
|
6106 |
+
'html_format' => array(
|
6107 |
+
'amp4ads',
|
6108 |
),
|
6109 |
+
'mandatory_parent' => 'amp-ad-exit',
|
6110 |
+
'spec_name' => 'amp-ad-exit configuration json',
|
6111 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad-exit',
|
6112 |
+
),
|
6113 |
+
|
6114 |
+
),
|
6115 |
+
array(
|
6116 |
+
'attr_spec_list' => array(
|
6117 |
+
'nonce' => array(),
|
6118 |
'type' => array(
|
6119 |
'mandatory' => true,
|
6120 |
'value_casei' => 'application/json',
|
6125 |
'amp',
|
6126 |
'amp4ads',
|
6127 |
),
|
6128 |
+
'mandatory_parent' => 'amp-analytics',
|
6129 |
+
'spec_name' => 'amp-analytics extension .json script',
|
6130 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-analytics',
|
6131 |
+
),
|
6132 |
+
|
6133 |
+
),
|
6134 |
+
array(
|
6135 |
+
'attr_spec_list' => array(
|
6136 |
+
'nonce' => array(),
|
6137 |
+
'type' => array(
|
6138 |
+
'mandatory' => true,
|
6139 |
+
'value_casei' => 'application/json',
|
6140 |
+
),
|
6141 |
+
),
|
6142 |
+
'tag_spec' => array(
|
6143 |
+
'mandatory_parent' => 'amp-animation',
|
6144 |
+
'spec_name' => 'amp-animation extension .json script',
|
6145 |
),
|
6146 |
|
6147 |
),
|
6148 |
array(
|
6149 |
'attr_spec_list' => array(
|
6150 |
+
'nonce' => array(),
|
6151 |
'type' => array(
|
|
|
6152 |
'mandatory' => true,
|
6153 |
'value_casei' => 'application/json',
|
6154 |
),
|
6159 |
),
|
6160 |
'mandatory_parent' => 'amp-state',
|
6161 |
'spec_name' => 'amp-bind extension .json script',
|
6162 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-bind',
|
6163 |
),
|
6164 |
|
6165 |
),
|
6166 |
array(
|
6167 |
'attr_spec_list' => array(
|
6168 |
+
'nonce' => array(),
|
6169 |
'type' => array(
|
|
|
6170 |
'mandatory' => true,
|
6171 |
'value_casei' => 'application/json',
|
6172 |
),
|
6177 |
),
|
6178 |
'mandatory_parent' => 'amp-experiment',
|
6179 |
'spec_name' => 'amp-experiment extension .json script',
|
6180 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-experiment',
|
6181 |
),
|
6182 |
|
6183 |
),
|
6199 |
),
|
6200 |
),
|
6201 |
'tag_spec' => array(
|
|
|
|
|
|
|
|
|
6202 |
'mandatory_parent' => 'amp-accordion',
|
6203 |
'spec_name' => 'amp-accordion > section',
|
6204 |
),
|
6208 |
'select' => array(
|
6209 |
array(
|
6210 |
'attr_spec_list' => array(
|
6211 |
+
'[autofocus]' => array(),
|
6212 |
+
'[disabled]' => array(),
|
6213 |
+
'[multiple]' => array(),
|
6214 |
+
'[required]' => array(),
|
6215 |
+
'[size]' => array(),
|
6216 |
'autofocus' => array(),
|
6217 |
'disabled' => array(),
|
6218 |
'multiple' => array(),
|
6219 |
+
'name' => array(
|
6220 |
+
'blacklisted_value_regex' => '(^|\\s)(__amp_\\s*|__count__|__definegetter__|__definesetter__|__lookupgetter__|__lookupsetter__|__nosuchmethod__|__parent__|__proto__|__amp_\\s*|\\$p|\\$proxy|acceptcharset|addeventlistener|appendchild|assignedslot|attachshadow|baseuri|checkvalidity|childelementcount|childnodes|classlist|classname|clientheight|clientleft|clienttop|clientwidth|comparedocumentposition|computedname|computedrole|contenteditable|createshadowroot|enqueaction|firstchild|firstelementchild|getanimations|getattribute|getattributens|getattributenode|getattributenodens|getboundingclientrect|getclientrects|getdestinationinsertionpoints|getelementsbyclassname|getelementsbytagname|getelementsbytagnamens|getrootnode|hasattribute|hasattributens|hasattributes|haschildnodes|haspointercapture|innerhtml|innertext|inputmode|insertadjacentelement|insertadjacenthtml|insertadjacenttext|iscontenteditable|isdefaultnamespace|isequalnode|issamenode|lastchild|lastelementchild|lookupnamespaceuri|namespaceuri|nextelementsibling|nextsibling|nodename|nodetype|nodevalue|offsetheight|offsetleft|offsetparent|offsettop|offsetwidth|outerhtml|outertext|ownerdocument|parentelement|parentnode|previouselementsibling|previoussibling|queryselector|queryselectorall|releasepointercapture|removeattribute|removeattributens|removeattributenode|removechild|removeeventlistener|replacechild|reportvalidity|requestpointerlock|scrollheight|scrollintoview|scrollintoviewifneeded|scrollleft|scrollwidth|setattribute|setattributens|setattributenode|setattributenodens|setpointercapture|shadowroot|stylemap|tabindex|tagname|textcontent|tostring|valueof|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)matchesselector|(webkit|moz|ms|o)requestfullscreen|(webkit|moz|ms|o)requestfullscreen)(\\s|$)',
|
6221 |
+
),
|
6222 |
'required' => array(),
|
6223 |
'size' => array(),
|
6224 |
),
|
6225 |
'tag_spec' => array(
|
6226 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form',
|
6227 |
+
),
|
6228 |
+
|
6229 |
+
),
|
6230 |
+
),
|
6231 |
+
'slot' => array(
|
6232 |
+
array(
|
6233 |
+
'attr_spec_list' => array(
|
6234 |
+
'name' => array(),
|
6235 |
+
),
|
6236 |
+
'tag_spec' => array(
|
6237 |
+
'html_format' => array(
|
6238 |
+
'amp',
|
6239 |
),
|
|
|
|
|
6240 |
),
|
6241 |
|
6242 |
),
|
6248 |
|
6249 |
),
|
6250 |
),
|
6251 |
+
'solidcolor' => array(
|
6252 |
+
array(
|
6253 |
+
'attr_spec_list' => array(
|
6254 |
+
'alignment-baseline' => array(),
|
6255 |
+
'baseline-shift' => array(),
|
6256 |
+
'clip' => array(),
|
6257 |
+
'clip-path' => array(),
|
6258 |
+
'clip-rule' => array(),
|
6259 |
+
'color' => array(),
|
6260 |
+
'color-interpolation' => array(),
|
6261 |
+
'color-interpolation-filters' => array(),
|
6262 |
+
'color-profile' => array(),
|
6263 |
+
'color-rendering' => array(),
|
6264 |
+
'cursor' => array(),
|
6265 |
+
'direction' => array(),
|
6266 |
+
'display' => array(),
|
6267 |
+
'dominant-baseline' => array(),
|
6268 |
+
'enable-background' => array(),
|
6269 |
+
'fill' => array(),
|
6270 |
+
'fill-opacity' => array(),
|
6271 |
+
'fill-rule' => array(),
|
6272 |
+
'filter' => array(),
|
6273 |
+
'flood-color' => array(),
|
6274 |
+
'flood-opacity' => array(),
|
6275 |
+
'font-family' => array(),
|
6276 |
+
'font-size' => array(),
|
6277 |
+
'font-size-adjust' => array(),
|
6278 |
+
'font-stretch' => array(),
|
6279 |
+
'font-style' => array(),
|
6280 |
+
'font-variant' => array(),
|
6281 |
+
'font-weight' => array(),
|
6282 |
+
'glyph-orientation-horizontal' => array(),
|
6283 |
+
'glyph-orientation-vertical' => array(),
|
6284 |
+
'image-rendering' => array(),
|
6285 |
+
'kerning' => array(),
|
6286 |
+
'letter-spacing' => array(),
|
6287 |
+
'lighting-color' => array(),
|
6288 |
+
'marker-end' => array(),
|
6289 |
+
'marker-mid' => array(),
|
6290 |
+
'marker-start' => array(),
|
6291 |
+
'mask' => array(),
|
6292 |
+
'opacity' => array(),
|
6293 |
+
'overflow' => array(),
|
6294 |
+
'pointer-events' => array(),
|
6295 |
+
'shape-rendering' => array(),
|
6296 |
+
'solid-color' => array(),
|
6297 |
+
'solid-opacity' => array(),
|
6298 |
+
'stop-color' => array(),
|
6299 |
+
'stop-opacity' => array(),
|
6300 |
+
'stroke' => array(),
|
6301 |
+
'stroke-dasharray' => array(),
|
6302 |
+
'stroke-dashoffset' => array(),
|
6303 |
+
'stroke-linecap' => array(),
|
6304 |
+
'stroke-linejoin' => array(),
|
6305 |
+
'stroke-miterlimit' => array(),
|
6306 |
+
'stroke-opacity' => array(),
|
6307 |
+
'stroke-width' => array(),
|
6308 |
+
'style' => array(
|
6309 |
+
'blacklisted_value_regex' => '!important',
|
6310 |
+
),
|
6311 |
+
'text-anchor' => array(),
|
6312 |
+
'text-decoration' => array(),
|
6313 |
+
'text-rendering' => array(),
|
6314 |
+
'unicode-bidi' => array(),
|
6315 |
+
'vector-effect' => array(),
|
6316 |
+
'visibility' => array(),
|
6317 |
+
'word-spacing' => array(),
|
6318 |
+
'writing-mode' => array(),
|
6319 |
+
'xml:lang' => array(),
|
6320 |
+
'xml:space' => array(),
|
6321 |
+
'xmlns' => array(),
|
6322 |
+
'xmlns:xlink' => array(),
|
6323 |
+
),
|
6324 |
+
'tag_spec' => array(
|
6325 |
+
'html_format' => array(
|
6326 |
+
'amp',
|
6327 |
+
'amp4ads',
|
6328 |
+
),
|
6329 |
+
'mandatory_ancestor' => 'svg',
|
6330 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
6331 |
+
),
|
6332 |
+
|
6333 |
+
),
|
6334 |
+
),
|
6335 |
'source' => array(
|
6336 |
array(
|
6337 |
'attr_spec_list' => array(
|
6338 |
+
'[src]' => array(),
|
6339 |
+
'[type]' => array(),
|
6340 |
'media' => array(),
|
6341 |
'src' => array(
|
6342 |
'blacklisted_value_regex' => '__amp_source_origin',
|
6348 |
'type' => array(),
|
6349 |
),
|
6350 |
'tag_spec' => array(
|
6351 |
+
'html_format' => array(
|
6352 |
+
'amp',
|
6353 |
+
'amp4ads',
|
6354 |
+
),
|
6355 |
'mandatory_parent' => 'amp-video',
|
6356 |
'spec_name' => 'amp-video > source',
|
6357 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-video',
|
6358 |
),
|
6359 |
|
6360 |
),
|
6361 |
array(
|
6362 |
'attr_spec_list' => array(
|
6363 |
+
'[src]' => array(),
|
6364 |
+
'[type]' => array(),
|
6365 |
'media' => array(),
|
6366 |
'src' => array(
|
6367 |
'blacklisted_value_regex' => '__amp_source_origin',
|
6373 |
'type' => array(),
|
6374 |
),
|
6375 |
'tag_spec' => array(
|
6376 |
+
'html_format' => array(
|
6377 |
+
'amp',
|
6378 |
+
'amp4ads',
|
6379 |
+
),
|
6380 |
'mandatory_parent' => 'amp-audio',
|
6381 |
'spec_name' => 'amp-audio > source',
|
6382 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-audio',
|
6383 |
),
|
6384 |
|
6385 |
),
|
6399 |
),
|
6400 |
),
|
6401 |
'tag_spec' => array(
|
6402 |
+
'html_format' => array(
|
6403 |
+
'amp',
|
6404 |
+
'amp4ads',
|
6405 |
+
),
|
6406 |
'mandatory_parent' => 'audio',
|
6407 |
'spec_name' => 'audio > source',
|
6408 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-audio',
|
6409 |
),
|
6410 |
|
6411 |
),
|
6425 |
),
|
6426 |
),
|
6427 |
'tag_spec' => array(
|
6428 |
+
'html_format' => array(
|
6429 |
+
'amp',
|
6430 |
+
'amp4ads',
|
6431 |
+
),
|
6432 |
+
'mandatory_parent' => 'video',
|
6433 |
+
'spec_name' => 'video > source',
|
6434 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-video',
|
6435 |
+
),
|
6436 |
+
|
6437 |
+
),
|
6438 |
+
array(
|
6439 |
+
'attr_spec_list' => array(
|
6440 |
+
'[src]' => array(),
|
6441 |
+
'[type]' => array(),
|
6442 |
+
'media' => array(),
|
6443 |
+
'src' => array(
|
6444 |
+
'blacklisted_value_regex' => '__amp_source_origin',
|
6445 |
+
'allow_relative' => true,
|
6446 |
+
'allowed_protocol' => array(
|
6447 |
+
'https',
|
6448 |
+
),
|
6449 |
+
),
|
6450 |
+
'type' => array(),
|
6451 |
+
),
|
6452 |
+
'tag_spec' => array(
|
6453 |
+
'html_format' => array(
|
6454 |
+
'amp',
|
6455 |
+
'amp4ads',
|
6456 |
+
),
|
6457 |
+
'mandatory_parent' => 'amp-ima-video',
|
6458 |
+
'spec_name' => 'amp-ima-video > source',
|
6459 |
),
|
6460 |
|
6461 |
),
|
6484 |
'offset' => array(),
|
6485 |
'stop-color' => array(),
|
6486 |
'stop-opacity' => array(),
|
6487 |
+
'style' => array(
|
6488 |
+
'blacklisted_value_regex' => '!important',
|
6489 |
+
),
|
6490 |
),
|
6491 |
'tag_spec' => array(
|
6492 |
+
'html_format' => array(
|
6493 |
+
'amp',
|
6494 |
+
'amp4ads',
|
6495 |
+
),
|
6496 |
'mandatory_ancestor' => 'lineargradient',
|
6497 |
'spec_name' => 'lineargradient > stop',
|
6498 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
6499 |
),
|
6500 |
|
6501 |
),
|
6504 |
'offset' => array(),
|
6505 |
'stop-color' => array(),
|
6506 |
'stop-opacity' => array(),
|
6507 |
+
'style' => array(
|
6508 |
+
'blacklisted_value_regex' => '!important',
|
6509 |
+
),
|
6510 |
),
|
6511 |
'tag_spec' => array(
|
6512 |
+
'html_format' => array(
|
6513 |
+
'amp',
|
6514 |
+
'amp4ads',
|
6515 |
+
),
|
6516 |
'mandatory_ancestor' => 'radialgradient',
|
6517 |
'spec_name' => 'radialgradient > stop',
|
6518 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
6519 |
),
|
6520 |
|
6521 |
),
|
6542 |
array(
|
6543 |
'attr_spec_list' => array(
|
6544 |
'amp-boilerplate' => array(
|
|
|
6545 |
'mandatory' => true,
|
6546 |
'value' => '',
|
6547 |
),
|
6548 |
+
'nonce' => array(),
|
6549 |
),
|
6550 |
'tag_spec' => array(
|
|
|
|
|
|
|
6551 |
'html_format' => array(
|
6552 |
'amp',
|
6553 |
),
|
6554 |
'mandatory_alternatives' => 'noscript > style[amp-boilerplate]',
|
6555 |
+
'mandatory_ancestor' => 'head',
|
6556 |
'mandatory_parent' => 'noscript',
|
6557 |
'spec_name' => 'noscript > style[amp-boilerplate]',
|
6558 |
'spec_url' => 'https://github.com/ampproject/amphtml/blob/master/spec/amp-boilerplate.md',
|
6560 |
),
|
6561 |
|
6562 |
),
|
6563 |
+
array(
|
6564 |
+
'attr_spec_list' => array(
|
6565 |
+
'amp-keyframes' => array(
|
6566 |
+
'mandatory' => true,
|
6567 |
+
'value' => '',
|
6568 |
+
),
|
6569 |
+
),
|
6570 |
+
'tag_spec' => array(
|
6571 |
+
'html_format' => array(
|
6572 |
+
'amp',
|
6573 |
+
'amp4ads',
|
6574 |
+
),
|
6575 |
+
'mandatory_parent' => 'body',
|
6576 |
+
'spec_name' => 'style[amp-keyframes]',
|
6577 |
+
'unique' => true,
|
6578 |
+
),
|
6579 |
+
|
6580 |
+
),
|
6581 |
),
|
6582 |
'sub' => array(
|
6583 |
array(
|
6598 |
'attr_spec_list' => array(
|
6599 |
'alignment-baseline' => array(),
|
6600 |
'baseline-shift' => array(),
|
|
|
6601 |
'clip' => array(),
|
6602 |
'clip-path' => array(),
|
6603 |
'clip-rule' => array(),
|
6660 |
'text-decoration' => array(),
|
6661 |
'text-rendering' => array(),
|
6662 |
'unicode-bidi' => array(),
|
6663 |
+
'vector-effect' => array(),
|
6664 |
'version' => array(
|
6665 |
'value_regex' => '(1.0|1.1)',
|
6666 |
),
|
6670 |
'word-spacing' => array(),
|
6671 |
'writing-mode' => array(),
|
6672 |
'x' => array(),
|
|
|
6673 |
'xml:lang' => array(),
|
6674 |
'xml:space' => array(),
|
6675 |
'xmlns' => array(),
|
6678 |
'zoomandpan' => array(),
|
6679 |
),
|
6680 |
'tag_spec' => array(
|
6681 |
+
'html_format' => array(
|
6682 |
+
'amp',
|
6683 |
+
'amp4ads',
|
6684 |
+
),
|
6685 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
6686 |
+
),
|
6687 |
+
|
6688 |
+
),
|
6689 |
+
),
|
6690 |
+
'switch' => array(
|
6691 |
+
array(
|
6692 |
+
'attr_spec_list' => array(
|
6693 |
+
'alignment-baseline' => array(),
|
6694 |
+
'baseline-shift' => array(),
|
6695 |
+
'clip' => array(),
|
6696 |
+
'clip-path' => array(),
|
6697 |
+
'clip-rule' => array(),
|
6698 |
+
'color' => array(),
|
6699 |
+
'color-interpolation' => array(),
|
6700 |
+
'color-interpolation-filters' => array(),
|
6701 |
+
'color-profile' => array(),
|
6702 |
+
'color-rendering' => array(),
|
6703 |
+
'cursor' => array(),
|
6704 |
+
'direction' => array(),
|
6705 |
+
'display' => array(),
|
6706 |
+
'dominant-baseline' => array(),
|
6707 |
+
'enable-background' => array(),
|
6708 |
+
'fill' => array(),
|
6709 |
+
'fill-opacity' => array(),
|
6710 |
+
'fill-rule' => array(),
|
6711 |
+
'filter' => array(),
|
6712 |
+
'flood-color' => array(),
|
6713 |
+
'flood-opacity' => array(),
|
6714 |
+
'font-family' => array(),
|
6715 |
+
'font-size' => array(),
|
6716 |
+
'font-size-adjust' => array(),
|
6717 |
+
'font-stretch' => array(),
|
6718 |
+
'font-style' => array(),
|
6719 |
+
'font-variant' => array(),
|
6720 |
+
'font-weight' => array(),
|
6721 |
+
'glyph-orientation-horizontal' => array(),
|
6722 |
+
'glyph-orientation-vertical' => array(),
|
6723 |
+
'image-rendering' => array(),
|
6724 |
+
'kerning' => array(),
|
6725 |
+
'letter-spacing' => array(),
|
6726 |
+
'lighting-color' => array(),
|
6727 |
+
'marker-end' => array(),
|
6728 |
+
'marker-mid' => array(),
|
6729 |
+
'marker-start' => array(),
|
6730 |
+
'mask' => array(),
|
6731 |
+
'opacity' => array(),
|
6732 |
+
'overflow' => array(),
|
6733 |
+
'pointer-events' => array(),
|
6734 |
+
'requiredextensions' => array(),
|
6735 |
+
'requiredfeatures' => array(),
|
6736 |
+
'shape-rendering' => array(),
|
6737 |
+
'stop-color' => array(),
|
6738 |
+
'stop-opacity' => array(),
|
6739 |
+
'stroke' => array(),
|
6740 |
+
'stroke-dasharray' => array(),
|
6741 |
+
'stroke-dashoffset' => array(),
|
6742 |
+
'stroke-linecap' => array(),
|
6743 |
+
'stroke-linejoin' => array(),
|
6744 |
+
'stroke-miterlimit' => array(),
|
6745 |
+
'stroke-opacity' => array(),
|
6746 |
+
'stroke-width' => array(),
|
6747 |
+
'style' => array(
|
6748 |
+
'blacklisted_value_regex' => '!important',
|
6749 |
+
),
|
6750 |
+
'systemlanguage' => array(),
|
6751 |
+
'text-anchor' => array(),
|
6752 |
+
'text-decoration' => array(),
|
6753 |
+
'text-rendering' => array(),
|
6754 |
+
'unicode-bidi' => array(),
|
6755 |
+
'vector-effect' => array(),
|
6756 |
+
'visibility' => array(),
|
6757 |
+
'word-spacing' => array(),
|
6758 |
+
'writing-mode' => array(),
|
6759 |
+
'xml:lang' => array(),
|
6760 |
+
'xml:space' => array(),
|
6761 |
+
'xmlns' => array(),
|
6762 |
+
'xmlns:xlink' => array(),
|
6763 |
+
),
|
6764 |
+
'tag_spec' => array(
|
6765 |
+
'html_format' => array(
|
6766 |
+
'amp',
|
6767 |
+
'amp4ads',
|
6768 |
+
),
|
6769 |
+
'mandatory_ancestor' => 'svg',
|
6770 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
6771 |
),
|
6772 |
|
6773 |
),
|
6777 |
'attr_spec_list' => array(
|
6778 |
'alignment-baseline' => array(),
|
6779 |
'baseline-shift' => array(),
|
|
|
6780 |
'clip' => array(),
|
6781 |
'clip-path' => array(),
|
6782 |
'clip-rule' => array(),
|
6829 |
'stroke-miterlimit' => array(),
|
6830 |
'stroke-opacity' => array(),
|
6831 |
'stroke-width' => array(),
|
6832 |
+
'style' => array(
|
6833 |
+
'blacklisted_value_regex' => '!important',
|
6834 |
+
),
|
6835 |
'text-anchor' => array(),
|
6836 |
'text-decoration' => array(),
|
6837 |
'text-rendering' => array(),
|
6838 |
'unicode-bidi' => array(),
|
6839 |
+
'vector-effect' => array(),
|
6840 |
'viewbox' => array(),
|
6841 |
'visibility' => array(),
|
6842 |
'word-spacing' => array(),
|
6843 |
'writing-mode' => array(),
|
|
|
6844 |
'xml:lang' => array(),
|
6845 |
'xml:space' => array(),
|
6846 |
'xmlns' => array(),
|
6847 |
'xmlns:xlink' => array(),
|
6848 |
),
|
6849 |
'tag_spec' => array(
|
6850 |
+
'html_format' => array(
|
6851 |
+
'amp',
|
6852 |
+
'amp4ads',
|
6853 |
+
),
|
6854 |
'mandatory_ancestor' => 'svg',
|
6855 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
6856 |
),
|
6857 |
|
6858 |
),
|
6906 |
),
|
6907 |
),
|
6908 |
'tag_spec' => array(
|
|
|
|
|
|
|
6909 |
'disallowed_ancestor' => array(
|
6910 |
'template',
|
6911 |
),
|
|
|
6912 |
),
|
6913 |
|
6914 |
),
|
6918 |
'attr_spec_list' => array(
|
6919 |
'alignment-baseline' => array(),
|
6920 |
'baseline-shift' => array(),
|
|
|
6921 |
'clip' => array(),
|
6922 |
'clip-path' => array(),
|
6923 |
'clip-rule' => array(),
|
6975 |
'stroke-miterlimit' => array(),
|
6976 |
'stroke-opacity' => array(),
|
6977 |
'stroke-width' => array(),
|
6978 |
+
'style' => array(
|
6979 |
+
'blacklisted_value_regex' => '!important',
|
6980 |
+
),
|
6981 |
'systemlanguage' => array(),
|
6982 |
'text-anchor' => array(),
|
6983 |
'text-decoration' => array(),
|
6985 |
'textlength' => array(),
|
6986 |
'transform' => array(),
|
6987 |
'unicode-bidi' => array(),
|
6988 |
+
'vector-effect' => array(),
|
6989 |
'visibility' => array(),
|
6990 |
'word-spacing' => array(),
|
6991 |
'writing-mode' => array(),
|
6992 |
'x' => array(),
|
|
|
6993 |
'xml:lang' => array(),
|
6994 |
'xml:space' => array(),
|
6995 |
'xmlns' => array(),
|
6997 |
'y' => array(),
|
6998 |
),
|
6999 |
'tag_spec' => array(
|
7000 |
+
'html_format' => array(
|
7001 |
+
'amp',
|
7002 |
+
'amp4ads',
|
7003 |
+
),
|
7004 |
'mandatory_ancestor' => 'svg',
|
7005 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
7006 |
),
|
7007 |
|
7008 |
),
|
7010 |
'textarea' => array(
|
7011 |
array(
|
7012 |
'attr_spec_list' => array(
|
7013 |
+
'[autocomplete]' => array(),
|
7014 |
+
'[autofocus]' => array(),
|
7015 |
+
'[cols]' => array(),
|
7016 |
+
'[disabled]' => array(),
|
7017 |
+
'[maxlength]' => array(),
|
7018 |
+
'[minlength]' => array(),
|
7019 |
+
'[placeholder]' => array(),
|
7020 |
+
'[readonly]' => array(),
|
7021 |
+
'[required]' => array(),
|
7022 |
+
'[rows]' => array(),
|
7023 |
+
'[selectiondirection]' => array(),
|
7024 |
+
'[selectionend]' => array(),
|
7025 |
+
'[selectionstart]' => array(),
|
7026 |
+
'[spellcheck]' => array(),
|
7027 |
+
'[wrap]' => array(),
|
7028 |
'autocomplete' => array(),
|
7029 |
'autofocus' => array(),
|
7030 |
'cols' => array(),
|
7031 |
'disabled' => array(),
|
7032 |
'maxlength' => array(),
|
7033 |
'minlength' => array(),
|
7034 |
+
'name' => array(
|
7035 |
+
'blacklisted_value_regex' => '(^|\\s)(__amp_\\s*|__count__|__definegetter__|__definesetter__|__lookupgetter__|__lookupsetter__|__nosuchmethod__|__parent__|__proto__|__amp_\\s*|\\$p|\\$proxy|acceptcharset|addeventlistener|appendchild|assignedslot|attachshadow|baseuri|checkvalidity|childelementcount|childnodes|classlist|classname|clientheight|clientleft|clienttop|clientwidth|comparedocumentposition|computedname|computedrole|contenteditable|createshadowroot|enqueaction|firstchild|firstelementchild|getanimations|getattribute|getattributens|getattributenode|getattributenodens|getboundingclientrect|getclientrects|getdestinationinsertionpoints|getelementsbyclassname|getelementsbytagname|getelementsbytagnamens|getrootnode|hasattribute|hasattributens|hasattributes|haschildnodes|haspointercapture|innerhtml|innertext|inputmode|insertadjacentelement|insertadjacenthtml|insertadjacenttext|iscontenteditable|isdefaultnamespace|isequalnode|issamenode|lastchild|lastelementchild|lookupnamespaceuri|namespaceuri|nextelementsibling|nextsibling|nodename|nodetype|nodevalue|offsetheight|offsetleft|offsetparent|offsettop|offsetwidth|outerhtml|outertext|ownerdocument|parentelement|parentnode|previouselementsibling|previoussibling|queryselector|queryselectorall|releasepointercapture|removeattribute|removeattributens|removeattributenode|removechild|removeeventlistener|replacechild|reportvalidity|requestpointerlock|scrollheight|scrollintoview|scrollintoviewifneeded|scrollleft|scrollwidth|setattribute|setattributens|setattributenode|setattributenodens|setpointercapture|shadowroot|stylemap|tabindex|tagname|textcontent|tostring|valueof|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)matchesselector|(webkit|moz|ms|o)requestfullscreen|(webkit|moz|ms|o)requestfullscreen)(\\s|$)',
|
7036 |
+
),
|
7037 |
'placeholder' => array(),
|
7038 |
'readonly' => array(),
|
7039 |
'required' => array(),
|
7045 |
'wrap' => array(),
|
7046 |
),
|
7047 |
'tag_spec' => array(
|
7048 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form',
|
|
|
|
|
|
|
|
|
7049 |
),
|
7050 |
|
7051 |
),
|
7055 |
'attr_spec_list' => array(
|
7056 |
'alignment-baseline' => array(),
|
7057 |
'baseline-shift' => array(),
|
|
|
7058 |
'clip' => array(),
|
7059 |
'clip-path' => array(),
|
7060 |
'clip-rule' => array(),
|
7111 |
'stroke-miterlimit' => array(),
|
7112 |
'stroke-opacity' => array(),
|
7113 |
'stroke-width' => array(),
|
7114 |
+
'style' => array(
|
7115 |
+
'blacklisted_value_regex' => '!important',
|
7116 |
+
),
|
7117 |
'systemlanguage' => array(),
|
7118 |
'text-anchor' => array(),
|
7119 |
'text-decoration' => array(),
|
7120 |
'text-rendering' => array(),
|
7121 |
'unicode-bidi' => array(),
|
7122 |
+
'vector-effect' => array(),
|
7123 |
'visibility' => array(),
|
7124 |
'word-spacing' => array(),
|
7125 |
'writing-mode' => array(),
|
7126 |
'xlink:actuate' => array(),
|
7127 |
'xlink:arcrole' => array(),
|
7128 |
'xlink:href' => array(
|
7129 |
+
'alternative_names' => array(
|
7130 |
+
'href',
|
7131 |
+
),
|
7132 |
+
'allow_empty' => false,
|
7133 |
+
'allow_relative' => true,
|
7134 |
+
'allowed_protocol' => array(
|
7135 |
+
'http',
|
7136 |
+
'https',
|
7137 |
+
),
|
7138 |
),
|
7139 |
'xlink:role' => array(),
|
7140 |
'xlink:show' => array(),
|
7141 |
'xlink:title' => array(),
|
7142 |
'xlink:type' => array(),
|
|
|
7143 |
'xml:lang' => array(),
|
7144 |
'xml:space' => array(),
|
7145 |
'xmlns' => array(),
|
7146 |
'xmlns:xlink' => array(),
|
7147 |
),
|
7148 |
'tag_spec' => array(
|
7149 |
+
'html_format' => array(
|
7150 |
+
'amp',
|
7151 |
+
'amp4ads',
|
7152 |
+
),
|
7153 |
'mandatory_ancestor' => 'svg',
|
7154 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
7155 |
),
|
7156 |
|
7157 |
),
|
7208 |
),
|
7209 |
array(
|
7210 |
'attr_spec_list' => array(
|
7211 |
+
'style' => array(
|
7212 |
+
'blacklisted_value_regex' => '!important',
|
7213 |
+
),
|
7214 |
'xml:lang' => array(),
|
7215 |
'xml:space' => array(),
|
7216 |
'xmlns' => array(),
|
7217 |
'xmlns:xlink' => array(),
|
7218 |
),
|
7219 |
'tag_spec' => array(
|
7220 |
+
'html_format' => array(
|
7221 |
+
'amp',
|
7222 |
+
'amp4ads',
|
7223 |
+
),
|
7224 |
'mandatory_ancestor' => 'svg',
|
7225 |
'spec_name' => 'svg title',
|
7226 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
7227 |
),
|
7228 |
|
7229 |
),
|
7261 |
'srclang' => array(),
|
7262 |
),
|
7263 |
'tag_spec' => array(
|
7264 |
+
'html_format' => array(
|
7265 |
+
'amp',
|
7266 |
+
'amp4ads',
|
7267 |
+
),
|
7268 |
'mandatory_parent' => 'audio',
|
7269 |
'spec_name' => 'audio > track',
|
7270 |
),
|
7293 |
),
|
7294 |
),
|
7295 |
'tag_spec' => array(
|
7296 |
+
'html_format' => array(
|
7297 |
+
'amp',
|
7298 |
+
'amp4ads',
|
7299 |
+
),
|
7300 |
'mandatory_parent' => 'audio',
|
7301 |
'spec_name' => 'audio > track[kind=subtitles]',
|
7302 |
),
|
7322 |
'srclang' => array(),
|
7323 |
),
|
7324 |
'tag_spec' => array(
|
7325 |
+
'html_format' => array(
|
7326 |
+
'amp',
|
7327 |
+
'amp4ads',
|
7328 |
+
),
|
7329 |
'mandatory_parent' => 'video',
|
7330 |
'spec_name' => 'video > track',
|
7331 |
),
|
7354 |
),
|
7355 |
),
|
7356 |
'tag_spec' => array(
|
7357 |
+
'html_format' => array(
|
7358 |
+
'amp',
|
7359 |
+
'amp4ads',
|
7360 |
+
),
|
7361 |
'mandatory_parent' => 'video',
|
7362 |
'spec_name' => 'video > track[kind=subtitles]',
|
7363 |
),
|
7365 |
),
|
7366 |
array(
|
7367 |
'attr_spec_list' => array(
|
7368 |
+
'[label]' => array(),
|
7369 |
+
'[src]' => array(),
|
7370 |
+
'[srclang]' => array(),
|
7371 |
'default' => array(
|
7372 |
'value' => '',
|
7373 |
),
|
7386 |
'srclang' => array(),
|
7387 |
),
|
7388 |
'tag_spec' => array(
|
7389 |
+
'html_format' => array(
|
7390 |
+
'amp',
|
7391 |
+
'amp4ads',
|
7392 |
+
),
|
7393 |
'mandatory_parent' => 'amp-audio',
|
7394 |
'spec_name' => 'amp-audio > track',
|
7395 |
),
|
7397 |
),
|
7398 |
array(
|
7399 |
'attr_spec_list' => array(
|
7400 |
+
'[label]' => array(),
|
7401 |
+
'[src]' => array(),
|
7402 |
+
'[srclang]' => array(),
|
7403 |
'default' => array(
|
7404 |
'value' => '',
|
7405 |
),
|
7421 |
),
|
7422 |
),
|
7423 |
'tag_spec' => array(
|
7424 |
+
'html_format' => array(
|
7425 |
+
'amp',
|
7426 |
+
'amp4ads',
|
7427 |
+
),
|
7428 |
'mandatory_parent' => 'amp-audio',
|
7429 |
'spec_name' => 'amp-audio > track[kind=subtitles]',
|
7430 |
),
|
7432 |
),
|
7433 |
array(
|
7434 |
'attr_spec_list' => array(
|
7435 |
+
'[label]' => array(),
|
7436 |
+
'[src]' => array(),
|
7437 |
+
'[srclang]' => array(),
|
7438 |
'default' => array(
|
7439 |
'value' => '',
|
7440 |
),
|
7453 |
'srclang' => array(),
|
7454 |
),
|
7455 |
'tag_spec' => array(
|
7456 |
+
'html_format' => array(
|
7457 |
+
'amp',
|
7458 |
+
'amp4ads',
|
7459 |
+
),
|
7460 |
'mandatory_parent' => 'amp-video',
|
7461 |
'spec_name' => 'amp-video > track',
|
7462 |
),
|
7464 |
),
|
7465 |
array(
|
7466 |
'attr_spec_list' => array(
|
7467 |
+
'[label]' => array(),
|
7468 |
+
'[src]' => array(),
|
7469 |
+
'[srclang]' => array(),
|
7470 |
'default' => array(
|
7471 |
'value' => '',
|
7472 |
),
|
7488 |
),
|
7489 |
),
|
7490 |
'tag_spec' => array(
|
7491 |
+
'html_format' => array(
|
7492 |
+
'amp',
|
7493 |
+
'amp4ads',
|
7494 |
+
),
|
7495 |
'mandatory_parent' => 'amp-video',
|
7496 |
'spec_name' => 'amp-video > track[kind=subtitles]',
|
7497 |
),
|
7498 |
|
7499 |
),
|
7500 |
+
array(
|
7501 |
+
'attr_spec_list' => array(
|
7502 |
+
'[label]' => array(),
|
7503 |
+
'[src]' => array(),
|
7504 |
+
'[srclang]' => array(),
|
7505 |
+
'default' => array(
|
7506 |
+
'value' => '',
|
7507 |
+
),
|
7508 |
+
'kind' => array(
|
7509 |
+
'mandatory' => true,
|
7510 |
+
'value_casei' => 'subtitles',
|
7511 |
+
),
|
7512 |
+
'label' => array(),
|
7513 |
+
'src' => array(
|
7514 |
+
'blacklisted_value_regex' => '__amp_source_origin',
|
7515 |
+
'mandatory' => true,
|
7516 |
+
'allow_relative' => false,
|
7517 |
+
'allowed_protocol' => array(
|
7518 |
+
'https',
|
7519 |
+
),
|
7520 |
+
),
|
7521 |
+
'srclang' => array(
|
7522 |
+
'mandatory' => true,
|
7523 |
+
),
|
7524 |
+
),
|
7525 |
+
'tag_spec' => array(
|
7526 |
+
'html_format' => array(
|
7527 |
+
'amp',
|
7528 |
+
'amp4ads',
|
7529 |
+
),
|
7530 |
+
'mandatory_parent' => 'amp-ima-video',
|
7531 |
+
'spec_name' => 'amp-ima-video > track[kind=subtitles]',
|
7532 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ima-video',
|
7533 |
+
),
|
7534 |
+
|
7535 |
+
),
|
7536 |
),
|
7537 |
'tref' => array(
|
7538 |
array(
|
7539 |
'attr_spec_list' => array(
|
7540 |
'alignment-baseline' => array(),
|
7541 |
'baseline-shift' => array(),
|
|
|
7542 |
'clip' => array(),
|
7543 |
'clip-path' => array(),
|
7544 |
'clip-rule' => array(),
|
7592 |
'stroke-miterlimit' => array(),
|
7593 |
'stroke-opacity' => array(),
|
7594 |
'stroke-width' => array(),
|
7595 |
+
'style' => array(
|
7596 |
+
'blacklisted_value_regex' => '!important',
|
7597 |
+
),
|
7598 |
'systemlanguage' => array(),
|
7599 |
'text-anchor' => array(),
|
7600 |
'text-decoration' => array(),
|
7601 |
'text-rendering' => array(),
|
7602 |
'unicode-bidi' => array(),
|
7603 |
+
'vector-effect' => array(),
|
7604 |
'visibility' => array(),
|
7605 |
'word-spacing' => array(),
|
7606 |
'writing-mode' => array(),
|
7607 |
'xlink:actuate' => array(),
|
7608 |
'xlink:arcrole' => array(),
|
7609 |
'xlink:href' => array(
|
7610 |
+
'alternative_names' => array(
|
7611 |
+
'href',
|
7612 |
+
),
|
7613 |
+
'allow_empty' => false,
|
7614 |
+
'allow_relative' => true,
|
7615 |
+
'allowed_protocol' => array(
|
7616 |
+
'http',
|
7617 |
+
'https',
|
7618 |
+
),
|
7619 |
),
|
7620 |
'xlink:role' => array(),
|
7621 |
'xlink:show' => array(),
|
7622 |
'xlink:title' => array(),
|
7623 |
'xlink:type' => array(),
|
|
|
7624 |
'xml:lang' => array(),
|
7625 |
'xml:space' => array(),
|
7626 |
'xmlns' => array(),
|
7627 |
'xmlns:xlink' => array(),
|
7628 |
),
|
7629 |
'tag_spec' => array(
|
7630 |
+
'html_format' => array(
|
7631 |
+
'amp',
|
7632 |
+
'amp4ads',
|
7633 |
+
),
|
7634 |
'mandatory_ancestor' => 'svg',
|
7635 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
7636 |
),
|
7637 |
|
7638 |
),
|
7642 |
'attr_spec_list' => array(
|
7643 |
'alignment-baseline' => array(),
|
7644 |
'baseline-shift' => array(),
|
|
|
7645 |
'clip' => array(),
|
7646 |
'clip-path' => array(),
|
7647 |
'clip-rule' => array(),
|
7699 |
'stroke-miterlimit' => array(),
|
7700 |
'stroke-opacity' => array(),
|
7701 |
'stroke-width' => array(),
|
7702 |
+
'style' => array(
|
7703 |
+
'blacklisted_value_regex' => '!important',
|
7704 |
+
),
|
7705 |
'systemlanguage' => array(),
|
7706 |
'text-anchor' => array(),
|
7707 |
'text-decoration' => array(),
|
7708 |
'text-rendering' => array(),
|
7709 |
'textlength' => array(),
|
7710 |
'unicode-bidi' => array(),
|
7711 |
+
'vector-effect' => array(),
|
7712 |
'visibility' => array(),
|
7713 |
'word-spacing' => array(),
|
7714 |
'writing-mode' => array(),
|
7715 |
'x' => array(),
|
|
|
7716 |
'xml:lang' => array(),
|
7717 |
'xml:space' => array(),
|
7718 |
'xmlns' => array(),
|
7720 |
'y' => array(),
|
7721 |
),
|
7722 |
'tag_spec' => array(
|
7723 |
+
'html_format' => array(
|
7724 |
+
'amp',
|
7725 |
+
'amp4ads',
|
7726 |
+
),
|
7727 |
'mandatory_ancestor' => 'svg',
|
7728 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
7729 |
),
|
7730 |
|
7731 |
),
|
7760 |
'attr_spec_list' => array(
|
7761 |
'alignment-baseline' => array(),
|
7762 |
'baseline-shift' => array(),
|
|
|
7763 |
'clip' => array(),
|
7764 |
'clip-path' => array(),
|
7765 |
'clip-rule' => array(),
|
7814 |
'stroke-miterlimit' => array(),
|
7815 |
'stroke-opacity' => array(),
|
7816 |
'stroke-width' => array(),
|
7817 |
+
'style' => array(
|
7818 |
+
'blacklisted_value_regex' => '!important',
|
7819 |
+
),
|
7820 |
'systemlanguage' => array(),
|
7821 |
'text-anchor' => array(),
|
7822 |
'text-decoration' => array(),
|
7823 |
'text-rendering' => array(),
|
7824 |
'transform' => array(),
|
7825 |
'unicode-bidi' => array(),
|
7826 |
+
'vector-effect' => array(),
|
7827 |
'visibility' => array(),
|
7828 |
'width' => array(),
|
7829 |
'word-spacing' => array(),
|
7832 |
'xlink:actuate' => array(),
|
7833 |
'xlink:arcrole' => array(),
|
7834 |
'xlink:href' => array(
|
7835 |
+
'alternative_names' => array(
|
7836 |
+
'href',
|
7837 |
+
),
|
7838 |
+
'allow_empty' => false,
|
7839 |
+
'allow_relative' => true,
|
7840 |
+
'allowed_protocol' => array(
|
7841 |
+
'http',
|
7842 |
+
'https',
|
7843 |
+
),
|
7844 |
),
|
7845 |
'xlink:role' => array(),
|
7846 |
'xlink:show' => array(),
|
7847 |
'xlink:title' => array(),
|
7848 |
'xlink:type' => array(),
|
|
|
7849 |
'xml:lang' => array(),
|
7850 |
'xml:space' => array(),
|
7851 |
'xmlns' => array(),
|
7853 |
'y' => array(),
|
7854 |
),
|
7855 |
'tag_spec' => array(
|
7856 |
+
'html_format' => array(
|
7857 |
+
'amp',
|
7858 |
+
'amp4ads',
|
7859 |
+
),
|
7860 |
'mandatory_ancestor' => 'svg',
|
7861 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
7862 |
),
|
7863 |
|
7864 |
),
|
7878 |
'height' => array(),
|
7879 |
'loop' => array(),
|
7880 |
'muted' => array(),
|
7881 |
+
'playsinline' => array(),
|
7882 |
'poster' => array(),
|
7883 |
'preload' => array(),
|
7884 |
'src' => array(
|
7897 |
),
|
7898 |
'mandatory_ancestor' => 'noscript',
|
7899 |
'mandatory_ancestor_suggested_alternative' => 'amp-video',
|
7900 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-video',
|
7901 |
),
|
7902 |
|
7903 |
),
|
7907 |
'attr_spec_list' => array(
|
7908 |
'externalresourcesrequired' => array(),
|
7909 |
'preserveaspectratio' => array(),
|
7910 |
+
'style' => array(
|
7911 |
+
'blacklisted_value_regex' => '!important',
|
7912 |
+
),
|
7913 |
'viewbox' => array(),
|
7914 |
'viewtarget' => array(),
|
|
|
7915 |
'xml:lang' => array(),
|
7916 |
'xml:space' => array(),
|
7917 |
'xmlns' => array(),
|
7919 |
'zoomandpan' => array(),
|
7920 |
),
|
7921 |
'tag_spec' => array(
|
7922 |
+
'html_format' => array(
|
7923 |
+
'amp',
|
7924 |
+
'amp4ads',
|
7925 |
+
),
|
7926 |
'mandatory_ancestor' => 'svg',
|
7927 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
7928 |
),
|
7929 |
|
7930 |
),
|
7935 |
'g1' => array(),
|
7936 |
'g2' => array(),
|
7937 |
'k' => array(),
|
7938 |
+
'style' => array(
|
7939 |
+
'blacklisted_value_regex' => '!important',
|
7940 |
+
),
|
7941 |
'u1' => array(),
|
7942 |
'u2' => array(),
|
|
|
7943 |
'xml:lang' => array(),
|
7944 |
'xml:space' => array(),
|
7945 |
'xmlns' => array(),
|
7946 |
'xmlns:xlink' => array(),
|
7947 |
),
|
7948 |
'tag_spec' => array(
|
7949 |
+
'html_format' => array(
|
7950 |
+
'amp',
|
7951 |
+
'amp4ads',
|
7952 |
+
),
|
7953 |
'mandatory_ancestor' => 'svg',
|
7954 |
+
'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
|
7955 |
),
|
7956 |
|
7957 |
),
|
7977 |
);
|
7978 |
|
7979 |
private static $layout_allowed_attrs = array(
|
7980 |
+
'[height]' => array(),
|
7981 |
+
'[width]' => array(),
|
7982 |
'height' => array(),
|
7983 |
'heights' => array(),
|
7984 |
'layout' => array(),
|
7989 |
|
7990 |
|
7991 |
private static $globally_allowed_attrs = array(
|
7992 |
+
'[aria-activedescendant]' => array(),
|
7993 |
+
'[aria-atomic]' => array(),
|
7994 |
+
'[aria-autocomplete]' => array(),
|
7995 |
+
'[aria-busy]' => array(),
|
7996 |
+
'[aria-checked]' => array(),
|
7997 |
+
'[aria-controls]' => array(),
|
7998 |
+
'[aria-describedby]' => array(),
|
7999 |
+
'[aria-disabled]' => array(),
|
8000 |
+
'[aria-dropeffect]' => array(),
|
8001 |
+
'[aria-expanded]' => array(),
|
8002 |
+
'[aria-flowto]' => array(),
|
8003 |
+
'[aria-grabbed]' => array(),
|
8004 |
+
'[aria-haspopup]' => array(),
|
8005 |
+
'[aria-hidden]' => array(),
|
8006 |
+
'[aria-invalid]' => array(),
|
8007 |
+
'[aria-label]' => array(),
|
8008 |
+
'[aria-labelledby]' => array(),
|
8009 |
+
'[aria-level]' => array(),
|
8010 |
+
'[aria-live]' => array(),
|
8011 |
+
'[aria-multiline]' => array(),
|
8012 |
+
'[aria-multiselectable]' => array(),
|
8013 |
+
'[aria-orientation]' => array(),
|
8014 |
+
'[aria-owns]' => array(),
|
8015 |
+
'[aria-posinset]' => array(),
|
8016 |
+
'[aria-pressed]' => array(),
|
8017 |
+
'[aria-readonly]' => array(),
|
8018 |
+
'[aria-relevant]' => array(),
|
8019 |
+
'[aria-required]' => array(),
|
8020 |
+
'[aria-selected]' => array(),
|
8021 |
+
'[aria-setsize]' => array(),
|
8022 |
+
'[aria-sort]' => array(),
|
8023 |
+
'[aria-valuemax]' => array(),
|
8024 |
+
'[aria-valuemin]' => array(),
|
8025 |
+
'[aria-valuenow]' => array(),
|
8026 |
+
'[aria-valuetext]' => array(),
|
8027 |
+
'[class]' => array(),
|
8028 |
+
'[hidden]' => array(),
|
8029 |
+
'[text]' => array(),
|
8030 |
+
'about' => array(),
|
8031 |
'accesskey' => array(),
|
8032 |
'amp-access' => array(),
|
8033 |
'amp-access-behavior' => array(),
|
8046 |
'aria-busy' => array(),
|
8047 |
'aria-checked' => array(),
|
8048 |
'aria-controls' => array(),
|
8049 |
+
'aria-current' => array(),
|
8050 |
'aria-describedby' => array(),
|
8051 |
'aria-disabled' => array(),
|
8052 |
'aria-dropeffect' => array(),
|
8079 |
'class' => array(
|
8080 |
'blacklisted_value_regex' => '(^|\\w)i-amphtml-',
|
8081 |
),
|
8082 |
+
'content' => array(),
|
8083 |
+
'datatype' => array(),
|
8084 |
'dir' => array(),
|
8085 |
'draggable' => array(),
|
8086 |
'fallback' => array(
|
8087 |
'value' => '',
|
8088 |
),
|
8089 |
+
'hidden' => array(
|
8090 |
+
'value' => '',
|
8091 |
+
),
|
8092 |
'i-amp-access-id' => array(),
|
8093 |
'id' => array(
|
8094 |
+
'blacklisted_value_regex' => '(^|\\s)(__amp_\\s*|__count__|__definegetter__|__definesetter__|__lookupgetter__|__lookupsetter__|__nosuchmethod__|__parent__|__proto__|__amp_\\s*|\\$p|\\$proxy|acceptcharset|addeventlistener|appendchild|assignedslot|attachshadow|amp|baseuri|checkvalidity|childelementcount|childnodes|classlist|classname|clientheight|clientleft|clienttop|clientwidth|comparedocumentposition|computedname|computedrole|contenteditable|createshadowroot|enqueaction|firstchild|firstelementchild|getanimations|getattribute|getattributens|getattributenode|getattributenodens|getboundingclientrect|getclientrects|getdestinationinsertionpoints|getelementsbyclassname|getelementsbytagname|getelementsbytagnamens|getrootnode|hasattribute|hasattributens|hasattributes|haschildnodes|haspointercapture|i-amphtml-\\s*|innerhtml|innertext|inputmode|insertadjacentelement|insertadjacenthtml|insertadjacenttext|iscontenteditable|isdefaultnamespace|isequalnode|issamenode|lastchild|lastelementchild|lookupnamespaceuri|namespaceuri|nextelementsibling|nextsibling|nodename|nodetype|nodevalue|offsetheight|offsetleft|offsetparent|offsettop|offsetwidth|outerhtml|outertext|ownerdocument|parentelement|parentnode|previouselementsibling|previoussibling|queryselector|queryselectorall|releasepointercapture|removeattribute|removeattributens|removeattributenode|removechild|removeeventlistener|replacechild|reportvalidity|requestpointerlock|scrollheight|scrollintoview|scrollintoviewifneeded|scrollleft|scrollwidth|setattribute|setattributens|setattributenode|setattributenodens|setpointercapture|shadowroot|stylemap|tabindex|tagname|textcontent|tostring|valueof|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)matchesselector|(webkit|moz|ms|o)requestfullscreen|(webkit|moz|ms|o)requestfullscreen)(\\s|$)',
|
8095 |
),
|
8096 |
+
'inlist' => array(),
|
8097 |
'itemid' => array(),
|
8098 |
'itemprop' => array(),
|
8099 |
'itemref' => array(),
|
8106 |
'placeholder' => array(
|
8107 |
'value' => '',
|
8108 |
),
|
8109 |
+
'prefix' => array(),
|
8110 |
+
'property' => array(),
|
8111 |
+
'rel' => array(
|
8112 |
+
'blacklisted_value_regex' => '(^|\\s)(canonical|components|dns-prefetch|import|manifest|preconnect|preload|prerender|serviceworker|stylesheet|subresource)(\\s|$)',
|
8113 |
+
),
|
8114 |
+
'resource' => array(),
|
8115 |
+
'rev' => array(),
|
8116 |
'role' => array(),
|
8117 |
'tabindex' => array(),
|
8118 |
'title' => array(),
|
8119 |
'translate' => array(),
|
8120 |
+
'typeof' => array(),
|
8121 |
'validation-for' => array(),
|
8122 |
'visible-when-invalid' => array(
|
8123 |
'value_regex' => '(badinput|customerror|patternmismatch|rangeoverflow|rangeunderflow|stepmismatch|toolong|typemismatch|valuemissing)',
|
8124 |
),
|
8125 |
+
'vocab' => array(),
|
8126 |
|
8127 |
);
|
8128 |
|
includes/sanitizers/class-amp-audio-sanitizer.php
CHANGED
@@ -1,53 +1,121 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
4 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
class AMP_Audio_Sanitizer extends AMP_Base_Sanitizer {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
public static $tag = 'audio';
|
7 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
private static $script_slug = 'amp-audio';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
private static $script_src = 'https://cdn.ampproject.org/v0/amp-audio-0.1.js';
|
10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
public function get_scripts() {
|
12 |
if ( ! $this->did_convert_elements ) {
|
13 |
return array();
|
14 |
}
|
15 |
-
|
16 |
return array( self::$script_slug => self::$script_src );
|
17 |
}
|
18 |
|
|
|
|
|
|
|
|
|
|
|
19 |
public function sanitize() {
|
20 |
-
$nodes
|
21 |
$num_nodes = $nodes->length;
|
22 |
if ( 0 === $num_nodes ) {
|
23 |
return;
|
24 |
}
|
25 |
|
26 |
for ( $i = $num_nodes - 1; $i >= 0; $i-- ) {
|
27 |
-
$node
|
28 |
$old_attributes = AMP_DOM_Utils::get_node_attributes_as_assoc_array( $node );
|
29 |
|
30 |
$new_attributes = $this->filter_attributes( $old_attributes );
|
31 |
|
32 |
$new_node = AMP_DOM_Utils::create_node( $this->dom, 'amp-audio', $new_attributes );
|
33 |
|
34 |
-
// TODO: `source` does not have closing tag, and DOMDocument doesn't handle it well.
|
35 |
foreach ( $node->childNodes as $child_node ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
$new_child_node = $child_node->cloneNode( true );
|
|
|
|
|
|
|
|
|
37 |
$old_child_attributes = AMP_DOM_Utils::get_node_attributes_as_assoc_array( $new_child_node );
|
38 |
$new_child_attributes = $this->filter_attributes( $old_child_attributes );
|
39 |
|
40 |
-
|
41 |
-
|
42 |
-
|
|
|
|
|
43 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
}
|
45 |
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
|
|
|
|
51 |
if ( 0 === $new_node->childNodes->length && empty( $new_attributes['src'] ) ) {
|
52 |
$node->parentNode->removeChild( $node );
|
53 |
} else {
|
@@ -58,6 +126,24 @@ class AMP_Audio_Sanitizer extends AMP_Base_Sanitizer {
|
|
58 |
}
|
59 |
}
|
60 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
private function filter_attributes( $attributes ) {
|
62 |
$out = array();
|
63 |
|
@@ -83,7 +169,7 @@ class AMP_Audio_Sanitizer extends AMP_Base_Sanitizer {
|
|
83 |
}
|
84 |
break;
|
85 |
|
86 |
-
default
|
87 |
break;
|
88 |
}
|
89 |
}
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Audio_Sanitizer
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class AMP_Audio_Sanitizer
|
10 |
+
*
|
11 |
+
* Converts <audio> tags to <amp-audio>
|
12 |
+
*/
|
13 |
class AMP_Audio_Sanitizer extends AMP_Base_Sanitizer {
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Tag.
|
17 |
+
*
|
18 |
+
* @var string HTML audio tag to identify and replace with AMP version.
|
19 |
+
* @since 0.2
|
20 |
+
*/
|
21 |
public static $tag = 'audio';
|
22 |
|
23 |
+
/**
|
24 |
+
* Script slug.
|
25 |
+
*
|
26 |
+
* @var string AMP HTML audio tag to use in place of HTML's 'audio' tag.
|
27 |
+
*
|
28 |
+
* @since 0.2
|
29 |
+
*/
|
30 |
private static $script_slug = 'amp-audio';
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Script src.
|
34 |
+
*
|
35 |
+
* @var string URL to AMP Project's Audio element javascript file found at cdn.ampproject.org
|
36 |
+
*
|
37 |
+
* @since 0.2
|
38 |
+
*/
|
39 |
private static $script_src = 'https://cdn.ampproject.org/v0/amp-audio-0.1.js';
|
40 |
|
41 |
+
/**
|
42 |
+
* Return one element array containing AMP HTML audio tag and respective Javascript URL
|
43 |
+
*
|
44 |
+
* HTML tags and Javascript URLs found at cdn.ampproject.org
|
45 |
+
*
|
46 |
+
* @since 0.2
|
47 |
+
*
|
48 |
+
* @return string[] Returns AMP HTML audio tag as array key and Javascript URL as array value,
|
49 |
+
* respectively. Will return an empty array if sanitization has yet to be run
|
50 |
+
* or if it did not find any HTML audio elements to convert to AMP equivalents.
|
51 |
+
*/
|
52 |
public function get_scripts() {
|
53 |
if ( ! $this->did_convert_elements ) {
|
54 |
return array();
|
55 |
}
|
|
|
56 |
return array( self::$script_slug => self::$script_src );
|
57 |
}
|
58 |
|
59 |
+
/**
|
60 |
+
* Sanitize the <audio> elements from the HTML contained in this instance's DOMDocument.
|
61 |
+
*
|
62 |
+
* @since 0.2
|
63 |
+
*/
|
64 |
public function sanitize() {
|
65 |
+
$nodes = $this->dom->getElementsByTagName( self::$tag );
|
66 |
$num_nodes = $nodes->length;
|
67 |
if ( 0 === $num_nodes ) {
|
68 |
return;
|
69 |
}
|
70 |
|
71 |
for ( $i = $num_nodes - 1; $i >= 0; $i-- ) {
|
72 |
+
$node = $nodes->item( $i );
|
73 |
$old_attributes = AMP_DOM_Utils::get_node_attributes_as_assoc_array( $node );
|
74 |
|
75 |
$new_attributes = $this->filter_attributes( $old_attributes );
|
76 |
|
77 |
$new_node = AMP_DOM_Utils::create_node( $this->dom, 'amp-audio', $new_attributes );
|
78 |
|
|
|
79 |
foreach ( $node->childNodes as $child_node ) {
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Child node.
|
83 |
+
*
|
84 |
+
* @todo: Fix when `source` has no closing tag as DOMDocument does not handle well.
|
85 |
+
*
|
86 |
+
* @var DOMNode $child_node
|
87 |
+
*/
|
88 |
+
|
89 |
$new_child_node = $child_node->cloneNode( true );
|
90 |
+
if ( ! $new_child_node instanceof DOMElement ) {
|
91 |
+
continue;
|
92 |
+
}
|
93 |
+
|
94 |
$old_child_attributes = AMP_DOM_Utils::get_node_attributes_as_assoc_array( $new_child_node );
|
95 |
$new_child_attributes = $this->filter_attributes( $old_child_attributes );
|
96 |
|
97 |
+
if ( empty( $new_child_attributes['src'] ) ) {
|
98 |
+
continue;
|
99 |
+
}
|
100 |
+
if ( 'source' !== $new_child_node->tagName ) {
|
101 |
+
continue;
|
102 |
}
|
103 |
+
|
104 |
+
// The textContent is invalid for `source` nodes.
|
105 |
+
$new_child_node->textContent = null;
|
106 |
+
|
107 |
+
// Only append source tags with a valid src attribute.
|
108 |
+
$new_node->appendChild( $new_child_node );
|
109 |
+
|
110 |
}
|
111 |
|
112 |
+
/**
|
113 |
+
* If the node has at least one valid source, replace the old node with it.
|
114 |
+
* Otherwise, just remove the node.
|
115 |
+
*
|
116 |
+
* @todo: Add a fallback handler.
|
117 |
+
* @see: https://github.com/ampproject/amphtml/issues/2261
|
118 |
+
*/
|
119 |
if ( 0 === $new_node->childNodes->length && empty( $new_attributes['src'] ) ) {
|
120 |
$node->parentNode->removeChild( $node );
|
121 |
} else {
|
126 |
}
|
127 |
}
|
128 |
|
129 |
+
/**
|
130 |
+
* "Filter" HTML attributes for <amp-audio> elements.
|
131 |
+
*
|
132 |
+
* @since 0.2
|
133 |
+
*
|
134 |
+
* @param string[] $attributes {
|
135 |
+
* Attributes.
|
136 |
+
*
|
137 |
+
* @type string $src Audio URL - Empty if HTTPS required per $this->args['require_https_src']
|
138 |
+
* @type int $width <audio> attribute - Set to numeric value if px or %
|
139 |
+
* @type int $height <audio> attribute - Set to numeric value if px or %
|
140 |
+
* @type string $class <audio> attribute - Pass along if found
|
141 |
+
* @type bool $loop <audio> attribute - Convert 'false' to empty string ''
|
142 |
+
* @type bool $muted <audio> attribute - Convert 'false' to empty string ''
|
143 |
+
* @type bool $autoplay <audio> attribute - Convert 'false' to empty string ''
|
144 |
+
* }
|
145 |
+
* @return array Returns HTML attributes; removes any not specifically declared above from input.
|
146 |
+
*/
|
147 |
private function filter_attributes( $attributes ) {
|
148 |
$out = array();
|
149 |
|
169 |
}
|
170 |
break;
|
171 |
|
172 |
+
default:
|
173 |
break;
|
174 |
}
|
175 |
}
|
includes/sanitizers/class-amp-base-sanitizer.php
CHANGED
@@ -1,36 +1,138 @@
|
|
1 |
<?php
|
|
|
|
|
|
|
|
|
|
|
2 |
|
|
|
|
|
|
|
3 |
abstract class AMP_Base_Sanitizer {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
const FALLBACK_HEIGHT = 400;
|
5 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
protected $DEFAULT_ARGS = array();
|
7 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
protected $dom;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
protected $args;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
protected $did_convert_elements = false;
|
11 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
public function __construct( $dom, $args = array() ) {
|
13 |
-
$this->dom
|
14 |
$this->args = array_merge( $this->DEFAULT_ARGS, $args );
|
15 |
}
|
16 |
|
|
|
|
|
|
|
17 |
abstract public function sanitize();
|
18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
public function get_scripts() {
|
20 |
return array();
|
21 |
}
|
22 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
public function get_styles() {
|
24 |
return array();
|
25 |
}
|
26 |
|
|
|
|
|
|
|
|
|
|
|
27 |
protected function get_body_node() {
|
28 |
return $this->dom->getElementsByTagName( 'body' )->item( 0 );
|
29 |
}
|
30 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
public function sanitize_dimension( $value, $dimension ) {
|
32 |
if ( empty( $value ) ) {
|
33 |
-
return
|
34 |
}
|
35 |
|
36 |
if ( false !== filter_var( $value, FILTER_VALIDATE_INT ) ) {
|
@@ -51,6 +153,20 @@ abstract class AMP_Base_Sanitizer {
|
|
51 |
return '';
|
52 |
}
|
53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
public function enforce_fixed_height( $attributes ) {
|
55 |
if ( empty( $attributes['height'] ) ) {
|
56 |
unset( $attributes['width'] );
|
@@ -71,6 +187,17 @@ abstract class AMP_Base_Sanitizer {
|
|
71 |
*
|
72 |
* See https://github.com/ampproject/amphtml/issues/1280#issuecomment-171533526
|
73 |
* See https://github.com/Automattic/amp-wp/issues/101
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
*/
|
75 |
public function enforce_sizes_attribute( $attributes ) {
|
76 |
if ( ! isset( $attributes['width'], $attributes['height'] ) ) {
|
@@ -89,6 +216,25 @@ abstract class AMP_Base_Sanitizer {
|
|
89 |
return $attributes;
|
90 |
}
|
91 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
92 |
public function add_or_append_attribute( &$attributes, $key, $value, $separator = ' ' ) {
|
93 |
if ( isset( $attributes[ $key ] ) ) {
|
94 |
$attributes[ $key ] .= $separator . $value;
|
@@ -99,22 +245,23 @@ abstract class AMP_Base_Sanitizer {
|
|
99 |
|
100 |
/**
|
101 |
* Decide if we should remove a src attribute if https is required.
|
|
|
102 |
* If not required, the implementing class may want to try and force https instead.
|
103 |
*
|
104 |
-
* @param string $
|
105 |
-
* @param boolean $force_https
|
106 |
-
* @return string
|
107 |
*/
|
108 |
public function maybe_enforce_https_src( $src, $force_https = false ) {
|
109 |
$protocol = strtok( $src, ':' );
|
110 |
if ( 'https' !== $protocol ) {
|
111 |
-
// Check if https is required
|
112 |
if ( isset( $this->args['require_https_src'] ) && true === $this->args['require_https_src'] ) {
|
113 |
// Remove the src. Let the implementing class decide what do from here.
|
114 |
$src = '';
|
115 |
} elseif ( ( ! isset( $this->args['require_https_src'] ) || false === $this->args['require_https_src'] )
|
116 |
&& true === $force_https ) {
|
117 |
-
// Don't remove the src, but force https instead
|
118 |
$src = set_url_scheme( $src, 'https' );
|
119 |
}
|
120 |
}
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Base_Sanitizer
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
|
8 |
+
/**
|
9 |
+
* Class AMP_Base_Sanitizer
|
10 |
+
*/
|
11 |
abstract class AMP_Base_Sanitizer {
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Value used with the height attribute in an $attributes parameter is empty.
|
15 |
+
*
|
16 |
+
* @since 0.3.3
|
17 |
+
*
|
18 |
+
* @const int
|
19 |
+
*/
|
20 |
const FALLBACK_HEIGHT = 400;
|
21 |
|
22 |
+
/**
|
23 |
+
* Placeholder for default args, to be set in child classes.
|
24 |
+
*
|
25 |
+
* @since 0.2
|
26 |
+
*
|
27 |
+
* @var array
|
28 |
+
*/
|
29 |
protected $DEFAULT_ARGS = array();
|
30 |
|
31 |
+
/**
|
32 |
+
* DOM.
|
33 |
+
*
|
34 |
+
* @var DOMDocument A standard PHP representation of an HTML document in object form.
|
35 |
+
*
|
36 |
+
* @since 0.2
|
37 |
+
*/
|
38 |
protected $dom;
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Array of flags used to control sanitization.
|
42 |
+
*
|
43 |
+
* @var array {
|
44 |
+
* @type int $content_max_width
|
45 |
+
* @type bool $add_placeholder
|
46 |
+
* @type bool $require_https_src
|
47 |
+
* @type string[] $amp_allowed_tags
|
48 |
+
* @type string[] $amp_globally_allowed_attributes
|
49 |
+
* @type string[] $amp_layout_allowed_attributes
|
50 |
+
* }
|
51 |
+
*/
|
52 |
protected $args;
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Flag to be set in child class' sanitize() method indicating if the
|
56 |
+
* HTML contained in the DOMDocument has been santized yet or not.
|
57 |
+
*
|
58 |
+
* @since 0.2
|
59 |
+
*
|
60 |
+
* @var bool
|
61 |
+
*/
|
62 |
protected $did_convert_elements = false;
|
63 |
|
64 |
+
/**
|
65 |
+
* AMP_Base_Sanitizer constructor.
|
66 |
+
*
|
67 |
+
* @since 0.2
|
68 |
+
*
|
69 |
+
* @param DOMDocument $dom Represents the HTML document to sanitize.
|
70 |
+
* @param array $args array {
|
71 |
+
* Args.
|
72 |
+
*
|
73 |
+
* @type int $content_max_width
|
74 |
+
* @type bool $add_placeholder
|
75 |
+
* @type bool $require_https_src
|
76 |
+
* @type string[] $amp_allowed_tags
|
77 |
+
* @type string[] $amp_globally_allowed_attributes
|
78 |
+
* @type string[] $amp_layout_allowed_attributes
|
79 |
+
* }
|
80 |
+
*/
|
81 |
public function __construct( $dom, $args = array() ) {
|
82 |
+
$this->dom = $dom;
|
83 |
$this->args = array_merge( $this->DEFAULT_ARGS, $args );
|
84 |
}
|
85 |
|
86 |
+
/**
|
87 |
+
* Sanitize the HTML contained in the DOMDocument received by the constructor
|
88 |
+
*/
|
89 |
abstract public function sanitize();
|
90 |
|
91 |
+
/**
|
92 |
+
* Return array of values that would be valid as an HTML `script` element.
|
93 |
+
*
|
94 |
+
* Array keys are AMP element names and array values are their respective
|
95 |
+
* Javascript URLs from https://cdn.ampproject.org
|
96 |
+
*
|
97 |
+
* @since 0.2
|
98 |
+
*
|
99 |
+
* @return string[] This are empty in this the base class.
|
100 |
+
*/
|
101 |
public function get_scripts() {
|
102 |
return array();
|
103 |
}
|
104 |
|
105 |
+
/**
|
106 |
+
* Return array of values that would be valid as an HTML `style` attribute.
|
107 |
+
*
|
108 |
+
* @since 0.4
|
109 |
+
*
|
110 |
+
* @return string[] This are empty in this the base class.
|
111 |
+
*/
|
112 |
public function get_styles() {
|
113 |
return array();
|
114 |
}
|
115 |
|
116 |
+
/**
|
117 |
+
* Get HTML body as DOMElement from DOMDocument received by the constructor.
|
118 |
+
*
|
119 |
+
* @return DOMElement
|
120 |
+
*/
|
121 |
protected function get_body_node() {
|
122 |
return $this->dom->getElementsByTagName( 'body' )->item( 0 );
|
123 |
}
|
124 |
|
125 |
+
/**
|
126 |
+
* Sanitizes a CSS dimension specifier while being sensitive to dimension context.
|
127 |
+
*
|
128 |
+
* @param string $value A valid CSS dimension specifier; e.g. 50, 50px, 50%.
|
129 |
+
* @param string $dimension 'width' or ignored. 'width' only affects $values ending in '%'.
|
130 |
+
*
|
131 |
+
* @return float|int|string Returns a numeric dimension value, or an empty string.
|
132 |
+
*/
|
133 |
public function sanitize_dimension( $value, $dimension ) {
|
134 |
if ( empty( $value ) ) {
|
135 |
+
return '';
|
136 |
}
|
137 |
|
138 |
if ( false !== filter_var( $value, FILTER_VALIDATE_INT ) ) {
|
153 |
return '';
|
154 |
}
|
155 |
|
156 |
+
/**
|
157 |
+
* Enforce fixed height.
|
158 |
+
*
|
159 |
+
* @param string[] $attributes {
|
160 |
+
* Attributes.
|
161 |
+
*
|
162 |
+
* @type int $height
|
163 |
+
* @type int $width
|
164 |
+
* @type string $sizes
|
165 |
+
* @type string $class
|
166 |
+
* @type string $layout
|
167 |
+
* }
|
168 |
+
* @return string[]
|
169 |
+
*/
|
170 |
public function enforce_fixed_height( $attributes ) {
|
171 |
if ( empty( $attributes['height'] ) ) {
|
172 |
unset( $attributes['width'] );
|
187 |
*
|
188 |
* See https://github.com/ampproject/amphtml/issues/1280#issuecomment-171533526
|
189 |
* See https://github.com/Automattic/amp-wp/issues/101
|
190 |
+
*
|
191 |
+
* @param string[] $attributes {
|
192 |
+
* Attributes.
|
193 |
+
*
|
194 |
+
* @type int $height
|
195 |
+
* @type int $width
|
196 |
+
* @type string $sizes
|
197 |
+
* @type string $class
|
198 |
+
* @type string $layout
|
199 |
+
* }
|
200 |
+
* @return string[]
|
201 |
*/
|
202 |
public function enforce_sizes_attribute( $attributes ) {
|
203 |
if ( ! isset( $attributes['width'], $attributes['height'] ) ) {
|
216 |
return $attributes;
|
217 |
}
|
218 |
|
219 |
+
/**
|
220 |
+
* Adds or appends key and value to list of attributes
|
221 |
+
*
|
222 |
+
* Adds key and value to list of attributes, or if the key already exists in the array
|
223 |
+
* it concatenates to existing attribute separator by a space or other supplied separator.
|
224 |
+
*
|
225 |
+
* @param string[] $attributes {
|
226 |
+
* Attributes.
|
227 |
+
*
|
228 |
+
* @type int $height
|
229 |
+
* @type int $width
|
230 |
+
* @type string $sizes
|
231 |
+
* @type string $class
|
232 |
+
* @type string $layout
|
233 |
+
* }
|
234 |
+
* @param string $key Valid associative array index to add.
|
235 |
+
* @param string $value Value to add or append to array indexed at the key.
|
236 |
+
* @param string $separator Optional; defaults to space but some other separator if needed.
|
237 |
+
*/
|
238 |
public function add_or_append_attribute( &$attributes, $key, $value, $separator = ' ' ) {
|
239 |
if ( isset( $attributes[ $key ] ) ) {
|
240 |
$attributes[ $key ] .= $separator . $value;
|
245 |
|
246 |
/**
|
247 |
* Decide if we should remove a src attribute if https is required.
|
248 |
+
*
|
249 |
* If not required, the implementing class may want to try and force https instead.
|
250 |
*
|
251 |
+
* @param string $src URL to convert to HTTPS if forced, or made empty if $args['require_https_src'].
|
252 |
+
* @param boolean $force_https Force setting of HTTPS if true.
|
253 |
+
* @return string URL which may have been updated with HTTPS, or may have been made empty.
|
254 |
*/
|
255 |
public function maybe_enforce_https_src( $src, $force_https = false ) {
|
256 |
$protocol = strtok( $src, ':' );
|
257 |
if ( 'https' !== $protocol ) {
|
258 |
+
// Check if https is required.
|
259 |
if ( isset( $this->args['require_https_src'] ) && true === $this->args['require_https_src'] ) {
|
260 |
// Remove the src. Let the implementing class decide what do from here.
|
261 |
$src = '';
|
262 |
} elseif ( ( ! isset( $this->args['require_https_src'] ) || false === $this->args['require_https_src'] )
|
263 |
&& true === $force_https ) {
|
264 |
+
// Don't remove the src, but force https instead.
|
265 |
$src = set_url_scheme( $src, 'https' );
|
266 |
}
|
267 |
}
|
includes/sanitizers/class-amp-blacklist-sanitizer.php
CHANGED
@@ -1,6 +1,9 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
|
|
|
|
|
|
4 |
|
5 |
/**
|
6 |
* Strips blacklisted tags and attributes from content.
|
@@ -8,28 +11,43 @@ require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-base-sanitizer.php' )
|
|
8 |
* See following for blacklist:
|
9 |
* https://github.com/ampproject/amphtml/blob/master/spec/amp-html-format.md#html-tags
|
10 |
*
|
11 |
-
*
|
12 |
-
*
|
13 |
*/
|
14 |
class AMP_Blacklist_Sanitizer extends AMP_Base_Sanitizer {
|
15 |
const PATTERN_REL_WP_ATTACHMENT = '#wp-att-([\d]+)#';
|
16 |
|
|
|
|
|
|
|
|
|
|
|
17 |
protected $DEFAULT_ARGS = array(
|
18 |
'add_blacklisted_protocols' => array(),
|
19 |
'add_blacklisted_tags' => array(),
|
20 |
'add_blacklisted_attributes' => array(),
|
21 |
);
|
22 |
|
|
|
|
|
|
|
23 |
public function sanitize() {
|
24 |
-
$blacklisted_tags
|
25 |
$blacklisted_attributes = $this->get_blacklisted_attributes();
|
26 |
-
$blacklisted_protocols
|
27 |
|
28 |
$body = $this->get_body_node();
|
29 |
$this->strip_tags( $body, $blacklisted_tags );
|
30 |
$this->strip_attributes_recursive( $body, $blacklisted_attributes, $blacklisted_protocols );
|
31 |
}
|
32 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
private function strip_attributes_recursive( $node, $bad_attributes, $bad_protocols ) {
|
34 |
if ( XML_ELEMENT_NODE !== $node->nodeType ) {
|
35 |
return;
|
@@ -50,14 +68,14 @@ class AMP_Blacklist_Sanitizer extends AMP_Base_Sanitizer {
|
|
50 |
if ( $node->hasAttributes() ) {
|
51 |
$length = $node->attributes->length;
|
52 |
for ( $i = $length - 1; $i >= 0; $i-- ) {
|
53 |
-
$attribute
|
54 |
$attribute_name = strtolower( $attribute->name );
|
55 |
if ( in_array( $attribute_name, $bad_attributes, true ) ) {
|
56 |
$node->removeAttribute( $attribute_name );
|
57 |
continue;
|
58 |
}
|
59 |
|
60 |
-
// on* attributes (like onclick) are a special case
|
61 |
if ( 0 === stripos( $attribute_name, 'on' ) && 'on' !== $attribute_name ) {
|
62 |
$node->removeAttribute( $attribute_name );
|
63 |
continue;
|
@@ -75,16 +93,22 @@ class AMP_Blacklist_Sanitizer extends AMP_Base_Sanitizer {
|
|
75 |
}
|
76 |
}
|
77 |
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
private function strip_tags( $node, $tag_names ) {
|
79 |
foreach ( $tag_names as $tag_name ) {
|
80 |
$elements = $node->getElementsByTagName( $tag_name );
|
81 |
-
$length
|
82 |
if ( 0 === $length ) {
|
83 |
continue;
|
84 |
}
|
85 |
|
86 |
for ( $i = $length - 1; $i >= 0; $i-- ) {
|
87 |
-
$element
|
88 |
$parent_node = $element->parentNode;
|
89 |
$parent_node->removeChild( $element );
|
90 |
|
@@ -95,6 +119,12 @@ class AMP_Blacklist_Sanitizer extends AMP_Base_Sanitizer {
|
|
95 |
}
|
96 |
}
|
97 |
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
private function sanitize_a_attribute( $node, $attribute ) {
|
99 |
$attribute_name = strtolower( $attribute->name );
|
100 |
|
@@ -117,23 +147,31 @@ class AMP_Blacklist_Sanitizer extends AMP_Base_Sanitizer {
|
|
117 |
// _new is not allowed; swap with _blank
|
118 |
$node->setAttribute( $attribute_name, '_blank' );
|
119 |
} else {
|
120 |
-
//
|
121 |
$node->removeAttribute( $attribute_name );
|
122 |
}
|
123 |
}
|
124 |
}
|
125 |
|
|
|
|
|
|
|
|
|
|
|
|
|
126 |
private function validate_a_node( $node ) {
|
127 |
-
// Get the href attribute
|
128 |
$href = $node->getAttribute( 'href' );
|
129 |
|
130 |
if ( empty( $href ) ) {
|
131 |
-
|
132 |
-
|
|
|
|
|
133 |
return $node->hasAttribute( 'name' ) || $node->hasAttribute( 'id' );
|
134 |
}
|
135 |
|
136 |
-
// If this is an anchor link, just return true
|
137 |
if ( 0 === strpos( $href, '#' ) ) {
|
138 |
return true;
|
139 |
}
|
@@ -143,9 +181,9 @@ class AMP_Blacklist_Sanitizer extends AMP_Base_Sanitizer {
|
|
143 |
$href = untrailingslashit( get_home_url() ) . $href;
|
144 |
}
|
145 |
|
146 |
-
$valid_protocols
|
147 |
-
$special_protocols = array( 'tel', 'sms' ); //
|
148 |
-
$protocol
|
149 |
|
150 |
if ( false === filter_var( $href, FILTER_VALIDATE_URL )
|
151 |
&& ! in_array( $protocol, $special_protocols, true ) ) {
|
@@ -159,6 +197,13 @@ class AMP_Blacklist_Sanitizer extends AMP_Base_Sanitizer {
|
|
159 |
return true;
|
160 |
}
|
161 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
162 |
private function replace_node_with_children( $node, $bad_attributes, $bad_protocols ) {
|
163 |
// If the node has children and also has a parent node,
|
164 |
// clone and re-add all the children just before current node.
|
@@ -176,8 +221,15 @@ class AMP_Blacklist_Sanitizer extends AMP_Base_Sanitizer {
|
|
176 |
}
|
177 |
}
|
178 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
179 |
private function merge_defaults_with_args( $key, $values ) {
|
180 |
-
// Merge default values with user specified args
|
181 |
if ( ! empty( $this->args[ $key ] )
|
182 |
&& is_array( $this->args[ $key ] ) ) {
|
183 |
$values = array_merge( $values, $this->args[ $key ] );
|
@@ -186,12 +238,22 @@ class AMP_Blacklist_Sanitizer extends AMP_Base_Sanitizer {
|
|
186 |
return $values;
|
187 |
}
|
188 |
|
|
|
|
|
|
|
|
|
|
|
189 |
private function get_blacklisted_protocols() {
|
190 |
return $this->merge_defaults_with_args( 'add_blacklisted_protocols', array(
|
191 |
'javascript',
|
192 |
) );
|
193 |
}
|
194 |
|
|
|
|
|
|
|
|
|
|
|
195 |
private function get_blacklisted_tags() {
|
196 |
return $this->merge_defaults_with_args( 'add_blacklisted_tags', array(
|
197 |
'script',
|
@@ -215,17 +277,16 @@ class AMP_Blacklist_Sanitizer extends AMP_Base_Sanitizer {
|
|
215 |
'embed',
|
216 |
'embedvideo',
|
217 |
|
218 |
-
// Other weird ones
|
219 |
'comments-count',
|
220 |
-
|
221 |
-
// These are converted into amp-* versions
|
222 |
-
//'img',
|
223 |
-
//'video',
|
224 |
-
//'audio',
|
225 |
-
//'iframe',
|
226 |
) );
|
227 |
}
|
228 |
|
|
|
|
|
|
|
|
|
|
|
229 |
private function get_blacklisted_attributes() {
|
230 |
return $this->merge_defaults_with_args( 'add_blacklisted_attributes', array(
|
231 |
'style',
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Blacklist_Sanitizer
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
|
8 |
/**
|
9 |
* Strips blacklisted tags and attributes from content.
|
11 |
* See following for blacklist:
|
12 |
* https://github.com/ampproject/amphtml/blob/master/spec/amp-html-format.md#html-tags
|
13 |
*
|
14 |
+
* @since 0.5 This has been replaced by AMP_Tag_And_Attribute_Sanitizer but is kept around for back-compat.
|
15 |
+
* @deprecated
|
16 |
*/
|
17 |
class AMP_Blacklist_Sanitizer extends AMP_Base_Sanitizer {
|
18 |
const PATTERN_REL_WP_ATTACHMENT = '#wp-att-([\d]+)#';
|
19 |
|
20 |
+
/**
|
21 |
+
* Default args.
|
22 |
+
*
|
23 |
+
* @var array
|
24 |
+
*/
|
25 |
protected $DEFAULT_ARGS = array(
|
26 |
'add_blacklisted_protocols' => array(),
|
27 |
'add_blacklisted_tags' => array(),
|
28 |
'add_blacklisted_attributes' => array(),
|
29 |
);
|
30 |
|
31 |
+
/**
|
32 |
+
* Sanitize.
|
33 |
+
*/
|
34 |
public function sanitize() {
|
35 |
+
$blacklisted_tags = $this->get_blacklisted_tags();
|
36 |
$blacklisted_attributes = $this->get_blacklisted_attributes();
|
37 |
+
$blacklisted_protocols = $this->get_blacklisted_protocols();
|
38 |
|
39 |
$body = $this->get_body_node();
|
40 |
$this->strip_tags( $body, $blacklisted_tags );
|
41 |
$this->strip_attributes_recursive( $body, $blacklisted_attributes, $blacklisted_protocols );
|
42 |
}
|
43 |
|
44 |
+
/**
|
45 |
+
* Strip attributes recursively.
|
46 |
+
*
|
47 |
+
* @param DOMNode $node DOM Node.
|
48 |
+
* @param array $bad_attributes Bad attributes.
|
49 |
+
* @param array $bad_protocols Bad protocols.
|
50 |
+
*/
|
51 |
private function strip_attributes_recursive( $node, $bad_attributes, $bad_protocols ) {
|
52 |
if ( XML_ELEMENT_NODE !== $node->nodeType ) {
|
53 |
return;
|
68 |
if ( $node->hasAttributes() ) {
|
69 |
$length = $node->attributes->length;
|
70 |
for ( $i = $length - 1; $i >= 0; $i-- ) {
|
71 |
+
$attribute = $node->attributes->item( $i );
|
72 |
$attribute_name = strtolower( $attribute->name );
|
73 |
if ( in_array( $attribute_name, $bad_attributes, true ) ) {
|
74 |
$node->removeAttribute( $attribute_name );
|
75 |
continue;
|
76 |
}
|
77 |
|
78 |
+
// The on* attributes (like onclick) are a special case.
|
79 |
if ( 0 === stripos( $attribute_name, 'on' ) && 'on' !== $attribute_name ) {
|
80 |
$node->removeAttribute( $attribute_name );
|
81 |
continue;
|
93 |
}
|
94 |
}
|
95 |
|
96 |
+
/**
|
97 |
+
* Strip tags.
|
98 |
+
*
|
99 |
+
* @param DOMElement $node Node.
|
100 |
+
* @param string[] $tag_names Tag names.
|
101 |
+
*/
|
102 |
private function strip_tags( $node, $tag_names ) {
|
103 |
foreach ( $tag_names as $tag_name ) {
|
104 |
$elements = $node->getElementsByTagName( $tag_name );
|
105 |
+
$length = $elements->length;
|
106 |
if ( 0 === $length ) {
|
107 |
continue;
|
108 |
}
|
109 |
|
110 |
for ( $i = $length - 1; $i >= 0; $i-- ) {
|
111 |
+
$element = $elements->item( $i );
|
112 |
$parent_node = $element->parentNode;
|
113 |
$parent_node->removeChild( $element );
|
114 |
|
119 |
}
|
120 |
}
|
121 |
|
122 |
+
/**
|
123 |
+
* Sanitize attribute.
|
124 |
+
*
|
125 |
+
* @param DOMElement $node Node.
|
126 |
+
* @param DOMAttr $attribute Attribute.
|
127 |
+
*/
|
128 |
private function sanitize_a_attribute( $node, $attribute ) {
|
129 |
$attribute_name = strtolower( $attribute->name );
|
130 |
|
147 |
// _new is not allowed; swap with _blank
|
148 |
$node->setAttribute( $attribute_name, '_blank' );
|
149 |
} else {
|
150 |
+
// Only _blank is allowed.
|
151 |
$node->removeAttribute( $attribute_name );
|
152 |
}
|
153 |
}
|
154 |
}
|
155 |
|
156 |
+
/**
|
157 |
+
* Validate node.
|
158 |
+
*
|
159 |
+
* @param DOMElement $node Node.
|
160 |
+
* @return bool
|
161 |
+
*/
|
162 |
private function validate_a_node( $node ) {
|
163 |
+
// Get the href attribute.
|
164 |
$href = $node->getAttribute( 'href' );
|
165 |
|
166 |
if ( empty( $href ) ) {
|
167 |
+
/*
|
168 |
+
* If no href, check that a is an anchor or not.
|
169 |
+
* We don't need to validate anchors any further.
|
170 |
+
*/
|
171 |
return $node->hasAttribute( 'name' ) || $node->hasAttribute( 'id' );
|
172 |
}
|
173 |
|
174 |
+
// If this is an anchor link, just return true.
|
175 |
if ( 0 === strpos( $href, '#' ) ) {
|
176 |
return true;
|
177 |
}
|
181 |
$href = untrailingslashit( get_home_url() ) . $href;
|
182 |
}
|
183 |
|
184 |
+
$valid_protocols = array( 'http', 'https', 'mailto', 'sms', 'tel', 'viber', 'whatsapp' );
|
185 |
+
$special_protocols = array( 'tel', 'sms' ); // These ones don't valid with `filter_var+FILTER_VALIDATE_URL`.
|
186 |
+
$protocol = strtok( $href, ':' );
|
187 |
|
188 |
if ( false === filter_var( $href, FILTER_VALIDATE_URL )
|
189 |
&& ! in_array( $protocol, $special_protocols, true ) ) {
|
197 |
return true;
|
198 |
}
|
199 |
|
200 |
+
/**
|
201 |
+
* Replace node with children.
|
202 |
+
*
|
203 |
+
* @param DOMElement $node Node.
|
204 |
+
* @param array $bad_attributes Bad attributes.
|
205 |
+
* @param array $bad_protocols Bad protocols.
|
206 |
+
*/
|
207 |
private function replace_node_with_children( $node, $bad_attributes, $bad_protocols ) {
|
208 |
// If the node has children and also has a parent node,
|
209 |
// clone and re-add all the children just before current node.
|
221 |
}
|
222 |
}
|
223 |
|
224 |
+
/**
|
225 |
+
* Merge defaults with args.
|
226 |
+
*
|
227 |
+
* @param string $key Key.
|
228 |
+
* @param array $values Values.
|
229 |
+
* @return array Merged args.
|
230 |
+
*/
|
231 |
private function merge_defaults_with_args( $key, $values ) {
|
232 |
+
// Merge default values with user specified args.
|
233 |
if ( ! empty( $this->args[ $key ] )
|
234 |
&& is_array( $this->args[ $key ] ) ) {
|
235 |
$values = array_merge( $values, $this->args[ $key ] );
|
238 |
return $values;
|
239 |
}
|
240 |
|
241 |
+
/**
|
242 |
+
* Get blacklisted protocols.
|
243 |
+
*
|
244 |
+
* @return array Protocols.
|
245 |
+
*/
|
246 |
private function get_blacklisted_protocols() {
|
247 |
return $this->merge_defaults_with_args( 'add_blacklisted_protocols', array(
|
248 |
'javascript',
|
249 |
) );
|
250 |
}
|
251 |
|
252 |
+
/**
|
253 |
+
* Get blacklisted tags.
|
254 |
+
*
|
255 |
+
* @return array Tags.
|
256 |
+
*/
|
257 |
private function get_blacklisted_tags() {
|
258 |
return $this->merge_defaults_with_args( 'add_blacklisted_tags', array(
|
259 |
'script',
|
277 |
'embed',
|
278 |
'embedvideo',
|
279 |
|
280 |
+
// Other weird ones.
|
281 |
'comments-count',
|
|
|
|
|
|
|
|
|
|
|
|
|
282 |
) );
|
283 |
}
|
284 |
|
285 |
+
/**
|
286 |
+
* Get blacklisted attributes.
|
287 |
+
*
|
288 |
+
* @return array Attributes.
|
289 |
+
*/
|
290 |
private function get_blacklisted_attributes() {
|
291 |
return $this->merge_defaults_with_args( 'add_blacklisted_attributes', array(
|
292 |
'style',
|
includes/sanitizers/class-amp-iframe-sanitizer.php
CHANGED
@@ -1,50 +1,114 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
|
|
|
|
|
|
4 |
|
5 |
/**
|
|
|
|
|
6 |
* Converts <iframe> tags to <amp-iframe>
|
7 |
*/
|
8 |
class AMP_Iframe_Sanitizer extends AMP_Base_Sanitizer {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
const FALLBACK_HEIGHT = 400;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
const SANDBOX_DEFAULTS = 'allow-scripts allow-same-origin';
|
11 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
public static $tag = 'iframe';
|
13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
private static $script_slug = 'amp-iframe';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
private static $script_src = 'https://cdn.ampproject.org/v0/amp-iframe-0.1.js';
|
16 |
|
|
|
|
|
|
|
|
|
|
|
17 |
protected $DEFAULT_ARGS = array(
|
18 |
'add_placeholder' => false,
|
19 |
);
|
20 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
public function get_scripts() {
|
22 |
if ( ! $this->did_convert_elements ) {
|
23 |
return array();
|
24 |
}
|
25 |
-
|
26 |
return array( self::$script_slug => self::$script_src );
|
27 |
}
|
28 |
|
|
|
|
|
|
|
|
|
|
|
29 |
public function sanitize() {
|
30 |
-
$nodes
|
31 |
$num_nodes = $nodes->length;
|
32 |
if ( 0 === $num_nodes ) {
|
33 |
return;
|
34 |
}
|
35 |
|
36 |
for ( $i = $num_nodes - 1; $i >= 0; $i-- ) {
|
37 |
-
$node
|
38 |
$old_attributes = AMP_DOM_Utils::get_node_attributes_as_assoc_array( $node );
|
39 |
|
40 |
$new_attributes = $this->filter_attributes( $old_attributes );
|
41 |
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
|
|
48 |
if ( empty( $new_attributes['src'] ) ) {
|
49 |
$node->parentNode->removeChild( $node );
|
50 |
continue;
|
@@ -63,20 +127,40 @@ class AMP_Iframe_Sanitizer extends AMP_Base_Sanitizer {
|
|
63 |
}
|
64 |
|
65 |
$parent_node = $node->parentNode;
|
66 |
-
if ( 'p'
|
67 |
-
|
|
|
|
|
68 |
$parent_node->removeChild( $node );
|
69 |
$parent_node->parentNode->insertBefore( $new_node, $parent_node->nextSibling );
|
70 |
|
71 |
if ( AMP_DOM_Utils::is_node_empty( $parent_node ) ) {
|
72 |
$parent_node->parentNode->removeChild( $parent_node );
|
73 |
}
|
74 |
-
} else {
|
75 |
-
$parent_node->replaceChild( $new_node, $node );
|
76 |
}
|
77 |
}
|
78 |
}
|
79 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
private function filter_attributes( $attributes ) {
|
81 |
$out = array();
|
82 |
|
@@ -111,7 +195,7 @@ class AMP_Iframe_Sanitizer extends AMP_Base_Sanitizer {
|
|
111 |
}
|
112 |
break;
|
113 |
|
114 |
-
default
|
115 |
break;
|
116 |
}
|
117 |
}
|
@@ -123,6 +207,19 @@ class AMP_Iframe_Sanitizer extends AMP_Base_Sanitizer {
|
|
123 |
return $out;
|
124 |
}
|
125 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
126 |
private function build_placeholder( $parent_attributes ) {
|
127 |
$placeholder_node = AMP_DOM_Utils::create_node( $this->dom, 'div', array(
|
128 |
'placeholder' => '',
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Iframe_Sanitizer
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
|
8 |
/**
|
9 |
+
* Class AMP_Iframe_Sanitizer
|
10 |
+
*
|
11 |
* Converts <iframe> tags to <amp-iframe>
|
12 |
*/
|
13 |
class AMP_Iframe_Sanitizer extends AMP_Base_Sanitizer {
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Value used for height attribute when $attributes['height'] is empty.
|
17 |
+
*
|
18 |
+
* @since 0.2
|
19 |
+
*
|
20 |
+
* @const int
|
21 |
+
*/
|
22 |
const FALLBACK_HEIGHT = 400;
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Default values for sandboxing IFrame.
|
26 |
+
*
|
27 |
+
* @since 0.2
|
28 |
+
*
|
29 |
+
* @const int
|
30 |
+
*/
|
31 |
const SANDBOX_DEFAULTS = 'allow-scripts allow-same-origin';
|
32 |
|
33 |
+
/**
|
34 |
+
* Tag.
|
35 |
+
*
|
36 |
+
* @var string HTML <iframe> tag to identify and replace with AMP version.
|
37 |
+
*
|
38 |
+
* @since 0.2
|
39 |
+
*/
|
40 |
public static $tag = 'iframe';
|
41 |
|
42 |
+
/**
|
43 |
+
* Script slug.
|
44 |
+
*
|
45 |
+
* @var string AMP HTML tag to use in place of HTML's <iframe> tag.
|
46 |
+
*
|
47 |
+
* @since 0.2
|
48 |
+
*/
|
49 |
private static $script_slug = 'amp-iframe';
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Script src.
|
53 |
+
*
|
54 |
+
* @var string URL to AMP Project's IFrame element's JavaScript file found at cdn.ampproject.org
|
55 |
+
*
|
56 |
+
* @since 0.2
|
57 |
+
*/
|
58 |
private static $script_src = 'https://cdn.ampproject.org/v0/amp-iframe-0.1.js';
|
59 |
|
60 |
+
/**
|
61 |
+
* Default args.
|
62 |
+
*
|
63 |
+
* @var array
|
64 |
+
*/
|
65 |
protected $DEFAULT_ARGS = array(
|
66 |
'add_placeholder' => false,
|
67 |
);
|
68 |
|
69 |
+
/**
|
70 |
+
* Return one element array containing AMP HTML iframe tag and respective Javascript URL
|
71 |
+
*
|
72 |
+
* HTML tags and Javascript URLs found at cdn.ampproject.org
|
73 |
+
*
|
74 |
+
* @since 0.2
|
75 |
+
*
|
76 |
+
* @return string[] Returns AMP HTML iframe tag as array key and Javascript URL as array value,
|
77 |
+
* respectively. Will return an empty array if sanitization has yet to be run
|
78 |
+
* or if it did not find any HTML iframe elements to convert to AMP equivalents.
|
79 |
+
*/
|
80 |
public function get_scripts() {
|
81 |
if ( ! $this->did_convert_elements ) {
|
82 |
return array();
|
83 |
}
|
|
|
84 |
return array( self::$script_slug => self::$script_src );
|
85 |
}
|
86 |
|
87 |
+
/**
|
88 |
+
* Sanitize the <iframe> elements from the HTML contained in this instance's DOMDocument.
|
89 |
+
*
|
90 |
+
* @since 0.2
|
91 |
+
*/
|
92 |
public function sanitize() {
|
93 |
+
$nodes = $this->dom->getElementsByTagName( self::$tag );
|
94 |
$num_nodes = $nodes->length;
|
95 |
if ( 0 === $num_nodes ) {
|
96 |
return;
|
97 |
}
|
98 |
|
99 |
for ( $i = $num_nodes - 1; $i >= 0; $i-- ) {
|
100 |
+
$node = $nodes->item( $i );
|
101 |
$old_attributes = AMP_DOM_Utils::get_node_attributes_as_assoc_array( $node );
|
102 |
|
103 |
$new_attributes = $this->filter_attributes( $old_attributes );
|
104 |
|
105 |
+
/**
|
106 |
+
* If the src doesn't exist, remove the node. Either it never
|
107 |
+
* existed or was invalidated while filtering attributes above.
|
108 |
+
*
|
109 |
+
* @todo: add a filter to allow for a fallback element in this instance.
|
110 |
+
* @see: https://github.com/ampproject/amphtml/issues/2261
|
111 |
+
*/
|
112 |
if ( empty( $new_attributes['src'] ) ) {
|
113 |
$node->parentNode->removeChild( $node );
|
114 |
continue;
|
127 |
}
|
128 |
|
129 |
$parent_node = $node->parentNode;
|
130 |
+
if ( 'p' !== strtolower( $parent_node->tagName ) ) {
|
131 |
+
$parent_node->replaceChild( $new_node, $node );
|
132 |
+
} else {
|
133 |
+
// AMP does not like iframes in <p> tags.
|
134 |
$parent_node->removeChild( $node );
|
135 |
$parent_node->parentNode->insertBefore( $new_node, $parent_node->nextSibling );
|
136 |
|
137 |
if ( AMP_DOM_Utils::is_node_empty( $parent_node ) ) {
|
138 |
$parent_node->parentNode->removeChild( $parent_node );
|
139 |
}
|
|
|
|
|
140 |
}
|
141 |
}
|
142 |
}
|
143 |
|
144 |
+
/**
|
145 |
+
* "Filter" HTML attributes for <amp-iframe> elements.
|
146 |
+
*
|
147 |
+
* @since 0.2
|
148 |
+
*
|
149 |
+
* @param string[] $attributes {
|
150 |
+
* Attributes.
|
151 |
+
*
|
152 |
+
* @type string $src IFrame URL - Empty if HTTPS required per $this->args['require_https_src']
|
153 |
+
* @type int $width <iframe> width attribute - Set to numeric value if px or %
|
154 |
+
* @type int $height <iframe> width attribute - Set to numeric value if px or %
|
155 |
+
* @type string $sandbox <iframe> `sandbox` attribute - Pass along if found; default to value of self::SANDBOX_DEFAULTS
|
156 |
+
* @type string $class <iframe> `class` attribute - Pass along if found
|
157 |
+
* @type string $sizes <iframe> `sizes` attribute - Pass along if found
|
158 |
+
* @type int $frameborder <iframe> `frameborder` attribute - Filter to '0' or '1'; default to '0'
|
159 |
+
* @type bool $allowfullscreen <iframe> `allowfullscreen` attribute - Convert 'false' to empty string ''
|
160 |
+
* @type bool $allowtransparency <iframe> `allowtransparency` attribute - Convert 'false' to empty string ''
|
161 |
+
* }
|
162 |
+
* @return array Returns HTML attributes; removes any not specifically declared above from input.
|
163 |
+
*/
|
164 |
private function filter_attributes( $attributes ) {
|
165 |
$out = array();
|
166 |
|
195 |
}
|
196 |
break;
|
197 |
|
198 |
+
default:
|
199 |
break;
|
200 |
}
|
201 |
}
|
207 |
return $out;
|
208 |
}
|
209 |
|
210 |
+
/**
|
211 |
+
* Builds a DOMElement to use as a placeholder for an <iframe>.
|
212 |
+
*
|
213 |
+
* @since 0.2
|
214 |
+
*
|
215 |
+
* @param string[] $parent_attributes {
|
216 |
+
* Attributes.
|
217 |
+
*
|
218 |
+
* @type string $placeholder AMP HTML <amp-iframe> `placeholder` attribute; default to 'amp-wp-iframe-placeholder'
|
219 |
+
* @type string $class AMP HTML <amp-iframe> `class` attribute; default to 'amp-wp-iframe-placeholder'
|
220 |
+
* }
|
221 |
+
* @return DOMElement|false
|
222 |
+
*/
|
223 |
private function build_placeholder( $parent_attributes ) {
|
224 |
$placeholder_node = AMP_DOM_Utils::create_node( $this->dom, 'div', array(
|
225 |
'placeholder' => '',
|
includes/sanitizers/class-amp-img-sanitizer.php
CHANGED
@@ -1,25 +1,101 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
4 |
-
|
|
|
|
|
5 |
|
6 |
/**
|
|
|
|
|
7 |
* Converts <img> tags to <amp-img> or <amp-anim>
|
8 |
*/
|
9 |
class AMP_Img_Sanitizer extends AMP_Base_Sanitizer {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
const FALLBACK_WIDTH = 600;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
const FALLBACK_HEIGHT = 400;
|
12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
public static $tag = 'img';
|
14 |
|
|
|
|
|
|
|
|
|
|
|
15 |
private static $anim_extension = '.gif';
|
16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
private static $script_slug = 'amp-anim';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
private static $script_src = 'https://cdn.ampproject.org/v0/amp-anim-0.1.js';
|
19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
public function sanitize() {
|
21 |
|
22 |
-
|
|
|
|
|
|
|
|
|
|
|
23 |
$need_dimensions = array();
|
24 |
|
25 |
$num_nodes = $nodes->length;
|
@@ -30,6 +106,9 @@ class AMP_Img_Sanitizer extends AMP_Base_Sanitizer {
|
|
30 |
|
31 |
for ( $i = $num_nodes - 1; $i >= 0; $i-- ) {
|
32 |
$node = $nodes->item( $i );
|
|
|
|
|
|
|
33 |
|
34 |
if ( ! $node->hasAttribute( 'src' ) || '' === $node->getAttribute( 'src' ) ) {
|
35 |
$node->parentNode->removeChild( $node );
|
@@ -49,36 +128,103 @@ class AMP_Img_Sanitizer extends AMP_Base_Sanitizer {
|
|
49 |
}
|
50 |
|
51 |
/**
|
52 |
-
*
|
53 |
-
* attempting to determine actual dimensions and setting reasonable defaults otherwise.
|
54 |
*
|
55 |
-
* @
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
*/
|
57 |
private function determine_dimensions( $need_dimensions ) {
|
|
|
58 |
$dimensions_by_url = AMP_Image_Dimension_Extractor::extract( array_keys( $need_dimensions ) );
|
59 |
|
60 |
foreach ( $dimensions_by_url as $url => $dimensions ) {
|
61 |
foreach ( $need_dimensions[ $url ] as $node ) {
|
|
|
|
|
|
|
|
|
62 |
// Provide default dimensions for images whose dimensions we couldn't fetch.
|
63 |
-
if ( false
|
64 |
-
$
|
|
|
|
|
|
|
65 |
$height = self::FALLBACK_HEIGHT;
|
66 |
$node->setAttribute( 'width', $width );
|
67 |
$node->setAttribute( 'height', $height );
|
68 |
$class = $node->hasAttribute( 'class' ) ? $node->getAttribute( 'class' ) . ' amp-wp-unknown-size' : 'amp-wp-unknown-size';
|
69 |
$node->setAttribute( 'class', $class );
|
70 |
-
} else {
|
71 |
-
$node->setAttribute( 'width', $dimensions['width'] );
|
72 |
-
$node->setAttribute( 'height', $dimensions['height'] );
|
73 |
}
|
74 |
}
|
75 |
}
|
76 |
}
|
77 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
/**
|
79 |
* Make final modifications to DOMNode
|
80 |
*
|
81 |
-
* @param DOMNode $node The DOMNode to adjust and replace
|
82 |
*/
|
83 |
private function adjust_and_replace_node( $node ) {
|
84 |
$old_attributes = AMP_DOM_Utils::get_node_attributes_as_assoc_array( $node );
|
@@ -86,6 +232,7 @@ class AMP_Img_Sanitizer extends AMP_Base_Sanitizer {
|
|
86 |
$new_attributes = $this->enforce_sizes_attribute( $new_attributes );
|
87 |
if ( $this->is_gif_url( $new_attributes['src'] ) ) {
|
88 |
$this->did_convert_elements = true;
|
|
|
89 |
$new_tag = 'amp-anim';
|
90 |
} else {
|
91 |
$new_tag = 'amp-img';
|
@@ -95,55 +242,16 @@ class AMP_Img_Sanitizer extends AMP_Base_Sanitizer {
|
|
95 |
}
|
96 |
|
97 |
/**
|
98 |
-
*
|
|
|
|
|
|
|
|
|
99 |
*
|
100 |
-
* @
|
101 |
*/
|
102 |
-
private function adjust_and_replace_nodes_in_array_map( $node_lists ) {
|
103 |
-
foreach ( $node_lists as $node_list ) {
|
104 |
-
foreach ( $node_list as $node ) {
|
105 |
-
$this->adjust_and_replace_node( $node );
|
106 |
-
}
|
107 |
-
}
|
108 |
-
}
|
109 |
-
|
110 |
-
public function get_scripts() {
|
111 |
-
if ( ! $this->did_convert_elements ) {
|
112 |
-
return array();
|
113 |
-
}
|
114 |
-
|
115 |
-
return array( self::$script_slug => self::$script_src );
|
116 |
-
}
|
117 |
-
|
118 |
-
private function filter_attributes( $attributes ) {
|
119 |
-
$out = array();
|
120 |
-
|
121 |
-
foreach ( $attributes as $name => $value ) {
|
122 |
-
switch ( $name ) {
|
123 |
-
case 'src':
|
124 |
-
case 'alt':
|
125 |
-
case 'class':
|
126 |
-
case 'srcset':
|
127 |
-
case 'sizes':
|
128 |
-
case 'on':
|
129 |
-
$out[ $name ] = $value;
|
130 |
-
break;
|
131 |
-
|
132 |
-
case 'width':
|
133 |
-
case 'height':
|
134 |
-
$out[ $name ] = $this->sanitize_dimension( $value, $name );
|
135 |
-
break;
|
136 |
-
|
137 |
-
default;
|
138 |
-
break;
|
139 |
-
}
|
140 |
-
}
|
141 |
-
|
142 |
-
return $out;
|
143 |
-
}
|
144 |
-
|
145 |
private function is_gif_url( $url ) {
|
146 |
-
$ext
|
147 |
$path = AMP_WP_Utils::parse_url( $url, PHP_URL_PATH );
|
148 |
return substr( $path, -strlen( $ext ) ) === $ext;
|
149 |
}
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Img_Sanitizer.
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
|
8 |
/**
|
9 |
+
* Class AMP_Img_Sanitizer
|
10 |
+
*
|
11 |
* Converts <img> tags to <amp-img> or <amp-anim>
|
12 |
*/
|
13 |
class AMP_Img_Sanitizer extends AMP_Base_Sanitizer {
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Value used for width attribute when $attributes['width'] is empty.
|
17 |
+
*
|
18 |
+
* @since 0.2
|
19 |
+
*
|
20 |
+
* @const int
|
21 |
+
*/
|
22 |
const FALLBACK_WIDTH = 600;
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Value used for height attribute when $attributes['height'] is empty.
|
26 |
+
*
|
27 |
+
* @since 0.2
|
28 |
+
*
|
29 |
+
* @const int
|
30 |
+
*/
|
31 |
const FALLBACK_HEIGHT = 400;
|
32 |
|
33 |
+
/**
|
34 |
+
* Tag.
|
35 |
+
*
|
36 |
+
* @var string HTML <img> tag to identify and replace with AMP version.
|
37 |
+
*
|
38 |
+
* @since 0.2
|
39 |
+
*/
|
40 |
public static $tag = 'img';
|
41 |
|
42 |
+
/**
|
43 |
+
* Animation extension.
|
44 |
+
*
|
45 |
+
* @var string
|
46 |
+
*/
|
47 |
private static $anim_extension = '.gif';
|
48 |
|
49 |
+
/**
|
50 |
+
* Script slug.
|
51 |
+
*
|
52 |
+
* @var string AMP HTML tag to use in place of HTML's <img> tag.
|
53 |
+
*
|
54 |
+
* @since 0.2
|
55 |
+
*/
|
56 |
private static $script_slug = 'amp-anim';
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Script src.
|
60 |
+
*
|
61 |
+
* @var string URL to AMP Project's Image element's JavaScript file found at cdn.ampproject.org
|
62 |
+
*
|
63 |
+
* @since 0.2
|
64 |
+
*/
|
65 |
private static $script_src = 'https://cdn.ampproject.org/v0/amp-anim-0.1.js';
|
66 |
|
67 |
+
/**
|
68 |
+
* Return one element array containing AMP HTML image tag and respective Javascript URL
|
69 |
+
*
|
70 |
+
* HTML tags and Javascript URLs found at cdn.ampproject.org
|
71 |
+
*
|
72 |
+
* @since 0.2
|
73 |
+
*
|
74 |
+
* @return string[] Returns AMP HTML image tag as array key and Javascript URL
|
75 |
+
* as array value, respectively. Will return an empty array
|
76 |
+
* if sanitization has yet to be run or if it did not find any
|
77 |
+
* HTML image elements to convert to AMP equivalents.
|
78 |
+
*/
|
79 |
+
public function get_scripts() {
|
80 |
+
if ( ! $this->did_convert_elements ) {
|
81 |
+
return array();
|
82 |
+
}
|
83 |
+
return array( self::$script_slug => self::$script_src );
|
84 |
+
}
|
85 |
+
|
86 |
+
/**
|
87 |
+
* Sanitize the <img> elements from the HTML contained in this instance's DOMDocument.
|
88 |
+
*
|
89 |
+
* @since 0.2
|
90 |
+
*/
|
91 |
public function sanitize() {
|
92 |
|
93 |
+
/**
|
94 |
+
* Node list.
|
95 |
+
*
|
96 |
+
* @var DOMNodeList $node
|
97 |
+
*/
|
98 |
+
$nodes = $this->dom->getElementsByTagName( self::$tag );
|
99 |
$need_dimensions = array();
|
100 |
|
101 |
$num_nodes = $nodes->length;
|
106 |
|
107 |
for ( $i = $num_nodes - 1; $i >= 0; $i-- ) {
|
108 |
$node = $nodes->item( $i );
|
109 |
+
if ( ! $node instanceof DOMElement ) {
|
110 |
+
continue;
|
111 |
+
}
|
112 |
|
113 |
if ( ! $node->hasAttribute( 'src' ) || '' === $node->getAttribute( 'src' ) ) {
|
114 |
$node->parentNode->removeChild( $node );
|
128 |
}
|
129 |
|
130 |
/**
|
131 |
+
* "Filter" HTML attributes for <amp-anim> elements.
|
|
|
132 |
*
|
133 |
+
* @since 0.2
|
134 |
+
*
|
135 |
+
* @param string[] $attributes {
|
136 |
+
* Attributes.
|
137 |
+
*
|
138 |
+
* @type string $src Image URL - Pass along if found
|
139 |
+
* @type string $alt <img> `alt` attribute - Pass along if found
|
140 |
+
* @type string $class <img> `class` attribute - Pass along if found
|
141 |
+
* @type string $srcset <img> `srcset` attribute - Pass along if found
|
142 |
+
* @type string $sizes <img> `sizes` attribute - Pass along if found
|
143 |
+
* @type string $on <img> `on` attribute - Pass along if found
|
144 |
+
* @type string $attribution <img> `attribution` attribute - Pass along if found
|
145 |
+
* @type int $width <img> width attribute - Set to numeric value if px or %
|
146 |
+
* @type int $height <img> width attribute - Set to numeric value if px or %
|
147 |
+
* }
|
148 |
+
* @return array Returns HTML attributes; removes any not specifically declared above from input.
|
149 |
+
*/
|
150 |
+
private function filter_attributes( $attributes ) {
|
151 |
+
$out = array();
|
152 |
+
|
153 |
+
foreach ( $attributes as $name => $value ) {
|
154 |
+
switch ( $name ) {
|
155 |
+
case 'src':
|
156 |
+
case 'alt':
|
157 |
+
case 'class':
|
158 |
+
case 'srcset':
|
159 |
+
case 'sizes':
|
160 |
+
case 'on':
|
161 |
+
case 'attribution':
|
162 |
+
$out[ $name ] = $value;
|
163 |
+
break;
|
164 |
+
|
165 |
+
case 'width':
|
166 |
+
case 'height':
|
167 |
+
$out[ $name ] = $this->sanitize_dimension( $value, $name );
|
168 |
+
break;
|
169 |
+
|
170 |
+
default:
|
171 |
+
break;
|
172 |
+
}
|
173 |
+
}
|
174 |
+
|
175 |
+
return $out;
|
176 |
+
}
|
177 |
+
|
178 |
+
/**
|
179 |
+
* Determine width and height attribute values for images without them.
|
180 |
+
*
|
181 |
+
* Attempt to determine actual dimensions, otherwise set reasonable defaults.
|
182 |
+
*
|
183 |
+
* @param DOMElement[][] $need_dimensions Map <img> @src URLs to node for images with missing dimensions.
|
184 |
*/
|
185 |
private function determine_dimensions( $need_dimensions ) {
|
186 |
+
|
187 |
$dimensions_by_url = AMP_Image_Dimension_Extractor::extract( array_keys( $need_dimensions ) );
|
188 |
|
189 |
foreach ( $dimensions_by_url as $url => $dimensions ) {
|
190 |
foreach ( $need_dimensions[ $url ] as $node ) {
|
191 |
+
if ( ! $node instanceof DOMElement ) {
|
192 |
+
continue;
|
193 |
+
}
|
194 |
+
|
195 |
// Provide default dimensions for images whose dimensions we couldn't fetch.
|
196 |
+
if ( false !== $dimensions ) {
|
197 |
+
$node->setAttribute( 'width', $dimensions['width'] );
|
198 |
+
$node->setAttribute( 'height', $dimensions['height'] );
|
199 |
+
} else {
|
200 |
+
$width = isset( $this->args['content_max_width'] ) ? $this->args['content_max_width'] : self::FALLBACK_WIDTH;
|
201 |
$height = self::FALLBACK_HEIGHT;
|
202 |
$node->setAttribute( 'width', $width );
|
203 |
$node->setAttribute( 'height', $height );
|
204 |
$class = $node->hasAttribute( 'class' ) ? $node->getAttribute( 'class' ) . ' amp-wp-unknown-size' : 'amp-wp-unknown-size';
|
205 |
$node->setAttribute( 'class', $class );
|
|
|
|
|
|
|
206 |
}
|
207 |
}
|
208 |
}
|
209 |
}
|
210 |
|
211 |
+
/**
|
212 |
+
* Now that all images have width and height attributes, make final tweaks and replace original image nodes
|
213 |
+
*
|
214 |
+
* @param DOMNodeList[] $node_lists Img DOM nodes (now with width and height attributes).
|
215 |
+
*/
|
216 |
+
private function adjust_and_replace_nodes_in_array_map( $node_lists ) {
|
217 |
+
foreach ( $node_lists as $node_list ) {
|
218 |
+
foreach ( $node_list as $node ) {
|
219 |
+
$this->adjust_and_replace_node( $node );
|
220 |
+
}
|
221 |
+
}
|
222 |
+
}
|
223 |
+
|
224 |
/**
|
225 |
* Make final modifications to DOMNode
|
226 |
*
|
227 |
+
* @param DOMNode $node The DOMNode to adjust and replace.
|
228 |
*/
|
229 |
private function adjust_and_replace_node( $node ) {
|
230 |
$old_attributes = AMP_DOM_Utils::get_node_attributes_as_assoc_array( $node );
|
232 |
$new_attributes = $this->enforce_sizes_attribute( $new_attributes );
|
233 |
if ( $this->is_gif_url( $new_attributes['src'] ) ) {
|
234 |
$this->did_convert_elements = true;
|
235 |
+
|
236 |
$new_tag = 'amp-anim';
|
237 |
} else {
|
238 |
$new_tag = 'amp-img';
|
242 |
}
|
243 |
|
244 |
/**
|
245 |
+
* Determines is a URL is considered a GIF URL
|
246 |
+
*
|
247 |
+
* @since 0.2
|
248 |
+
*
|
249 |
+
* @param string $url URL to inspect for GIF vs. JPEG or PNG.
|
250 |
*
|
251 |
+
* @return bool Returns true if $url ends in `.gif`
|
252 |
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
253 |
private function is_gif_url( $url ) {
|
254 |
+
$ext = self::$anim_extension;
|
255 |
$path = AMP_WP_Utils::parse_url( $url, PHP_URL_PATH );
|
256 |
return substr( $path, -strlen( $ext ) ) === $ext;
|
257 |
}
|
includes/sanitizers/class-amp-playbuzz-sanitizer.php
CHANGED
@@ -1,46 +1,100 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
|
|
|
|
|
|
4 |
|
5 |
/**
|
|
|
|
|
6 |
* Converts Playbuzz embed to <amp-playbuzz>
|
|
|
|
|
7 |
*/
|
8 |
class AMP_Playbuzz_Sanitizer extends AMP_Base_Sanitizer {
|
9 |
|
10 |
-
|
|
|
|
|
|
|
|
|
|
|
11 |
public static $tag = 'div';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
public static $pb_class = 'pb_feed';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
private static $script_slug = 'amp-playbuzz';
|
14 |
-
private static $height = '500';
|
15 |
-
private static $script_src = 'https://cdn.ampproject.org/v0/amp-playbuzz-0.1.js';
|
16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
public function get_scripts() {
|
20 |
if ( ! $this->did_convert_elements ) {
|
21 |
return array();
|
22 |
}
|
23 |
-
return array(
|
24 |
-
self::$script_slug => self::$script_src,
|
25 |
-
);
|
26 |
}
|
27 |
|
28 |
|
|
|
|
|
|
|
|
|
|
|
29 |
public function sanitize() {
|
30 |
|
31 |
-
$nodes
|
32 |
$num_nodes = $nodes->length;
|
33 |
|
34 |
if ( 0 === $num_nodes ) {
|
35 |
-
|
36 |
return;
|
37 |
-
|
38 |
}
|
39 |
|
40 |
for ( $i = $num_nodes - 1; $i >= 0; $i-- ) {
|
41 |
$node = $nodes->item( $i );
|
42 |
|
43 |
-
if ( self::$pb_class !== $node
|
44 |
continue;
|
45 |
}
|
46 |
|
@@ -62,7 +116,23 @@ class AMP_Playbuzz_Sanitizer extends AMP_Base_Sanitizer {
|
|
62 |
|
63 |
}
|
64 |
|
65 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
private function filter_attributes( $attributes ) {
|
67 |
$out = array();
|
68 |
|
@@ -72,28 +142,28 @@ class AMP_Playbuzz_Sanitizer extends AMP_Base_Sanitizer {
|
|
72 |
if ( ! empty( $value ) ) {
|
73 |
$out['data-item'] = $value;
|
74 |
}
|
75 |
-
|
76 |
|
77 |
case 'data-game':
|
78 |
if ( ! empty( $value ) ) {
|
79 |
$out['src'] = $value;
|
80 |
}
|
81 |
-
|
82 |
|
83 |
case 'data-game-info':
|
84 |
$out['data-item-info'] = $value;
|
85 |
-
|
86 |
|
87 |
case 'data-shares':
|
88 |
$out['data-share-buttons'] = $value;
|
89 |
-
|
90 |
|
91 |
case 'data-comments':
|
92 |
$out['data-comments'] = $value;
|
93 |
-
|
94 |
|
95 |
-
default
|
96 |
-
|
97 |
}
|
98 |
}
|
99 |
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Playbuzz_Sanitizer
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
|
8 |
/**
|
9 |
+
* Class AMP_Playbuzz_Sanitizer
|
10 |
+
*
|
11 |
* Converts Playbuzz embed to <amp-playbuzz>
|
12 |
+
*
|
13 |
+
* @see https://www.playbuzz.com/
|
14 |
*/
|
15 |
class AMP_Playbuzz_Sanitizer extends AMP_Base_Sanitizer {
|
16 |
|
17 |
+
/**
|
18 |
+
* Tag.
|
19 |
+
*
|
20 |
+
* @var string HTML tag to identify and replace with AMP version.
|
21 |
+
* @since 0.2
|
22 |
+
*/
|
23 |
public static $tag = 'div';
|
24 |
+
|
25 |
+
/**
|
26 |
+
* PlayBuzz class.
|
27 |
+
*
|
28 |
+
* @var string CSS class to identify Playbuzz <div> to replace with AMP version.
|
29 |
+
*
|
30 |
+
* @since 0.2
|
31 |
+
*/
|
32 |
public static $pb_class = 'pb_feed';
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Script slug.
|
36 |
+
*
|
37 |
+
* @var string AMP HTML audio tag to use in place of HTML's 'audio' tag.
|
38 |
+
*
|
39 |
+
* @since 0.2
|
40 |
+
*/
|
41 |
private static $script_slug = 'amp-playbuzz';
|
|
|
|
|
42 |
|
43 |
+
/**
|
44 |
+
* Script src.
|
45 |
+
*
|
46 |
+
* @var string URL to AMP Project's Playbuzz element javascript file found at cdn.ampproject.org
|
47 |
+
*
|
48 |
+
* @since 0.2
|
49 |
+
*/
|
50 |
+
private static $script_src = 'https://cdn.ampproject.org/v0/amp-playbuzz-0.1.js';
|
51 |
|
52 |
+
/**
|
53 |
+
* Hardcoded height to set for Playbuzz elements.
|
54 |
+
*
|
55 |
+
* @var string
|
56 |
+
*
|
57 |
+
* @since 0.2
|
58 |
+
*/
|
59 |
+
private static $height = '500';
|
60 |
|
61 |
+
/**
|
62 |
+
* Return one element array containing AMP HTML audio tag and respective Javascript URL
|
63 |
+
*
|
64 |
+
* HTML tags and Javascript URLs found at cdn.ampproject.org
|
65 |
+
*
|
66 |
+
* @since 0.2
|
67 |
+
*
|
68 |
+
* @return string[] Returns AMP Playbuzz tag as array key and Javascript URL as array value,
|
69 |
+
* respectively. Will return an empty array if sanitization has yet to be run
|
70 |
+
* or if it did not find any HTML Playbuzz elements to convert to AMP equivalents.
|
71 |
+
*/
|
72 |
public function get_scripts() {
|
73 |
if ( ! $this->did_convert_elements ) {
|
74 |
return array();
|
75 |
}
|
76 |
+
return array( self::$script_slug => self::$script_src );
|
|
|
|
|
77 |
}
|
78 |
|
79 |
|
80 |
+
/**
|
81 |
+
* Sanitize the Playbuzz elements from the HTML contained in this instance's DOMDocument.
|
82 |
+
*
|
83 |
+
* @since 0.2
|
84 |
+
*/
|
85 |
public function sanitize() {
|
86 |
|
87 |
+
$nodes = $this->dom->getElementsByTagName( self::$tag );
|
88 |
$num_nodes = $nodes->length;
|
89 |
|
90 |
if ( 0 === $num_nodes ) {
|
|
|
91 |
return;
|
|
|
92 |
}
|
93 |
|
94 |
for ( $i = $num_nodes - 1; $i >= 0; $i-- ) {
|
95 |
$node = $nodes->item( $i );
|
96 |
|
97 |
+
if ( self::$pb_class !== $node->getAttribute( 'class' ) ) {
|
98 |
continue;
|
99 |
}
|
100 |
|
116 |
|
117 |
}
|
118 |
|
119 |
+
/**
|
120 |
+
* "Filter" HTML attributes for <amp-audio> elements.
|
121 |
+
*
|
122 |
+
* @since 0.2
|
123 |
+
*
|
124 |
+
* @param string[] $attributes {
|
125 |
+
* Attributes.
|
126 |
+
*
|
127 |
+
* @type string $data-item Playbuzz <div> attribute - Pass along if found and not empty.
|
128 |
+
* @type string $data-game Playbuzz <div> attribute - Assign to its value to $attributes['src'] if found and not empty.
|
129 |
+
* @type string $data-game-info Playbuzz <div> attribute - Assign to its value to $attributes['data-item-info'] if found.
|
130 |
+
* @type string $data-shares Playbuzz <div> attribute - Assign to its value to $attributes['data-share-buttons'] if found.
|
131 |
+
* @type string $data-comments Playbuzz <div> attribute - Pass along if found.
|
132 |
+
* @type int $height Playbuzz <div> attribute - Set to hardcoded value of 500.
|
133 |
+
* }
|
134 |
+
* @return array Returns HTML attributes; removes any not specifically declared above from input.
|
135 |
+
*/
|
136 |
private function filter_attributes( $attributes ) {
|
137 |
$out = array();
|
138 |
|
142 |
if ( ! empty( $value ) ) {
|
143 |
$out['data-item'] = $value;
|
144 |
}
|
145 |
+
break;
|
146 |
|
147 |
case 'data-game':
|
148 |
if ( ! empty( $value ) ) {
|
149 |
$out['src'] = $value;
|
150 |
}
|
151 |
+
break;
|
152 |
|
153 |
case 'data-game-info':
|
154 |
$out['data-item-info'] = $value;
|
155 |
+
break;
|
156 |
|
157 |
case 'data-shares':
|
158 |
$out['data-share-buttons'] = $value;
|
159 |
+
break;
|
160 |
|
161 |
case 'data-comments':
|
162 |
$out['data-comments'] = $value;
|
163 |
+
break;
|
164 |
|
165 |
+
default:
|
166 |
+
break;
|
167 |
}
|
168 |
}
|
169 |
|
includes/sanitizers/class-amp-rule-spec.php
ADDED
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Rule_Spec
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class AMP_Rule_Spec
|
10 |
+
*
|
11 |
+
* Set of constants used throughout the sanitizer.
|
12 |
+
*/
|
13 |
+
abstract class AMP_Rule_Spec {
|
14 |
+
|
15 |
+
/**
|
16 |
+
* AMP rule_spec types
|
17 |
+
*/
|
18 |
+
const ATTR_SPEC_LIST = 'attr_spec_list';
|
19 |
+
const TAG_SPEC = 'tag_spec';
|
20 |
+
|
21 |
+
/**
|
22 |
+
* AMP attr_spec value check results
|
23 |
+
*/
|
24 |
+
const PASS = 'pass';
|
25 |
+
const FAIL = 'fail';
|
26 |
+
const NOT_APPLICABLE = 'not_applicable';
|
27 |
+
|
28 |
+
/**
|
29 |
+
* HTML Element Tag rule names
|
30 |
+
*/
|
31 |
+
const DISALLOWED_ANCESTOR = 'disallowed_ancestor';
|
32 |
+
const MANDATORY_ANCESTOR = 'mandatory_ancestor';
|
33 |
+
const MANDATORY_PARENT = 'mandatory_parent';
|
34 |
+
|
35 |
+
/**
|
36 |
+
* HTML Element Attribute rule names
|
37 |
+
*/
|
38 |
+
const ALLOW_EMPTY = 'allow_empty';
|
39 |
+
const ALLOW_RELATIVE = 'allow_relative';
|
40 |
+
const ALLOWED_PROTOCOL = 'allowed_protocol';
|
41 |
+
const ALTERNATIVE_NAMES = 'alternative_names';
|
42 |
+
const BLACKLISTED_VALUE_REGEX = 'blacklisted_value_regex';
|
43 |
+
const DISALLOWED_DOMAIN = 'disallowed_domain';
|
44 |
+
const MANDATORY = 'mandatory';
|
45 |
+
const VALUE = 'value';
|
46 |
+
const VALUE_CASEI = 'value_casei';
|
47 |
+
const VALUE_REGEX = 'value_regex';
|
48 |
+
const VALUE_REGEX_CASEI = 'value_regex_casei';
|
49 |
+
|
50 |
+
/**
|
51 |
+
* If a node type listed here is invalid, it and it's subtree will be
|
52 |
+
* removed if it is invalid. This is mainly because any children will be
|
53 |
+
* non-functional without this parent.
|
54 |
+
*
|
55 |
+
* If a tag is not listed here, it will be replaced by its children if it
|
56 |
+
* is invalid.
|
57 |
+
*
|
58 |
+
* @todo There are other nodes that should probably be listed here as well.
|
59 |
+
*
|
60 |
+
* @var array
|
61 |
+
*/
|
62 |
+
public static $node_types_to_remove_if_invalid = array(
|
63 |
+
'form',
|
64 |
+
'input',
|
65 |
+
'link',
|
66 |
+
'meta',
|
67 |
+
'style',
|
68 |
+
// Include 'script' here?
|
69 |
+
);
|
70 |
+
|
71 |
+
/**
|
72 |
+
* It is mentioned in the documentation in several places that data-*
|
73 |
+
* is generally allowed, but there is no specific rule for it in the
|
74 |
+
* protoascii file, so we include it here.
|
75 |
+
*
|
76 |
+
* @var array
|
77 |
+
*/
|
78 |
+
public static $whitelisted_attr_regex = array(
|
79 |
+
'@^data-[a-zA-Z][\\w:.-]*$@uis',
|
80 |
+
'(update|item|pagination)', // Allowed for live reference points.
|
81 |
+
);
|
82 |
+
|
83 |
+
/**
|
84 |
+
* Additional allowed tags.
|
85 |
+
*
|
86 |
+
* @var array
|
87 |
+
*/
|
88 |
+
public static $additional_allowed_tags = array(
|
89 |
+
|
90 |
+
// An experimental tag with no protoascii.
|
91 |
+
'amp-share-tracking' => array(
|
92 |
+
'attr_spec_list' => array(),
|
93 |
+
'tag_spec' => array(),
|
94 |
+
),
|
95 |
+
|
96 |
+
// Needed for some tags such as analytics.
|
97 |
+
'script' => array(
|
98 |
+
'attr_spec_list' => array(
|
99 |
+
'type' => array(
|
100 |
+
'mandatory' => true,
|
101 |
+
'value_casei' => 'application/json',
|
102 |
+
),
|
103 |
+
),
|
104 |
+
'tag_spec' => array(),
|
105 |
+
),
|
106 |
+
);
|
107 |
+
}
|
includes/sanitizers/class-amp-style-sanitizer.php
CHANGED
@@ -1,22 +1,64 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
|
|
|
|
|
|
4 |
|
5 |
/**
|
|
|
|
|
6 |
* Collects inline styles and outputs them in the amp-custom stylesheet.
|
7 |
*/
|
8 |
class AMP_Style_Sanitizer extends AMP_Base_Sanitizer {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
private $styles = array();
|
10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
public function get_styles() {
|
|
|
|
|
|
|
12 |
return $this->styles;
|
13 |
}
|
14 |
|
|
|
|
|
|
|
|
|
|
|
15 |
public function sanitize() {
|
16 |
$body = $this->get_body_node();
|
17 |
$this->collect_styles_recursive( $body );
|
|
|
18 |
}
|
19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
private function collect_styles_recursive( $node ) {
|
21 |
if ( XML_ELEMENT_NODE !== $node->nodeType ) {
|
22 |
return;
|
@@ -35,7 +77,6 @@ class AMP_Style_Sanitizer extends AMP_Base_Sanitizer {
|
|
35 |
$node->setAttribute( 'class', $new_class );
|
36 |
$this->styles[ '.' . $class_name ] = $style;
|
37 |
}
|
38 |
-
|
39 |
$node->removeAttribute( 'style' );
|
40 |
}
|
41 |
}
|
@@ -43,29 +84,42 @@ class AMP_Style_Sanitizer extends AMP_Base_Sanitizer {
|
|
43 |
$length = $node->childNodes->length;
|
44 |
for ( $i = $length - 1; $i >= 0; $i -- ) {
|
45 |
$child_node = $node->childNodes->item( $i );
|
46 |
-
|
47 |
$this->collect_styles_recursive( $child_node );
|
48 |
}
|
49 |
}
|
50 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
private function process_style( $string ) {
|
52 |
-
|
|
|
|
|
|
|
53 |
$string = safecss_filter_attr( esc_html( $string ) );
|
54 |
|
55 |
if ( ! $string ) {
|
56 |
return array();
|
57 |
}
|
58 |
|
59 |
-
|
60 |
-
|
61 |
-
|
|
|
|
|
|
|
62 |
|
63 |
-
// Normalize the order of the styles
|
64 |
sort( $styles );
|
65 |
|
66 |
$processed_styles = array();
|
67 |
|
68 |
-
// Normalize whitespace and filter rules
|
69 |
foreach ( $styles as $index => $rule ) {
|
70 |
$arr2 = array_map( 'trim', explode( ':', $rule, 2 ) );
|
71 |
if ( 2 !== count( $arr2 ) ) {
|
@@ -77,26 +131,43 @@ class AMP_Style_Sanitizer extends AMP_Base_Sanitizer {
|
|
77 |
continue;
|
78 |
}
|
79 |
|
80 |
-
$processed_styles[ $index ] = $property
|
81 |
}
|
82 |
|
83 |
return $processed_styles;
|
84 |
}
|
85 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
86 |
private function filter_style( $property, $value ) {
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
|
|
|
|
93 |
}
|
94 |
|
95 |
if ( 'width' === $property ) {
|
96 |
$property = 'max-width';
|
97 |
}
|
98 |
|
99 |
-
|
|
|
|
|
100 |
if ( false !== strpos( $value, 'important' ) ) {
|
101 |
$value = preg_replace( '/\s*\!\s*important$/', '', $value );
|
102 |
}
|
@@ -104,6 +175,16 @@ class AMP_Style_Sanitizer extends AMP_Base_Sanitizer {
|
|
104 |
return array( $property, $value );
|
105 |
}
|
106 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
private function generate_class_name( $data ) {
|
108 |
$string = maybe_serialize( $data );
|
109 |
return 'amp-wp-inline-' . md5( $string );
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Style_Sanitizer
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
|
8 |
/**
|
9 |
+
* Class AMP_Style_Sanitizer
|
10 |
+
*
|
11 |
* Collects inline styles and outputs them in the amp-custom stylesheet.
|
12 |
*/
|
13 |
class AMP_Style_Sanitizer extends AMP_Base_Sanitizer {
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Styles.
|
17 |
+
*
|
18 |
+
* @var string[] List of CSS styles in HTML content of DOMDocument ($this->dom).
|
19 |
+
*
|
20 |
+
* @since 0.4
|
21 |
+
*/
|
22 |
private $styles = array();
|
23 |
|
24 |
+
/**
|
25 |
+
* Get list of CSS styles in HTML content of DOMDocument ($this->dom).
|
26 |
+
*
|
27 |
+
* @since 0.4
|
28 |
+
*
|
29 |
+
* @return string[]
|
30 |
+
*/
|
31 |
public function get_styles() {
|
32 |
+
if ( ! $this->did_convert_elements ) {
|
33 |
+
return array();
|
34 |
+
}
|
35 |
return $this->styles;
|
36 |
}
|
37 |
|
38 |
+
/**
|
39 |
+
* Sanitize CSS styles within the HTML contained in this instance's DOMDocument.
|
40 |
+
*
|
41 |
+
* @since 0.4
|
42 |
+
*/
|
43 |
public function sanitize() {
|
44 |
$body = $this->get_body_node();
|
45 |
$this->collect_styles_recursive( $body );
|
46 |
+
$this->did_convert_elements = true;
|
47 |
}
|
48 |
|
49 |
+
/**
|
50 |
+
* Collect and store all CSS styles.
|
51 |
+
*
|
52 |
+
* Collects the CSS styles from within the HTML contained in this instance's DOMDocument.
|
53 |
+
*
|
54 |
+
* @see Retrieve array of styles using $this->get_styles() after calling this method.
|
55 |
+
*
|
56 |
+
* @since 0.4
|
57 |
+
*
|
58 |
+
* @note Uses recursion to traverse down the tree of DOMDocument nodes.
|
59 |
+
*
|
60 |
+
* @param DOMNode $node Node.
|
61 |
+
*/
|
62 |
private function collect_styles_recursive( $node ) {
|
63 |
if ( XML_ELEMENT_NODE !== $node->nodeType ) {
|
64 |
return;
|
77 |
$node->setAttribute( 'class', $new_class );
|
78 |
$this->styles[ '.' . $class_name ] = $style;
|
79 |
}
|
|
|
80 |
$node->removeAttribute( 'style' );
|
81 |
}
|
82 |
}
|
84 |
$length = $node->childNodes->length;
|
85 |
for ( $i = $length - 1; $i >= 0; $i -- ) {
|
86 |
$child_node = $node->childNodes->item( $i );
|
|
|
87 |
$this->collect_styles_recursive( $child_node );
|
88 |
}
|
89 |
}
|
90 |
|
91 |
+
/**
|
92 |
+
* Sanitize and convert individual styles.
|
93 |
+
*
|
94 |
+
* @since 0.4
|
95 |
+
*
|
96 |
+
* @param string $string Style string.
|
97 |
+
* @return array
|
98 |
+
*/
|
99 |
private function process_style( $string ) {
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Filter properties
|
103 |
+
*/
|
104 |
$string = safecss_filter_attr( esc_html( $string ) );
|
105 |
|
106 |
if ( ! $string ) {
|
107 |
return array();
|
108 |
}
|
109 |
|
110 |
+
/*
|
111 |
+
* safecss returns a string but we want individual rules.
|
112 |
+
* Use preg_split to break up rules by `;` but only if the
|
113 |
+
* semi-colon is not inside parens (like a data-encoded image).
|
114 |
+
*/
|
115 |
+
$styles = array_map( 'trim', preg_split( '/;(?![^(]*\))/', $string ) );
|
116 |
|
117 |
+
// Normalize the order of the styles.
|
118 |
sort( $styles );
|
119 |
|
120 |
$processed_styles = array();
|
121 |
|
122 |
+
// Normalize whitespace and filter rules.
|
123 |
foreach ( $styles as $index => $rule ) {
|
124 |
$arr2 = array_map( 'trim', explode( ':', $rule, 2 ) );
|
125 |
if ( 2 !== count( $arr2 ) ) {
|
131 |
continue;
|
132 |
}
|
133 |
|
134 |
+
$processed_styles[ $index ] = "{$property}:{$value}";
|
135 |
}
|
136 |
|
137 |
return $processed_styles;
|
138 |
}
|
139 |
|
140 |
+
/**
|
141 |
+
* Filter individual CSS name/value pairs.
|
142 |
+
*
|
143 |
+
* - Remove overflow if value is `auto` or `scroll`
|
144 |
+
* - Change `width` to `max-width`
|
145 |
+
* - Remove !important
|
146 |
+
*
|
147 |
+
* @since 0.4
|
148 |
+
*
|
149 |
+
* @param string $property Property.
|
150 |
+
* @param string $value Value.
|
151 |
+
* @return array
|
152 |
+
*/
|
153 |
private function filter_style( $property, $value ) {
|
154 |
+
|
155 |
+
/**
|
156 |
+
* Remove overflow if value is `auto` or `scroll`; not allowed in AMP
|
157 |
+
*
|
158 |
+
* @see https://www.ampproject.org/docs/reference/spec.html#properties
|
159 |
+
*/
|
160 |
+
if ( preg_match( '#^overflow#i', $property ) && preg_match( '#^(auto|scroll)$#i', $value ) ) {
|
161 |
+
return array( false, false );
|
162 |
}
|
163 |
|
164 |
if ( 'width' === $property ) {
|
165 |
$property = 'max-width';
|
166 |
}
|
167 |
|
168 |
+
/**
|
169 |
+
* Remove `!important`; not allowed in AMP
|
170 |
+
*/
|
171 |
if ( false !== strpos( $value, 'important' ) ) {
|
172 |
$value = preg_replace( '/\s*\!\s*important$/', '', $value );
|
173 |
}
|
175 |
return array( $property, $value );
|
176 |
}
|
177 |
|
178 |
+
/**
|
179 |
+
* Generate a unique class name
|
180 |
+
*
|
181 |
+
* Use the md5() of the $data parameter
|
182 |
+
*
|
183 |
+
* @since 0.4
|
184 |
+
*
|
185 |
+
* @param string $data Data.
|
186 |
+
* @return string Class name.
|
187 |
+
*/
|
188 |
private function generate_class_name( $data ) {
|
189 |
$string = maybe_serialize( $data );
|
190 |
return 'amp-wp-inline-' . md5( $string );
|
includes/sanitizers/class-amp-tag-and-attribute-sanitizer.php
CHANGED
@@ -1,33 +1,84 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
4 |
-
|
|
|
|
|
5 |
|
6 |
/**
|
7 |
-
* Strips tags and attributes not allowed by the AMP
|
8 |
*
|
9 |
* Allowed tags array is generated from this protocol buffer:
|
|
|
10 |
* https://github.com/ampproject/amphtml/blob/master/validator/validator-main.protoascii
|
11 |
* by the python script in amp-wp/bin/amp_wp_build.py. See the comment at the top
|
12 |
* of that file for instructions to generate class-amp-allowed-tags-generated.php.
|
13 |
*
|
14 |
-
*
|
15 |
-
*
|
16 |
-
*
|
17 |
-
*
|
18 |
-
*
|
19 |
-
*
|
20 |
-
*
|
21 |
-
*
|
|
|
22 |
*/
|
23 |
class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
protected $allowed_tags;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
protected $globally_allowed_attributes;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
protected $layout_allowed_attributes;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
private $stack = array();
|
28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
protected $DEFAULT_ARGS = array();
|
30 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
public function __construct( $dom, $args = array() ) {
|
32 |
$this->DEFAULT_ARGS = array(
|
33 |
'amp_allowed_tags' => AMP_Allowed_Tags_Generated::get_allowed_tags(),
|
@@ -37,66 +88,94 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
37 |
|
38 |
parent::__construct( $dom, $args );
|
39 |
|
40 |
-
|
41 |
-
|
|
|
|
|
42 |
$this->globally_allowed_attributes = $this->args['amp_globally_allowed_attributes'];
|
43 |
-
$this->layout_allowed_attributes
|
44 |
}
|
45 |
|
|
|
|
|
|
|
|
|
|
|
46 |
public function sanitize() {
|
47 |
-
|
|
|
48 |
$this->allowed_tags[ $tag_name ][] = $tag_rule_spec;
|
49 |
}
|
50 |
|
51 |
-
|
|
|
|
|
|
|
|
|
52 |
$body = $this->get_body_node();
|
|
|
53 |
$this->stack[] = $body;
|
54 |
|
55 |
-
|
56 |
-
|
|
|
|
|
57 |
|
58 |
// Get the next node to process.
|
59 |
$node = array_pop( $this->stack );
|
60 |
|
61 |
-
|
|
|
|
|
62 |
$this->process_node( $node );
|
63 |
|
64 |
-
|
65 |
-
|
|
|
|
|
66 |
if ( $node->parentNode ) {
|
67 |
$child = $node->firstChild;
|
68 |
while ( $child ) {
|
69 |
$this->stack[] = $child;
|
70 |
-
$child
|
71 |
}
|
72 |
}
|
73 |
}
|
74 |
}
|
75 |
|
|
|
|
|
|
|
|
|
|
|
76 |
private function process_node( $node ) {
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
( XML_CDATA_SECTION_NODE == $node->nodeType ) ) {
|
81 |
return;
|
82 |
}
|
83 |
|
84 |
-
// Remove nodes with
|
85 |
if ( ! $this->is_amp_allowed_tag( $node ) ) {
|
86 |
-
|
|
|
87 |
$this->replace_node_with_children( $node );
|
|
|
88 |
// Return early since this node no longer exists.
|
89 |
return;
|
90 |
}
|
91 |
|
92 |
-
|
93 |
-
|
|
|
|
|
94 |
$rule_spec_list_to_validate = array();
|
|
|
95 |
if ( isset( $this->allowed_tags[ $node->nodeName ] ) ) {
|
96 |
$rule_spec_list = $this->allowed_tags[ $node->nodeName ];
|
97 |
}
|
98 |
foreach ( $rule_spec_list as $id => $rule_spec ) {
|
99 |
-
if ( $this->validate_tag_spec_for_node( $node, $rule_spec[AMP_Rule_Spec::TAG_SPEC] ) ) {
|
100 |
$rule_spec_list_to_validate[ $id ] = $rule_spec;
|
101 |
}
|
102 |
}
|
@@ -110,52 +189,56 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
110 |
// The remaining validations all have to do with attributes.
|
111 |
$attr_spec_list = array();
|
112 |
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
// try to deduce which one is intended by inspecting the node's
|
121 |
-
// attributes.
|
122 |
|
123 |
-
|
124 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
125 |
$attr_spec_scores = array();
|
126 |
foreach ( $rule_spec_list_to_validate as $spec_id => $rule_spec ) {
|
127 |
-
$attr_spec_scores[ $spec_id ] = $this->validate_attr_spec_list_for_node( $node, $rule_spec[AMP_Rule_Spec::ATTR_SPEC_LIST] );
|
128 |
}
|
129 |
|
130 |
// Get the key(s) to the highest score(s).
|
131 |
-
$spec_ids_sorted = array_keys( $attr_spec_scores, max( $attr_spec_scores ) );
|
132 |
|
133 |
// If there is exactly one attr_spec with a max score, use that one.
|
134 |
-
if ( 1
|
135 |
-
$attr_spec_list = $rule_spec_list_to_validate[ $spec_ids_sorted[0] ][AMP_Rule_Spec::ATTR_SPEC_LIST];
|
136 |
-
// Otherwise...
|
137 |
} else {
|
138 |
// This should not happen very often, but...
|
139 |
// If we're here, then we're not sure which spec should
|
140 |
// be used. Let's use the top scoring ones.
|
141 |
-
foreach( $spec_ids_sorted as $id ) {
|
142 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
143 |
}
|
144 |
}
|
145 |
-
}
|
146 |
-
|
147 |
-
// If an attribute is mandatory and we don't have it, just remove the node and move on.
|
148 |
-
foreach ( $attr_spec_list as $attr_name => $attr_spec_rule_value ) {
|
149 |
-
$is_mandatory =
|
150 |
-
isset( $attr_spec_rule_value[ AMP_Rule_Spec::MANDATORY ] )
|
151 |
-
? (bool) $attr_spec_rule_value[ AMP_Rule_Spec::MANDATORY ]
|
152 |
-
: false;
|
153 |
-
$attribute_exists = $node->hasAttribute( $attr_name );
|
154 |
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
}
|
159 |
}
|
160 |
|
161 |
// Remove any remaining disallowed attributes.
|
@@ -166,30 +249,54 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
166 |
}
|
167 |
|
168 |
/**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
169 |
* Checks to see if a node's placement with the DOM is be valid for the
|
170 |
* given tag_spec. If there are restrictions placed on the type of node
|
171 |
* that can be an immediate parent or an ancestor of this node, then make
|
172 |
* sure those restrictions are met.
|
173 |
*
|
174 |
-
*
|
175 |
-
*
|
|
|
|
|
|
|
176 |
*/
|
177 |
private function validate_tag_spec_for_node( $node, $tag_spec ) {
|
178 |
-
if ( ! empty( $tag_spec[AMP_Rule_Spec::MANDATORY_PARENT] ) &&
|
179 |
-
! $this->has_parent( $node, $tag_spec[AMP_Rule_Spec::MANDATORY_PARENT] ) ) {
|
180 |
return false;
|
181 |
}
|
182 |
|
183 |
-
if ( ! empty( $tag_spec[AMP_Rule_Spec::DISALLOWED_ANCESTOR] ) ) {
|
184 |
-
foreach ( $tag_spec[AMP_Rule_Spec::DISALLOWED_ANCESTOR] as $disallowed_ancestor_node_name ) {
|
185 |
if ( $this->has_ancestor( $node, $disallowed_ancestor_node_name ) ) {
|
186 |
return false;
|
187 |
}
|
188 |
}
|
189 |
}
|
190 |
|
191 |
-
if ( ! empty( $tag_spec[AMP_Rule_Spec::MANDATORY_ANCESTOR] ) &&
|
192 |
-
! $this->has_ancestor( $node, $tag_spec[AMP_Rule_Spec::MANDATORY_ANCESTOR] ) ) {
|
193 |
return false;
|
194 |
}
|
195 |
|
@@ -197,144 +304,196 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
197 |
}
|
198 |
|
199 |
/**
|
200 |
-
* Checks to see if a spec is potentially valid
|
201 |
-
*
|
|
|
202 |
*
|
203 |
-
*
|
|
|
|
|
|
|
|
|
|
|
204 |
*/
|
205 |
private function validate_attr_spec_list_for_node( $node, $attr_spec_list ) {
|
206 |
-
|
207 |
-
|
|
|
|
|
208 |
if ( ! $node->hasAttributes() ) {
|
209 |
return 0;
|
210 |
}
|
211 |
|
212 |
-
foreach( $node->attributes as $attr_name => $attr_node ) {
|
213 |
-
if ( isset( $attr_spec_list[ $attr_name ][AMP_Rule_Spec::ALTERNATIVE_NAMES] ) ) {
|
214 |
-
|
215 |
-
$attr_spec_list[ $attr_alt_name ] = $attr_spec_list[ $attr_name ];
|
216 |
-
}
|
217 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
218 |
}
|
219 |
|
220 |
$score = 0;
|
221 |
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
|
|
|
|
226 |
foreach ( $attr_spec_list as $attr_name => $attr_spec_rule ) {
|
227 |
|
228 |
-
|
229 |
-
if ( isset( $attr_spec_rule[AMP_Rule_Spec::MANDATORY] ) ) {
|
230 |
-
if ( AMP_Rule_Spec::PASS
|
231 |
-
$score
|
232 |
}
|
233 |
}
|
234 |
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
|
|
|
|
240 |
}
|
241 |
}
|
242 |
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
|
|
|
|
249 |
}
|
250 |
}
|
251 |
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
|
|
|
|
258 |
}
|
259 |
}
|
260 |
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
|
|
|
|
267 |
}
|
268 |
}
|
269 |
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
|
|
|
|
275 |
}
|
276 |
}
|
277 |
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
|
|
|
|
283 |
}
|
284 |
}
|
285 |
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
|
|
|
|
291 |
}
|
292 |
}
|
293 |
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
|
|
|
|
299 |
}
|
300 |
}
|
301 |
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
|
|
|
|
307 |
}
|
308 |
}
|
309 |
}
|
310 |
|
311 |
-
// return true;
|
312 |
return $score;
|
313 |
}
|
314 |
|
315 |
/**
|
316 |
-
*
|
317 |
-
*
|
|
|
|
|
318 |
*/
|
319 |
private function sanitize_disallowed_attributes_in_node( $node, $attr_spec_list ) {
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
324 |
$attrs_to_remove = array();
|
325 |
foreach ( $node->attributes as $attr_name => $attr_node ) {
|
326 |
-
// see if this attribute is allowed for this node
|
327 |
if ( ! $this->is_amp_allowed_attribute( $attr_name, $attr_spec_list ) ) {
|
|
|
|
|
|
|
328 |
$attrs_to_remove[] = $attr_name;
|
329 |
}
|
330 |
}
|
331 |
|
332 |
if ( ! empty( $attrs_to_remove ) ) {
|
333 |
-
|
334 |
-
|
|
|
|
|
335 |
foreach ( $attr_spec_list as $attr_name => $attr_spec_rule_value ) {
|
336 |
-
if ( isset( $attr_spec_rule_value[AMP_Rule_Spec::ALTERNATIVE_NAMES] ) ) {
|
337 |
-
foreach ( $attr_spec_rule_value[AMP_Rule_Spec::ALTERNATIVE_NAMES] as $alternative_name ) {
|
338 |
$alt_name_keys = array_keys( $attrs_to_remove, $alternative_name, true );
|
339 |
if ( ! empty( $alt_name_keys ) ) {
|
340 |
unset( $attrs_to_remove[ $alt_name_keys[0] ] );
|
@@ -343,7 +502,7 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
343 |
}
|
344 |
}
|
345 |
|
346 |
-
// Remove the
|
347 |
foreach ( $attrs_to_remove as $attr_name ) {
|
348 |
$node->removeAttribute( $attr_name );
|
349 |
}
|
@@ -351,71 +510,91 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
351 |
}
|
352 |
|
353 |
/**
|
354 |
-
*
|
355 |
-
*
|
|
|
|
|
|
|
|
|
356 |
*/
|
357 |
private function sanitize_disallowed_attribute_values_in_node( $node, $attr_spec_list ) {
|
358 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
359 |
if ( ! empty( $attr_spec_list ) ) {
|
360 |
-
$this->
|
361 |
}
|
362 |
}
|
363 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
364 |
$attrs_to_remove = array();
|
365 |
|
366 |
-
foreach( $attr_spec_list as $attr_name => $attr_val ) {
|
367 |
-
if ( isset( $attr_spec_list[ $attr_name ][AMP_Rule_Spec::ALTERNATIVE_NAMES] ) ) {
|
368 |
-
foreach( $attr_spec_list[ $attr_name ][AMP_Rule_Spec::ALTERNATIVE_NAMES] as $attr_alt_name ) {
|
369 |
$attr_spec_list[ $attr_alt_name ] = $attr_spec_list[ $attr_name ];
|
370 |
}
|
371 |
}
|
372 |
}
|
373 |
|
374 |
-
$
|
375 |
-
|
376 |
-
foreach( $node->attributes as $attr_name => $attr_node ) {
|
377 |
|
378 |
-
if ( ! isset( $attr_spec_list[$attr_name] ) ) {
|
379 |
continue;
|
380 |
}
|
381 |
|
382 |
$should_remove_node = false;
|
383 |
-
$attr_spec_rule
|
384 |
|
385 |
-
if ( isset( $attr_spec_rule[AMP_Rule_Spec::VALUE] ) &&
|
386 |
-
AMP_Rule_Spec::FAIL
|
387 |
$should_remove_node = true;
|
388 |
-
} elseif ( isset( $attr_spec_rule[AMP_Rule_Spec::VALUE_CASEI] ) &&
|
389 |
-
AMP_Rule_Spec::FAIL
|
390 |
$should_remove_node = true;
|
391 |
-
} elseif ( isset( $attr_spec_rule[AMP_Rule_Spec::VALUE_REGEX] ) &&
|
392 |
-
|
393 |
$should_remove_node = true;
|
394 |
-
} elseif ( isset( $attr_spec_rule[AMP_Rule_Spec::VALUE_REGEX_CASEI] ) &&
|
395 |
-
AMP_Rule_Spec::FAIL
|
396 |
$should_remove_node = true;
|
397 |
-
} elseif ( isset( $attr_spec_rule[AMP_Rule_Spec::ALLOWED_PROTOCOL] ) &&
|
398 |
-
AMP_Rule_Spec::FAIL
|
399 |
$should_remove_node = true;
|
400 |
-
} elseif ( isset( $attr_spec_rule[AMP_Rule_Spec::ALLOW_RELATIVE] ) &&
|
401 |
-
AMP_Rule_Spec::FAIL
|
402 |
$should_remove_node = true;
|
403 |
-
} elseif ( isset( $attr_spec_rule[AMP_Rule_Spec::ALLOW_EMPTY] ) &&
|
404 |
-
AMP_Rule_Spec::FAIL
|
405 |
$should_remove_node = true;
|
406 |
-
} elseif ( isset( $attr_spec_rule[AMP_Rule_Spec::DISALLOWED_DOMAIN] ) &&
|
407 |
-
AMP_Rule_Spec::FAIL
|
408 |
$should_remove_node = true;
|
409 |
-
} elseif ( isset( $attr_spec_rule[AMP_Rule_Spec::BLACKLISTED_VALUE_REGEX] ) &&
|
410 |
-
AMP_Rule_Spec::FAIL
|
411 |
$should_remove_node = true;
|
412 |
}
|
413 |
|
414 |
if ( $should_remove_node ) {
|
415 |
$is_mandatory =
|
416 |
isset( $attr_spec_rule[ AMP_Rule_Spec::MANDATORY ] )
|
417 |
-
|
418 |
-
|
419 |
|
420 |
if ( $is_mandatory ) {
|
421 |
$this->remove_node( $node );
|
@@ -426,12 +605,11 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
426 |
}
|
427 |
}
|
428 |
|
429 |
-
// Remove the disallowed values
|
430 |
foreach ( $attrs_to_remove as $attr_name ) {
|
431 |
-
if ( isset( $attr_spec_list[$attr_name][AMP_Rule_Spec::ALLOW_EMPTY] ) &&
|
432 |
-
( true
|
433 |
-
$
|
434 |
-
$attr[ $attr_name ]->value = '';
|
435 |
} else {
|
436 |
$node->removeAttribute( $attr_name );
|
437 |
}
|
@@ -439,29 +617,32 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
439 |
}
|
440 |
|
441 |
/**
|
442 |
-
*
|
443 |
-
* whether the attribute (or a specified alternate) exists.
|
444 |
*
|
445 |
-
*
|
446 |
-
*
|
447 |
-
*
|
448 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
449 |
*/
|
450 |
private function check_attr_spec_rule_mandatory( $node, $attr_name, $attr_spec_rule ) {
|
451 |
-
if ( isset( $attr_spec_rule[AMP_Rule_Spec::MANDATORY] ) &&
|
452 |
-
( true == $attr_spec_rule[AMP_Rule_Spec::MANDATORY] ) ) {
|
453 |
if ( $node->hasAttribute( $attr_name ) ) {
|
454 |
return AMP_Rule_Spec::PASS;
|
455 |
} else {
|
456 |
-
//
|
457 |
-
if ( isset( $attr_spec_rule[AMP_Rule_Spec::ALTERNATIVE_NAMES] ) ) {
|
458 |
-
foreach ( $attr_spec_rule[AMP_Rule_Spec::ALTERNATIVE_NAMES] as $alt_name ) {
|
459 |
if ( $node->hasAttribute( $alt_name ) ) {
|
460 |
return AMP_Rule_Spec::PASS;
|
461 |
}
|
462 |
}
|
463 |
}
|
464 |
-
|
465 |
return AMP_Rule_Spec::FAIL;
|
466 |
}
|
467 |
}
|
@@ -469,27 +650,32 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
469 |
}
|
470 |
|
471 |
/**
|
472 |
-
*
|
473 |
-
*
|
474 |
-
*
|
475 |
-
*
|
476 |
-
*
|
477 |
-
*
|
478 |
-
*
|
479 |
-
*
|
|
|
|
|
|
|
|
|
|
|
480 |
*/
|
481 |
private function check_attr_spec_rule_value( $node, $attr_name, $attr_spec_rule ) {
|
482 |
-
if ( isset( $attr_spec_rule[AMP_Rule_Spec::VALUE] ) ) {
|
483 |
if ( $node->hasAttribute( $attr_name ) ) {
|
484 |
-
if ( $node->getAttribute( $attr_name )
|
485 |
return AMP_Rule_Spec::PASS;
|
486 |
} else {
|
487 |
return AMP_Rule_Spec::FAIL;
|
488 |
}
|
489 |
-
} elseif ( isset( $attr_spec_rule[AMP_Rule_Spec::ALTERNATIVE_NAMES] ) ) {
|
490 |
-
foreach ( $attr_spec_rule[AMP_Rule_Spec::ALTERNATIVE_NAMES] as $alternative_name ) {
|
491 |
if ( $node->hasAttribute( $alternative_name ) ) {
|
492 |
-
if ( $node->getAttribute( $alternative_name )
|
493 |
return AMP_Rule_Spec::PASS;
|
494 |
} else {
|
495 |
return AMP_Rule_Spec::FAIL;
|
@@ -502,31 +688,36 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
502 |
}
|
503 |
|
504 |
/**
|
505 |
-
*
|
506 |
-
*
|
507 |
-
*
|
508 |
-
*
|
509 |
-
*
|
510 |
-
*
|
511 |
-
*
|
512 |
-
*
|
|
|
|
|
|
|
513 |
*/
|
514 |
private function check_attr_spec_rule_value_casei( $node, $attr_name, $attr_spec_rule ) {
|
515 |
-
|
516 |
-
|
517 |
-
|
|
|
|
|
518 |
if ( $node->hasAttribute( $attr_name ) ) {
|
519 |
$attr_value = strtolower( $node->getAttribute( $attr_name ) );
|
520 |
-
if ( $attr_value
|
521 |
return AMP_Rule_Spec::PASS;
|
522 |
} else {
|
523 |
return AMP_Rule_Spec::FAIL;
|
524 |
}
|
525 |
-
} elseif ( isset( $attr_spec_rule[AMP_Rule_Spec::ALTERNATIVE_NAMES] ) ) {
|
526 |
-
foreach ( $attr_spec_rule[AMP_Rule_Spec::ALTERNATIVE_NAMES] as $alternative_name ) {
|
527 |
if ( $node->hasAttribute( $alternative_name ) ) {
|
528 |
$attr_value = strtolower( $node->getAttribute( $alternative_name ) );
|
529 |
-
if ( $attr_value
|
530 |
return AMP_Rule_Spec::PASS;
|
531 |
} else {
|
532 |
return AMP_Rule_Spec::FAIL;
|
@@ -539,25 +730,30 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
539 |
}
|
540 |
|
541 |
/**
|
542 |
-
*
|
543 |
-
*
|
544 |
-
*
|
545 |
-
*
|
546 |
-
*
|
547 |
-
*
|
548 |
-
*
|
549 |
-
*
|
|
|
|
|
|
|
550 |
*/
|
551 |
private function check_attr_spec_rule_value_regex( $node, $attr_name, $attr_spec_rule ) {
|
552 |
-
//
|
553 |
-
if ( isset( $attr_spec_rule[AMP_Rule_Spec::VALUE_REGEX] ) && $node->hasAttribute( $attr_name ) ) {
|
554 |
-
$rule_value = $attr_spec_rule[AMP_Rule_Spec::VALUE_REGEX];
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
|
|
|
|
561 |
return AMP_Rule_Spec::PASS;
|
562 |
} else {
|
563 |
return AMP_Rule_Spec::FAIL;
|
@@ -567,21 +763,27 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
567 |
}
|
568 |
|
569 |
/**
|
570 |
-
*
|
571 |
-
*
|
572 |
-
*
|
573 |
-
*
|
574 |
-
*
|
575 |
-
*
|
576 |
-
*
|
577 |
-
*
|
|
|
|
|
|
|
578 |
*/
|
579 |
private function check_attr_spec_rule_value_regex_casei( $node, $attr_name, $attr_spec_rule ) {
|
580 |
-
|
581 |
-
|
582 |
-
|
|
|
|
|
|
|
583 |
// See note above regarding the '^' and '$' that are added here.
|
584 |
-
if ( preg_match('/^' . $rule_value . '$/ui', $node->getAttribute( $attr_name ) ) ) {
|
585 |
return AMP_Rule_Spec::PASS;
|
586 |
} else {
|
587 |
return AMP_Rule_Spec::FAIL;
|
@@ -591,42 +793,51 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
591 |
}
|
592 |
|
593 |
/**
|
594 |
-
*
|
595 |
-
*
|
596 |
-
*
|
597 |
-
*
|
598 |
-
*
|
599 |
-
*
|
600 |
-
*
|
601 |
-
*
|
|
|
|
|
|
|
602 |
*/
|
603 |
private function check_attr_spec_rule_allowed_protocol( $node, $attr_name, $attr_spec_rule ) {
|
604 |
-
if ( isset( $attr_spec_rule[AMP_Rule_Spec::ALLOWED_PROTOCOL] ) ) {
|
605 |
if ( $node->hasAttribute( $attr_name ) ) {
|
606 |
-
$attr_value
|
607 |
-
$attr_value
|
608 |
$urls_to_test = explode( ',', $attr_value );
|
609 |
foreach ( $urls_to_test as $url ) {
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
|
|
|
|
|
|
614 |
return AMP_Rule_Spec::FAIL;
|
615 |
}
|
616 |
}
|
617 |
}
|
618 |
return AMP_Rule_Spec::PASS;
|
619 |
-
} elseif ( isset( $attr_spec_rule[AMP_Rule_Spec::ALTERNATIVE_NAMES] ) ) {
|
620 |
-
foreach ( $attr_spec_rule[AMP_Rule_Spec::ALTERNATIVE_NAMES] as $alternative_name ) {
|
621 |
if ( $node->hasAttribute( $alternative_name ) ) {
|
622 |
-
$attr_value
|
623 |
-
$attr_value
|
624 |
$urls_to_test = explode( ',', $attr_value );
|
625 |
foreach ( $urls_to_test as $url ) {
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
|
|
|
|
|
|
630 |
return AMP_Rule_Spec::FAIL;
|
631 |
}
|
632 |
}
|
@@ -640,39 +851,44 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
640 |
}
|
641 |
|
642 |
/**
|
643 |
-
*
|
644 |
-
*
|
645 |
-
*
|
646 |
-
*
|
647 |
-
*
|
648 |
-
*
|
649 |
-
*
|
650 |
-
*
|
|
|
|
|
|
|
651 |
*/
|
652 |
private function check_attr_spec_rule_disallowed_relative( $node, $attr_name, $attr_spec_rule ) {
|
653 |
-
if ( isset( $attr_spec_rule[AMP_Rule_Spec::ALLOW_RELATIVE] ) &&
|
654 |
-
( false == $attr_spec_rule[AMP_Rule_Spec::ALLOW_RELATIVE] ) ) {
|
655 |
if ( $node->hasAttribute( $attr_name ) ) {
|
656 |
-
$attr_value
|
657 |
-
$attr_value
|
658 |
$urls_to_test = explode( ',', $attr_value );
|
659 |
foreach ( $urls_to_test as $url ) {
|
660 |
$parsed_url = AMP_WP_Utils::parse_url( $url );
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
|
|
|
|
|
|
666 |
if ( empty( $parsed_url['scheme'] ) ) {
|
667 |
return AMP_Rule_Spec::FAIL;
|
668 |
}
|
669 |
}
|
670 |
return AMP_Rule_Spec::PASS;
|
671 |
-
} elseif ( isset( $attr_spec_rule[AMP_Rule_Spec::ALTERNATIVE_NAMES] ) ) {
|
672 |
-
foreach ( $attr_spec_rule[AMP_Rule_Spec::ALTERNATIVE_NAMES] as $alternative_name ) {
|
673 |
if ( $node->hasAttribute( $alternative_name ) ) {
|
674 |
-
$attr_value
|
675 |
-
$attr_value
|
676 |
$urls_to_test = explode( ',', $attr_value );
|
677 |
foreach ( $urls_to_test as $url ) {
|
678 |
$parsed_url = AMP_WP_Utils::parse_url( $url );
|
@@ -689,19 +905,20 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
689 |
}
|
690 |
|
691 |
/**
|
692 |
-
*
|
693 |
-
*
|
694 |
-
*
|
695 |
-
*
|
696 |
-
*
|
697 |
-
*
|
698 |
-
*
|
699 |
-
*
|
|
|
|
|
|
|
700 |
*/
|
701 |
private function check_attr_spec_rule_disallowed_empty( $node, $attr_name, $attr_spec_rule ) {
|
702 |
-
if ( isset( $attr_spec_rule[AMP_Rule_Spec::ALLOW_EMPTY] ) &&
|
703 |
-
( false == $attr_spec_rule[AMP_Rule_Spec::ALLOW_EMPTY] ) &&
|
704 |
-
$node->hasAttribute( $attr_name ) ) {
|
705 |
$attr_value = $node->getAttribute( $attr_name );
|
706 |
if ( empty( $attr_value ) ) {
|
707 |
return AMP_Rule_Spec::FAIL;
|
@@ -712,23 +929,26 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
712 |
}
|
713 |
|
714 |
/**
|
715 |
-
*
|
716 |
-
*
|
717 |
-
*
|
718 |
-
*
|
719 |
-
*
|
720 |
-
*
|
721 |
-
*
|
722 |
-
*
|
|
|
|
|
|
|
723 |
*/
|
724 |
private function check_attr_spec_rule_disallowed_domain( $node, $attr_name, $attr_spec_rule ) {
|
725 |
-
if ( isset( $attr_spec_rule[AMP_Rule_Spec::DISALLOWED_DOMAIN] ) &&
|
726 |
-
$node->hasAttribute( $attr_name ) ) {
|
727 |
$attr_value = $node->getAttribute( $attr_name );
|
728 |
$url_domain = AMP_WP_Utils::parse_url( $attr_value, PHP_URL_HOST );
|
729 |
if ( ! empty( $url_domain ) ) {
|
730 |
-
foreach ( $attr_spec_rule[AMP_Rule_Spec::DISALLOWED_DOMAIN] as $disallowed_domain ) {
|
731 |
-
if ( strtolower( $url_domain )
|
|
|
732 |
// Found a disallowed domain, fail validation.
|
733 |
return AMP_Rule_Spec::FAIL;
|
734 |
}
|
@@ -740,18 +960,23 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
740 |
}
|
741 |
|
742 |
/**
|
743 |
-
*
|
744 |
-
*
|
745 |
-
*
|
746 |
-
*
|
747 |
-
*
|
748 |
-
*
|
749 |
-
*
|
750 |
-
*
|
|
|
|
|
|
|
|
|
|
|
751 |
*/
|
752 |
private function check_attr_spec_rule_blacklisted_value_regex( $node, $attr_name, $attr_spec_rule ) {
|
753 |
-
if ( isset( $attr_spec_rule[AMP_Rule_Spec::BLACKLISTED_VALUE_REGEX] ) ) {
|
754 |
-
$pattern = '/' . $attr_spec_rule[AMP_Rule_Spec::BLACKLISTED_VALUE_REGEX] . '/u';
|
755 |
if ( $node->hasAttribute( $attr_name ) ) {
|
756 |
$attr_value = $node->getAttribute( $attr_name );
|
757 |
if ( preg_match( $pattern, $attr_value ) ) {
|
@@ -759,8 +984,8 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
759 |
} else {
|
760 |
return AMP_Rule_Spec::PASS;
|
761 |
}
|
762 |
-
} elseif ( isset( $attr_spec_rule[AMP_Rule_Spec::ALTERNATIVE_NAMES] ) ) {
|
763 |
-
foreach( $attr_spec_rule[AMP_Rule_Spec::ALTERNATIVE_NAMES] as $alternative_name ) {
|
764 |
if ( $node->hasAttribute( $alternative_name ) ) {
|
765 |
$attr_value = $node->getAttribute( $alternative_name );
|
766 |
if ( preg_match( $pattern, $attr_value ) ) {
|
@@ -776,12 +1001,16 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
776 |
}
|
777 |
|
778 |
/**
|
779 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
780 |
*/
|
781 |
private function is_amp_allowed_attribute( $attr_name, $attr_spec_list ) {
|
782 |
-
if ( isset( $this->globally_allowed_attributes[ $attr_name ] ) ||
|
783 |
-
isset( $this->layout_allowed_attributes[ $attr_name ] ) ||
|
784 |
-
isset( $attr_spec_list[ $attr_name ] ) ) {
|
785 |
return true;
|
786 |
} else {
|
787 |
foreach ( AMP_Rule_Spec::$whitelisted_attr_regex as $whitelisted_attr_regex ) {
|
@@ -794,31 +1023,52 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
794 |
}
|
795 |
|
796 |
/**
|
797 |
-
*
|
|
|
|
|
|
|
|
|
|
|
798 |
*/
|
799 |
private function is_amp_allowed_tag( $node ) {
|
800 |
-
|
801 |
-
|
802 |
-
|
|
|
|
|
|
|
|
|
|
|
803 |
isset( $this->allowed_tags[ $node->nodeName ] ) ||
|
804 |
-
( XML_COMMENT_NODE
|
805 |
-
( XML_CDATA_SECTION_NODE
|
|
|
806 |
}
|
807 |
|
808 |
/**
|
809 |
-
*
|
810 |
-
*
|
|
|
|
|
|
|
|
|
|
|
811 |
*/
|
812 |
private function has_parent( $node, $parent_tag_name ) {
|
813 |
-
if ( $node && $node->parentNode && ( $node->parentNode->nodeName
|
814 |
return true;
|
815 |
}
|
816 |
return false;
|
817 |
}
|
818 |
|
819 |
/**
|
820 |
-
*
|
821 |
-
*
|
|
|
|
|
|
|
|
|
|
|
822 |
*/
|
823 |
private function has_ancestor( $node, $ancestor_tag_name ) {
|
824 |
if ( $this->get_ancestor_with_tag_name( $node, $ancestor_tag_name ) ) {
|
@@ -828,12 +1078,18 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
828 |
}
|
829 |
|
830 |
/**
|
831 |
-
*
|
832 |
-
*
|
|
|
|
|
|
|
|
|
|
|
833 |
*/
|
834 |
private function get_ancestor_with_tag_name( $node, $ancestor_tag_name ) {
|
835 |
-
while ( $node && $node
|
836 |
-
|
|
|
837 |
return $node;
|
838 |
}
|
839 |
}
|
@@ -841,44 +1097,64 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
841 |
}
|
842 |
|
843 |
/**
|
844 |
-
* Replaces the given node with it's child nodes, if any
|
845 |
-
*
|
|
|
|
|
|
|
|
|
|
|
846 |
*/
|
847 |
private function replace_node_with_children( $node ) {
|
848 |
-
// If node has children, replace it with them and push children onto stack
|
849 |
-
if ( $node->hasChildNodes() && $node->parentNode ) {
|
850 |
|
851 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
852 |
$fragment = $this->dom->createDocumentFragment();
|
853 |
|
854 |
-
// Add all children to fragment/stack
|
855 |
$child = $node->firstChild;
|
856 |
-
while( $child ) {
|
857 |
$fragment->appendChild( $child );
|
858 |
$this->stack[] = $child;
|
859 |
-
$child
|
860 |
}
|
861 |
|
862 |
-
//
|
863 |
$node->parentNode->replaceChild( $fragment, $node );
|
864 |
|
865 |
-
// If node has no children, just remove the node.
|
866 |
-
} else {
|
867 |
-
$this->remove_node( $node );
|
868 |
}
|
869 |
}
|
870 |
|
871 |
/**
|
872 |
-
*
|
873 |
-
*
|
874 |
-
*
|
|
|
|
|
|
|
|
|
|
|
875 |
*/
|
876 |
private function remove_node( $node ) {
|
877 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
878 |
$parent->removeChild( $node );
|
879 |
}
|
880 |
-
while( $parent &&
|
881 |
-
$node
|
882 |
$parent = $parent->parentNode;
|
883 |
if ( $parent ) {
|
884 |
$parent->removeChild( $node );
|
@@ -887,91 +1163,3 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
|
887 |
}
|
888 |
}
|
889 |
|
890 |
-
/**
|
891 |
-
* This is a set of constants that are used throughout the sanitizer.
|
892 |
-
* The rule name strings are listed here because it's easier to have the php
|
893 |
-
* interpreter catch a typo than for me to catch mistyping a string.
|
894 |
-
*/
|
895 |
-
abstract class AMP_Rule_Spec {
|
896 |
-
|
897 |
-
// AMP rule_spec types
|
898 |
-
const ATTR_SPEC_LIST = 'attr_spec_list';
|
899 |
-
const TAG_SPEC = 'tag_spec';
|
900 |
-
|
901 |
-
// AMP attr_spec value check results
|
902 |
-
const PASS = 'pass';
|
903 |
-
const FAIL = 'fail';
|
904 |
-
const NOT_APPLICABLE = 'not_applicable';
|
905 |
-
|
906 |
-
// tag rule names
|
907 |
-
const DISALLOWED_ANCESTOR = 'disallowed_ancestor';
|
908 |
-
const MANDATORY_ANCESTOR = 'mandatory_ancestor';
|
909 |
-
const MANDATORY_PARENT = 'mandatory_parent';
|
910 |
-
|
911 |
-
// attr rule names
|
912 |
-
const ALLOW_EMPTY = 'allow_empty';
|
913 |
-
const ALLOW_RELATIVE = 'allow_relative';
|
914 |
-
const ALLOWED_PROTOCOL = 'allowed_protocol';
|
915 |
-
const ALTERNATIVE_NAMES = 'alternative_names';
|
916 |
-
const BLACKLISTED_VALUE_REGEX = 'blacklisted_value_regex';
|
917 |
-
const DISALLOWED_DOMAIN = 'disallowed_domain';
|
918 |
-
const MANDATORY = 'mandatory';
|
919 |
-
const VALUE = 'value';
|
920 |
-
const VALUE_CASEI = 'value_casei';
|
921 |
-
const VALUE_REGEX = 'value_regex';
|
922 |
-
const VALUE_REGEX_CASEI = 'value_regex_casei';
|
923 |
-
|
924 |
-
// If a node type listed here is invalid, it and it's subtree will be
|
925 |
-
// removed if it is invalid. This is mainly because any children will be
|
926 |
-
// non-functional without this parent.
|
927 |
-
//
|
928 |
-
// If a tag is not listed here, it will be replaced by its children if it
|
929 |
-
// is invalid.
|
930 |
-
//
|
931 |
-
// TODO: There are other nodes that should probably be listed here as well.
|
932 |
-
static $node_types_to_remove_if_invalid = array(
|
933 |
-
'form',
|
934 |
-
'input',
|
935 |
-
'link',
|
936 |
-
'meta',
|
937 |
-
// 'script',
|
938 |
-
'style',
|
939 |
-
);
|
940 |
-
|
941 |
-
// It is mentioned in the documentation in several places that data-* is
|
942 |
-
// generally allowed, but there is no specific rule for it in the protoascii
|
943 |
-
// file, so I'm including it here.
|
944 |
-
static $whitelisted_attr_regex = array(
|
945 |
-
'@^data-[a-zA-Z][\\w:.-]*$@uis',
|
946 |
-
'(update|item|pagination)', // allowed for live reference points
|
947 |
-
);
|
948 |
-
|
949 |
-
static $additional_allowed_tags = array(
|
950 |
-
|
951 |
-
// this is an experimental tag with no protoascii
|
952 |
-
'amp-share-tracking' => array(
|
953 |
-
'attr_spec_list' => array(),
|
954 |
-
'tag_spec' => array(),
|
955 |
-
),
|
956 |
-
|
957 |
-
// this is needed for some tags such as analytics
|
958 |
-
'script' => array(
|
959 |
-
'attr_spec_list' => array(
|
960 |
-
'type' => array(
|
961 |
-
'mandatory' => true,
|
962 |
-
'value_casei' => 'text/javascript',
|
963 |
-
),
|
964 |
-
),
|
965 |
-
'tag_spec' => array(),
|
966 |
-
),
|
967 |
-
'script' => array(
|
968 |
-
'attr_spec_list' => array(
|
969 |
-
'type' => array(
|
970 |
-
'mandatory' => true,
|
971 |
-
'value_casei' => 'application/json',
|
972 |
-
),
|
973 |
-
),
|
974 |
-
'tag_spec' => array(),
|
975 |
-
),
|
976 |
-
);
|
977 |
-
}
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Tag_And_Attribute_Sanitizer
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
|
8 |
/**
|
9 |
+
* Strips the tags and attributes from the content that are not allowed by the AMP spec.
|
10 |
*
|
11 |
* Allowed tags array is generated from this protocol buffer:
|
12 |
+
*
|
13 |
* https://github.com/ampproject/amphtml/blob/master/validator/validator-main.protoascii
|
14 |
* by the python script in amp-wp/bin/amp_wp_build.py. See the comment at the top
|
15 |
* of that file for instructions to generate class-amp-allowed-tags-generated.php.
|
16 |
*
|
17 |
+
* @todo Need to check the following items that are not yet checked by this sanitizer:
|
18 |
+
*
|
19 |
+
* - `also_requires_attr` - if one attribute is present, this requires another.
|
20 |
+
* - `CdataSpec` - CDATA is not validated or sanitized.
|
21 |
+
* - `ChildTagSpec` - Places restrictions on the number and type of child tags.
|
22 |
+
* - `if_value_regex` - if one attribute value matches, this places a restriction
|
23 |
+
* on another attribute/value.
|
24 |
+
* - `mandatory_oneof` - Within the context of the tag, exactly one of the attributes
|
25 |
+
* must be present.
|
26 |
*/
|
27 |
class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Allowed tags.
|
31 |
+
*
|
32 |
+
* @since 0.5
|
33 |
+
*
|
34 |
+
* @var string[]
|
35 |
+
*/
|
36 |
protected $allowed_tags;
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Globally-allowed attributes.
|
40 |
+
*
|
41 |
+
* @since 0.5
|
42 |
+
*
|
43 |
+
* @var array[][]
|
44 |
+
*/
|
45 |
protected $globally_allowed_attributes;
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Layout-allowed attributes.
|
49 |
+
*
|
50 |
+
* @since 0.5
|
51 |
+
*
|
52 |
+
* @var string[]
|
53 |
+
*/
|
54 |
protected $layout_allowed_attributes;
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Stack.
|
58 |
+
*
|
59 |
+
* @since 0.5
|
60 |
+
*
|
61 |
+
* @var DOMElement[]
|
62 |
+
*/
|
63 |
private $stack = array();
|
64 |
|
65 |
+
/**
|
66 |
+
* Default args.
|
67 |
+
*
|
68 |
+
* @since 0.5
|
69 |
+
*
|
70 |
+
* @var array
|
71 |
+
*/
|
72 |
protected $DEFAULT_ARGS = array();
|
73 |
|
74 |
+
/**
|
75 |
+
* AMP_Tag_And_Attribute_Sanitizer constructor.
|
76 |
+
*
|
77 |
+
* @since 0.5
|
78 |
+
*
|
79 |
+
* @param DOMDocument $dom DOM.
|
80 |
+
* @param array $args Args.
|
81 |
+
*/
|
82 |
public function __construct( $dom, $args = array() ) {
|
83 |
$this->DEFAULT_ARGS = array(
|
84 |
'amp_allowed_tags' => AMP_Allowed_Tags_Generated::get_allowed_tags(),
|
88 |
|
89 |
parent::__construct( $dom, $args );
|
90 |
|
91 |
+
/**
|
92 |
+
* Prepare whitelists
|
93 |
+
*/
|
94 |
+
$this->allowed_tags = $this->args['amp_allowed_tags'];
|
95 |
$this->globally_allowed_attributes = $this->args['amp_globally_allowed_attributes'];
|
96 |
+
$this->layout_allowed_attributes = $this->args['amp_layout_allowed_attributes'];
|
97 |
}
|
98 |
|
99 |
+
/**
|
100 |
+
* Sanitize the <video> elements from the HTML contained in this instance's DOMDocument.
|
101 |
+
*
|
102 |
+
* @since 0.5
|
103 |
+
*/
|
104 |
public function sanitize() {
|
105 |
+
|
106 |
+
foreach ( AMP_Rule_Spec::$additional_allowed_tags as $tag_name => $tag_rule_spec ) {
|
107 |
$this->allowed_tags[ $tag_name ][] = $tag_rule_spec;
|
108 |
}
|
109 |
|
110 |
+
/**
|
111 |
+
* Add root of content to the stack.
|
112 |
+
*
|
113 |
+
* @var DOMElement $body
|
114 |
+
*/
|
115 |
$body = $this->get_body_node();
|
116 |
+
|
117 |
$this->stack[] = $body;
|
118 |
|
119 |
+
/**
|
120 |
+
* This loop traverses through the DOM tree iteratively.
|
121 |
+
*/
|
122 |
+
while ( ! empty( $this->stack ) ) {
|
123 |
|
124 |
// Get the next node to process.
|
125 |
$node = array_pop( $this->stack );
|
126 |
|
127 |
+
/**
|
128 |
+
* Process this node.
|
129 |
+
*/
|
130 |
$this->process_node( $node );
|
131 |
|
132 |
+
/*
|
133 |
+
* Push child nodes onto the stack, if any exist.
|
134 |
+
* if node was removed, then it's parentNode value is null.
|
135 |
+
*/
|
136 |
if ( $node->parentNode ) {
|
137 |
$child = $node->firstChild;
|
138 |
while ( $child ) {
|
139 |
$this->stack[] = $child;
|
140 |
+
$child = $child->nextSibling;
|
141 |
}
|
142 |
}
|
143 |
}
|
144 |
}
|
145 |
|
146 |
+
/**
|
147 |
+
* Process a node by sanitizing and/or validating it per.
|
148 |
+
*
|
149 |
+
* @param DOMNode $node Node.
|
150 |
+
*/
|
151 |
private function process_node( $node ) {
|
152 |
+
|
153 |
+
// Don't process text or comment nodes.
|
154 |
+
if ( XML_TEXT_NODE === $node->nodeType || XML_COMMENT_NODE === $node->nodeType || XML_CDATA_SECTION_NODE === $node->nodeType ) {
|
|
|
155 |
return;
|
156 |
}
|
157 |
|
158 |
+
// Remove nodes with tags that have not been whitelisted.
|
159 |
if ( ! $this->is_amp_allowed_tag( $node ) ) {
|
160 |
+
|
161 |
+
// If it's not an allowed tag, replace the node with it's children.
|
162 |
$this->replace_node_with_children( $node );
|
163 |
+
|
164 |
// Return early since this node no longer exists.
|
165 |
return;
|
166 |
}
|
167 |
|
168 |
+
/*
|
169 |
+
* Compile a list of rule_specs to validate for this node
|
170 |
+
* based on tag name of the node.
|
171 |
+
*/
|
172 |
$rule_spec_list_to_validate = array();
|
173 |
+
$rule_spec_list = array();
|
174 |
if ( isset( $this->allowed_tags[ $node->nodeName ] ) ) {
|
175 |
$rule_spec_list = $this->allowed_tags[ $node->nodeName ];
|
176 |
}
|
177 |
foreach ( $rule_spec_list as $id => $rule_spec ) {
|
178 |
+
if ( $this->validate_tag_spec_for_node( $node, $rule_spec[ AMP_Rule_Spec::TAG_SPEC ] ) ) {
|
179 |
$rule_spec_list_to_validate[ $id ] = $rule_spec;
|
180 |
}
|
181 |
}
|
189 |
// The remaining validations all have to do with attributes.
|
190 |
$attr_spec_list = array();
|
191 |
|
192 |
+
/*
|
193 |
+
* If we have exactly one rule_spec, use it's attr_spec_list
|
194 |
+
* to validate the node's attributes.
|
195 |
+
*/
|
196 |
+
if ( 1 === count( $rule_spec_list_to_validate ) ) {
|
197 |
+
$rule_spec = array_pop( $rule_spec_list_to_validate );
|
198 |
+
$attr_spec_list = $rule_spec[ AMP_Rule_Spec::ATTR_SPEC_LIST ];
|
|
|
|
|
199 |
|
200 |
+
} else {
|
201 |
+
/*
|
202 |
+
* If there is more than one valid rule_spec for this node,
|
203 |
+
* then try to deduce which one is intended by inspecting
|
204 |
+
* the node's attributes.
|
205 |
+
*/
|
206 |
+
|
207 |
+
/*
|
208 |
+
* Get a score from each attr_spec_list by seeing how many
|
209 |
+
* attributes and values match the node.
|
210 |
+
*/
|
211 |
$attr_spec_scores = array();
|
212 |
foreach ( $rule_spec_list_to_validate as $spec_id => $rule_spec ) {
|
213 |
+
$attr_spec_scores[ $spec_id ] = $this->validate_attr_spec_list_for_node( $node, $rule_spec[ AMP_Rule_Spec::ATTR_SPEC_LIST ] );
|
214 |
}
|
215 |
|
216 |
// Get the key(s) to the highest score(s).
|
217 |
+
$spec_ids_sorted = array_keys( $attr_spec_scores, max( $attr_spec_scores ), true );
|
218 |
|
219 |
// If there is exactly one attr_spec with a max score, use that one.
|
220 |
+
if ( 1 === count( $spec_ids_sorted ) ) {
|
221 |
+
$attr_spec_list = $rule_spec_list_to_validate[ $spec_ids_sorted[0] ][ AMP_Rule_Spec::ATTR_SPEC_LIST ];
|
|
|
222 |
} else {
|
223 |
// This should not happen very often, but...
|
224 |
// If we're here, then we're not sure which spec should
|
225 |
// be used. Let's use the top scoring ones.
|
226 |
+
foreach ( $spec_ids_sorted as $id ) {
|
227 |
+
$spec_list = isset( $rule_spec_list_to_validate[ $id ][ AMP_Rule_Spec::ATTR_SPEC_LIST ] ) ? $rule_spec_list_to_validate[ $id ][ AMP_Rule_Spec::ATTR_SPEC_LIST ] : null;
|
228 |
+
if ( ! $this->is_missing_mandatory_attribute( $spec_list, $node ) ) {
|
229 |
+
$attr_spec_list = array_merge( $attr_spec_list, $spec_list );
|
230 |
+
}
|
231 |
+
}
|
232 |
+
$first_spec = reset( $rule_spec_list_to_validate );
|
233 |
+
if ( empty( $attr_spec_list ) && isset( $first_spec[ AMP_Rule_Spec::ATTR_SPEC_LIST ] ) ) {
|
234 |
+
$attr_spec_list = $first_spec[ AMP_Rule_Spec::ATTR_SPEC_LIST ];
|
235 |
}
|
236 |
}
|
237 |
+
} // End if().
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
238 |
|
239 |
+
if ( ! empty( $attr_spec_list ) && $this->is_missing_mandatory_attribute( $attr_spec_list, $node ) ) {
|
240 |
+
$this->remove_node( $node );
|
241 |
+
return;
|
|
|
242 |
}
|
243 |
|
244 |
// Remove any remaining disallowed attributes.
|
249 |
}
|
250 |
|
251 |
/**
|
252 |
+
* Whether a node is missing a mandatory attribute.
|
253 |
+
*
|
254 |
+
* @param array $attr_spec The attribute specification.
|
255 |
+
* @param object $node The DOMElement of the node to check.
|
256 |
+
* @return boolean $is_missing boolean Whether a required attribute is missing.
|
257 |
+
*/
|
258 |
+
public function is_missing_mandatory_attribute( $attr_spec, $node ) {
|
259 |
+
if ( ! is_array( $attr_spec ) ) {
|
260 |
+
return false;
|
261 |
+
}
|
262 |
+
foreach ( $attr_spec as $attr_name => $attr_spec_rule_value ) {
|
263 |
+
$is_mandatory = isset( $attr_spec_rule_value[ AMP_Rule_Spec::MANDATORY ] ) ? ( true === $attr_spec_rule_value[ AMP_Rule_Spec::MANDATORY ] ) : false;
|
264 |
+
$attribute_exists = method_exists( $node, 'hasAttribute' ) && $node->hasAttribute( $attr_name );
|
265 |
+
if ( $is_mandatory && ! $attribute_exists ) {
|
266 |
+
return true;
|
267 |
+
}
|
268 |
+
}
|
269 |
+
return false;
|
270 |
+
}
|
271 |
+
|
272 |
+
/**
|
273 |
+
* Determines is a node is currently valid per its tag specification.
|
274 |
+
*
|
275 |
* Checks to see if a node's placement with the DOM is be valid for the
|
276 |
* given tag_spec. If there are restrictions placed on the type of node
|
277 |
* that can be an immediate parent or an ancestor of this node, then make
|
278 |
* sure those restrictions are met.
|
279 |
*
|
280 |
+
* @since 0.5
|
281 |
+
*
|
282 |
+
* @param object $node The node to validate.
|
283 |
+
* @param array $tag_spec The sepecification.
|
284 |
+
* @return boolean $valid Whether the node's placement is valid.
|
285 |
*/
|
286 |
private function validate_tag_spec_for_node( $node, $tag_spec ) {
|
287 |
+
if ( ! empty( $tag_spec[ AMP_Rule_Spec::MANDATORY_PARENT ] ) && ! $this->has_parent( $node, $tag_spec[ AMP_Rule_Spec::MANDATORY_PARENT ] ) ) {
|
|
|
288 |
return false;
|
289 |
}
|
290 |
|
291 |
+
if ( ! empty( $tag_spec[ AMP_Rule_Spec::DISALLOWED_ANCESTOR ] ) ) {
|
292 |
+
foreach ( $tag_spec[ AMP_Rule_Spec::DISALLOWED_ANCESTOR ] as $disallowed_ancestor_node_name ) {
|
293 |
if ( $this->has_ancestor( $node, $disallowed_ancestor_node_name ) ) {
|
294 |
return false;
|
295 |
}
|
296 |
}
|
297 |
}
|
298 |
|
299 |
+
if ( ! empty( $tag_spec[ AMP_Rule_Spec::MANDATORY_ANCESTOR ] ) && ! $this->has_ancestor( $node, $tag_spec[ AMP_Rule_Spec::MANDATORY_ANCESTOR ] ) ) {
|
|
|
300 |
return false;
|
301 |
}
|
302 |
|
304 |
}
|
305 |
|
306 |
/**
|
307 |
+
* Checks to see if a spec is potentially valid.
|
308 |
+
*
|
309 |
+
* Checks the given node based on the attributes present in the node.
|
310 |
*
|
311 |
+
* @note This can be a very expensive function. Use it sparingly.
|
312 |
+
*
|
313 |
+
* @param DOMNode $node Node.
|
314 |
+
* @param array[] $attr_spec_list Attribute Spec list.
|
315 |
+
*
|
316 |
+
* @return int Validity.
|
317 |
*/
|
318 |
private function validate_attr_spec_list_for_node( $node, $attr_spec_list ) {
|
319 |
+
|
320 |
+
/**
|
321 |
+
* If node has no attributes there is no point in continuing.
|
322 |
+
*/
|
323 |
if ( ! $node->hasAttributes() ) {
|
324 |
return 0;
|
325 |
}
|
326 |
|
327 |
+
foreach ( $node->attributes as $attr_name => $attr_node ) {
|
328 |
+
if ( ! isset( $attr_spec_list[ $attr_name ][ AMP_Rule_Spec::ALTERNATIVE_NAMES ] ) ) {
|
329 |
+
continue;
|
|
|
|
|
330 |
}
|
331 |
+
foreach ( $attr_spec_list[ $attr_name ][ AMP_Rule_Spec::ALTERNATIVE_NAMES ] as $attr_alt_name ) {
|
332 |
+
$attr_spec_list[ $attr_alt_name ] = $attr_spec_list[ $attr_name ];
|
333 |
+
}
|
334 |
+
}
|
335 |
+
|
336 |
+
if ( ! $node instanceof DOMElement ) {
|
337 |
+
/*
|
338 |
+
* A DOMNode is not valid for checks so might
|
339 |
+
* as well bail here is not an DOMElement.
|
340 |
+
*/
|
341 |
+
return 0;
|
342 |
}
|
343 |
|
344 |
$score = 0;
|
345 |
|
346 |
+
/*
|
347 |
+
* Iterate through each attribute rule in this attr spec list and run
|
348 |
+
* the series of tests. Each filter is given a `$node`, an `$attr_name`,
|
349 |
+
* and an `$attr_spec_rule`. If the `$attr_spec_rule` seems to be valid
|
350 |
+
* for the given node, then the filter should increment the score by one.
|
351 |
+
*/
|
352 |
foreach ( $attr_spec_list as $attr_name => $attr_spec_rule ) {
|
353 |
|
354 |
+
// If a mandatory attribute is required, and attribute exists, pass.
|
355 |
+
if ( isset( $attr_spec_rule[ AMP_Rule_Spec::MANDATORY ] ) ) {
|
356 |
+
if ( AMP_Rule_Spec::PASS === $this->check_attr_spec_rule_mandatory( $node, $attr_name, $attr_spec_rule ) ) {
|
357 |
+
$score++;
|
358 |
}
|
359 |
}
|
360 |
|
361 |
+
/*
|
362 |
+
* Check 'value' - case sensitive
|
363 |
+
* Given attribute's value must exactly equal value of the rule to pass.
|
364 |
+
*/
|
365 |
+
if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE ] ) ) {
|
366 |
+
if ( AMP_Rule_Spec::PASS === $this->check_attr_spec_rule_value( $node, $attr_name, $attr_spec_rule ) ) {
|
367 |
+
$score++;
|
368 |
}
|
369 |
}
|
370 |
|
371 |
+
/*
|
372 |
+
* Check 'value_regex' - case sensitive regex match
|
373 |
+
* Given attribute's value must be a case insensitive match to regex pattern
|
374 |
+
* specified by the value of rule to pass.
|
375 |
+
*/
|
376 |
+
if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_REGEX ] ) ) {
|
377 |
+
if ( AMP_Rule_Spec::PASS === $this->check_attr_spec_rule_value_regex( $node, $attr_name, $attr_spec_rule ) ) {
|
378 |
+
$score++;
|
379 |
}
|
380 |
}
|
381 |
|
382 |
+
/*
|
383 |
+
* Check 'value_casei' - case insensitive
|
384 |
+
* Given attribute's value must be a case insensitive match to the value of
|
385 |
+
* the rule to pass.
|
386 |
+
*/
|
387 |
+
if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_CASEI ] ) ) {
|
388 |
+
if ( AMP_Rule_Spec::PASS === $this->check_attr_spec_rule_value_casei( $node, $attr_name, $attr_spec_rule ) ) {
|
389 |
+
$score++;
|
390 |
}
|
391 |
}
|
392 |
|
393 |
+
/*
|
394 |
+
* Check 'value_regex_casei' - case insensitive regex match
|
395 |
+
* Given attribute's value must be a case insensitive match to the regex
|
396 |
+
* pattern specified by the value of the rule to pass.
|
397 |
+
*/
|
398 |
+
if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_REGEX_CASEI ] ) ) {
|
399 |
+
if ( AMP_Rule_Spec::PASS === $this->check_attr_spec_rule_value_regex_casei( $node, $attr_name, $attr_spec_rule ) ) {
|
400 |
+
$score++;
|
401 |
}
|
402 |
}
|
403 |
|
404 |
+
/*
|
405 |
+
* If given attribute's value is a URL with a protocol, the protocol must
|
406 |
+
* be in the array specified by the rule's value to pass.
|
407 |
+
*/
|
408 |
+
if ( isset( $attr_spec_rule[ AMP_Rule_Spec::ALLOWED_PROTOCOL ] ) ) {
|
409 |
+
if ( AMP_Rule_Spec::PASS === $this->check_attr_spec_rule_allowed_protocol( $node, $attr_name, $attr_spec_rule ) ) {
|
410 |
+
$score++;
|
411 |
}
|
412 |
}
|
413 |
|
414 |
+
/*
|
415 |
+
* If the given attribute's value is *not* a relative path, and the rule's
|
416 |
+
* value is `false`, then pass.
|
417 |
+
*/
|
418 |
+
if ( isset( $attr_spec_rule[ AMP_Rule_Spec::ALLOW_RELATIVE ] ) ) {
|
419 |
+
if ( AMP_Rule_Spec::PASS === $this->check_attr_spec_rule_disallowed_relative( $node, $attr_name, $attr_spec_rule ) ) {
|
420 |
+
$score++;
|
421 |
}
|
422 |
}
|
423 |
|
424 |
+
/*
|
425 |
+
* If the given attribute's value exists, is non-empty and the rule's value
|
426 |
+
* is false, then pass.
|
427 |
+
*/
|
428 |
+
if ( isset( $attr_spec_rule[ AMP_Rule_Spec::ALLOW_EMPTY ] ) ) {
|
429 |
+
if ( AMP_Rule_Spec::PASS === $this->check_attr_spec_rule_disallowed_empty( $node, $attr_name, $attr_spec_rule ) ) {
|
430 |
+
$score++;
|
431 |
}
|
432 |
}
|
433 |
|
434 |
+
/*
|
435 |
+
* If the given attribute's value is a URL and does not match any of the list
|
436 |
+
* of domains in the value of the rule, then pass.
|
437 |
+
*/
|
438 |
+
if ( isset( $attr_spec_rule[ AMP_Rule_Spec::DISALLOWED_DOMAIN ] ) ) {
|
439 |
+
if ( AMP_Rule_Spec::PASS === $this->check_attr_spec_rule_disallowed_domain( $node, $attr_name, $attr_spec_rule ) ) {
|
440 |
+
$score++;
|
441 |
}
|
442 |
}
|
443 |
|
444 |
+
/*
|
445 |
+
* If the attribute's value exists and does not match the regex specified
|
446 |
+
* by the rule's value, then pass.
|
447 |
+
*/
|
448 |
+
if ( isset( $attr_spec_rule[ AMP_Rule_Spec::BLACKLISTED_VALUE_REGEX ] ) ) {
|
449 |
+
if ( AMP_Rule_Spec::PASS === $this->check_attr_spec_rule_blacklisted_value_regex( $node, $attr_name, $attr_spec_rule ) ) {
|
450 |
+
$score++;
|
451 |
}
|
452 |
}
|
453 |
}
|
454 |
|
|
|
455 |
return $score;
|
456 |
}
|
457 |
|
458 |
/**
|
459 |
+
* Remove attributes from $node that are not listed in $allowed_attrs.
|
460 |
+
*
|
461 |
+
* @param DOMNode $node Node.
|
462 |
+
* @param array[] $attr_spec_list Attribute spec list.
|
463 |
*/
|
464 |
private function sanitize_disallowed_attributes_in_node( $node, $attr_spec_list ) {
|
465 |
+
|
466 |
+
if ( ! $node instanceof DOMElement ) {
|
467 |
+
/**
|
468 |
+
* If $node is only a DOMNode and not a DOMElement we can't
|
469 |
+
* remove an attribute from it anyway. So bail out now.
|
470 |
+
*/
|
471 |
+
return;
|
472 |
+
}
|
473 |
+
|
474 |
+
/*
|
475 |
+
* We can't remove attributes inside the 'foreach' loop without
|
476 |
+
* breaking the iteration. So we keep track of the attributes to
|
477 |
+
* remove in the first loop, then remove them in the second loop.
|
478 |
+
*/
|
479 |
$attrs_to_remove = array();
|
480 |
foreach ( $node->attributes as $attr_name => $attr_node ) {
|
|
|
481 |
if ( ! $this->is_amp_allowed_attribute( $attr_name, $attr_spec_list ) ) {
|
482 |
+
/**
|
483 |
+
* This attribute is not allowed for this node; plan to remove it.
|
484 |
+
*/
|
485 |
$attrs_to_remove[] = $attr_name;
|
486 |
}
|
487 |
}
|
488 |
|
489 |
if ( ! empty( $attrs_to_remove ) ) {
|
490 |
+
/*
|
491 |
+
* Ensure we are not removing attributes listed as an alternate
|
492 |
+
* or allowed attributes, e.g. 'srcset' is an alternate for 'src'.
|
493 |
+
*/
|
494 |
foreach ( $attr_spec_list as $attr_name => $attr_spec_rule_value ) {
|
495 |
+
if ( isset( $attr_spec_rule_value[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] ) ) {
|
496 |
+
foreach ( $attr_spec_rule_value[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] as $alternative_name ) {
|
497 |
$alt_name_keys = array_keys( $attrs_to_remove, $alternative_name, true );
|
498 |
if ( ! empty( $alt_name_keys ) ) {
|
499 |
unset( $attrs_to_remove[ $alt_name_keys[0] ] );
|
502 |
}
|
503 |
}
|
504 |
|
505 |
+
// Remove the disallowed attributes.
|
506 |
foreach ( $attrs_to_remove as $attr_name ) {
|
507 |
$node->removeAttribute( $attr_name );
|
508 |
}
|
510 |
}
|
511 |
|
512 |
/**
|
513 |
+
* Remove invalid AMP attributes values from $node that have been implicitly disallowed.
|
514 |
+
*
|
515 |
+
* Allowed values are found $this->globally_allowed_attributes and in parameter $attr_spec_list
|
516 |
+
*
|
517 |
+
* @param DOMNode $node Node.
|
518 |
+
* @param array[][] $attr_spec_list Attribute spec list.
|
519 |
*/
|
520 |
private function sanitize_disallowed_attribute_values_in_node( $node, $attr_spec_list ) {
|
521 |
+
|
522 |
+
if ( ! $node instanceof DOMElement ) {
|
523 |
+
/*
|
524 |
+
* If $node is only a DOMNode and not a DOMElement we can't
|
525 |
+
* remove an attribute from it anyway. So bail out now.
|
526 |
+
*/
|
527 |
+
return;
|
528 |
+
}
|
529 |
+
|
530 |
+
$this->delegated_sanitize_disallowed_attribute_values_in_node( $node, $this->globally_allowed_attributes );
|
531 |
if ( ! empty( $attr_spec_list ) ) {
|
532 |
+
$this->delegated_sanitize_disallowed_attribute_values_in_node( $node, $attr_spec_list );
|
533 |
}
|
534 |
}
|
535 |
+
|
536 |
+
/**
|
537 |
+
* Remove attributes values from $node that have been disallowed by AMP.
|
538 |
+
*
|
539 |
+
* @see $this->sanitize_disallowed_attribute_values_in_node() which delegates to this method
|
540 |
+
*
|
541 |
+
* @param DOMElement $node Node.
|
542 |
+
* @param array[][] $attr_spec_list Attribute spec list.
|
543 |
+
*/
|
544 |
+
private function delegated_sanitize_disallowed_attribute_values_in_node( $node, $attr_spec_list ) {
|
545 |
$attrs_to_remove = array();
|
546 |
|
547 |
+
foreach ( $attr_spec_list as $attr_name => $attr_val ) {
|
548 |
+
if ( isset( $attr_spec_list[ $attr_name ][ AMP_Rule_Spec::ALTERNATIVE_NAMES ] ) ) {
|
549 |
+
foreach ( $attr_spec_list[ $attr_name ][ AMP_Rule_Spec::ALTERNATIVE_NAMES ] as $attr_alt_name ) {
|
550 |
$attr_spec_list[ $attr_alt_name ] = $attr_spec_list[ $attr_name ];
|
551 |
}
|
552 |
}
|
553 |
}
|
554 |
|
555 |
+
foreach ( $node->attributes as $attr_name => $attr_node ) {
|
|
|
|
|
556 |
|
557 |
+
if ( ! isset( $attr_spec_list[ $attr_name ] ) ) {
|
558 |
continue;
|
559 |
}
|
560 |
|
561 |
$should_remove_node = false;
|
562 |
+
$attr_spec_rule = $attr_spec_list[ $attr_name ];
|
563 |
|
564 |
+
if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE ] ) &&
|
565 |
+
AMP_Rule_Spec::FAIL === $this->check_attr_spec_rule_value( $node, $attr_name, $attr_spec_rule ) ) {
|
566 |
$should_remove_node = true;
|
567 |
+
} elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_CASEI ] ) &&
|
568 |
+
AMP_Rule_Spec::FAIL === $this->check_attr_spec_rule_value_casei( $node, $attr_name, $attr_spec_rule ) ) {
|
569 |
$should_remove_node = true;
|
570 |
+
} elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_REGEX ] ) &&
|
571 |
+
AMP_Rule_Spec::FAIL === $this->check_attr_spec_rule_value_regex( $node, $attr_name, $attr_spec_rule ) ) {
|
572 |
$should_remove_node = true;
|
573 |
+
} elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_REGEX_CASEI ] ) &&
|
574 |
+
AMP_Rule_Spec::FAIL === $this->check_attr_spec_rule_value_regex_casei( $node, $attr_name, $attr_spec_rule ) ) {
|
575 |
$should_remove_node = true;
|
576 |
+
} elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::ALLOWED_PROTOCOL ] ) &&
|
577 |
+
AMP_Rule_Spec::FAIL === $this->check_attr_spec_rule_allowed_protocol( $node, $attr_name, $attr_spec_rule ) ) {
|
578 |
$should_remove_node = true;
|
579 |
+
} elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::ALLOW_RELATIVE ] ) &&
|
580 |
+
AMP_Rule_Spec::FAIL === $this->check_attr_spec_rule_disallowed_relative( $node, $attr_name, $attr_spec_rule ) ) {
|
581 |
$should_remove_node = true;
|
582 |
+
} elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::ALLOW_EMPTY ] ) &&
|
583 |
+
AMP_Rule_Spec::FAIL === $this->check_attr_spec_rule_disallowed_empty( $node, $attr_name, $attr_spec_rule ) ) {
|
584 |
$should_remove_node = true;
|
585 |
+
} elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::DISALLOWED_DOMAIN ] ) &&
|
586 |
+
AMP_Rule_Spec::FAIL === $this->check_attr_spec_rule_disallowed_domain( $node, $attr_name, $attr_spec_rule ) ) {
|
587 |
$should_remove_node = true;
|
588 |
+
} elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::BLACKLISTED_VALUE_REGEX ] ) &&
|
589 |
+
AMP_Rule_Spec::FAIL === $this->check_attr_spec_rule_blacklisted_value_regex( $node, $attr_name, $attr_spec_rule ) ) {
|
590 |
$should_remove_node = true;
|
591 |
}
|
592 |
|
593 |
if ( $should_remove_node ) {
|
594 |
$is_mandatory =
|
595 |
isset( $attr_spec_rule[ AMP_Rule_Spec::MANDATORY ] )
|
596 |
+
? (bool) $attr_spec_rule[ AMP_Rule_Spec::MANDATORY ]
|
597 |
+
: false;
|
598 |
|
599 |
if ( $is_mandatory ) {
|
600 |
$this->remove_node( $node );
|
605 |
}
|
606 |
}
|
607 |
|
608 |
+
// Remove the disallowed values.
|
609 |
foreach ( $attrs_to_remove as $attr_name ) {
|
610 |
+
if ( isset( $attr_spec_list[ $attr_name ][ AMP_Rule_Spec::ALLOW_EMPTY ] ) &&
|
611 |
+
( true === $attr_spec_list[ $attr_name ][ AMP_Rule_Spec::ALLOW_EMPTY ] ) ) {
|
612 |
+
$node->setAttribute( $attr_name, '' );
|
|
|
613 |
} else {
|
614 |
$node->removeAttribute( $attr_name );
|
615 |
}
|
617 |
}
|
618 |
|
619 |
/**
|
620 |
+
* Check if attribute is mandatory determine whether it exists in $node.
|
|
|
621 |
*
|
622 |
+
* When checking for the given attribute it also checks valid alternates.
|
623 |
+
*
|
624 |
+
* @param DOMElement $node Node.
|
625 |
+
* @param string $attr_name Attribute name.
|
626 |
+
* @param array[] $attr_spec_rule Attribute spec rule.
|
627 |
+
*
|
628 |
+
* @return string:
|
629 |
+
* - AMP_Rule_Spec::PASS - $attr_name is mandatory and it exists
|
630 |
+
* - AMP_Rule_Spec::FAIL - $attr_name is mandatory, but doesn't exist
|
631 |
+
* - AMP_Rule_Spec::NOT_APPLICABLE - $attr_name is not mandatory
|
632 |
*/
|
633 |
private function check_attr_spec_rule_mandatory( $node, $attr_name, $attr_spec_rule ) {
|
634 |
+
if ( isset( $attr_spec_rule[ AMP_Rule_Spec::MANDATORY ] ) && ( $attr_spec_rule[ AMP_Rule_Spec::MANDATORY ] ) ) {
|
|
|
635 |
if ( $node->hasAttribute( $attr_name ) ) {
|
636 |
return AMP_Rule_Spec::PASS;
|
637 |
} else {
|
638 |
+
// Check if an alternative name list is specified.
|
639 |
+
if ( isset( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] ) ) {
|
640 |
+
foreach ( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] as $alt_name ) {
|
641 |
if ( $node->hasAttribute( $alt_name ) ) {
|
642 |
return AMP_Rule_Spec::PASS;
|
643 |
}
|
644 |
}
|
645 |
}
|
|
|
646 |
return AMP_Rule_Spec::FAIL;
|
647 |
}
|
648 |
}
|
650 |
}
|
651 |
|
652 |
/**
|
653 |
+
* Check if attribute has a value rule determine if its value is valid.
|
654 |
+
*
|
655 |
+
* Checks for value validity by matches against valid values.
|
656 |
+
*
|
657 |
+
* @param DOMElement $node Node.
|
658 |
+
* @param string $attr_name Attribute name.
|
659 |
+
* @param array[] $attr_spec_rule Attribute spec rule.
|
660 |
+
*
|
661 |
+
* @return string:
|
662 |
+
* - AMP_Rule_Spec::PASS - $attr_name has a value that matches the rule.
|
663 |
+
* - AMP_Rule_Spec::FAIL - $attr_name has a value that does *not* match rule.
|
664 |
+
* - AMP_Rule_Spec::NOT_APPLICABLE - $attr_name does not exist or there
|
665 |
+
* is no rule for this attribute.
|
666 |
*/
|
667 |
private function check_attr_spec_rule_value( $node, $attr_name, $attr_spec_rule ) {
|
668 |
+
if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE ] ) ) {
|
669 |
if ( $node->hasAttribute( $attr_name ) ) {
|
670 |
+
if ( $node->getAttribute( $attr_name ) === $attr_spec_rule[ AMP_Rule_Spec::VALUE ] ) {
|
671 |
return AMP_Rule_Spec::PASS;
|
672 |
} else {
|
673 |
return AMP_Rule_Spec::FAIL;
|
674 |
}
|
675 |
+
} elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] ) ) {
|
676 |
+
foreach ( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] as $alternative_name ) {
|
677 |
if ( $node->hasAttribute( $alternative_name ) ) {
|
678 |
+
if ( $node->getAttribute( $alternative_name ) === $attr_spec_rule[ AMP_Rule_Spec::VALUE ] ) {
|
679 |
return AMP_Rule_Spec::PASS;
|
680 |
} else {
|
681 |
return AMP_Rule_Spec::FAIL;
|
688 |
}
|
689 |
|
690 |
/**
|
691 |
+
* Check if attribute has a value rule determine if its value matches ignoring case.
|
692 |
+
*
|
693 |
+
* @param DOMElement $node Node.
|
694 |
+
* @param string $attr_name Attribute name.
|
695 |
+
* @param array[]|string[] $attr_spec_rule Attribute spec rule.
|
696 |
+
*
|
697 |
+
* @return string:
|
698 |
+
* - AMP_Rule_Spec::PASS - $attr_name has a value that matches the rule.
|
699 |
+
* - AMP_Rule_Spec::FAIL - $attr_name has a value that does *not* match rule.
|
700 |
+
* - AMP_Rule_Spec::NOT_APPLICABLE - $attr_name does not exist or there
|
701 |
+
* is no rule for this attribute.
|
702 |
*/
|
703 |
private function check_attr_spec_rule_value_casei( $node, $attr_name, $attr_spec_rule ) {
|
704 |
+
/**
|
705 |
+
* Check 'value_casei' - case insensitive
|
706 |
+
*/
|
707 |
+
if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_CASEI ] ) ) {
|
708 |
+
$rule_value = strtolower( $attr_spec_rule[ AMP_Rule_Spec::VALUE_CASEI ] );
|
709 |
if ( $node->hasAttribute( $attr_name ) ) {
|
710 |
$attr_value = strtolower( $node->getAttribute( $attr_name ) );
|
711 |
+
if ( $attr_value === (string) $rule_value ) {
|
712 |
return AMP_Rule_Spec::PASS;
|
713 |
} else {
|
714 |
return AMP_Rule_Spec::FAIL;
|
715 |
}
|
716 |
+
} elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] ) ) {
|
717 |
+
foreach ( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] as $alternative_name ) {
|
718 |
if ( $node->hasAttribute( $alternative_name ) ) {
|
719 |
$attr_value = strtolower( $node->getAttribute( $alternative_name ) );
|
720 |
+
if ( $attr_value === (string) $rule_value ) {
|
721 |
return AMP_Rule_Spec::PASS;
|
722 |
} else {
|
723 |
return AMP_Rule_Spec::FAIL;
|
730 |
}
|
731 |
|
732 |
/**
|
733 |
+
* Check if attribute has a regex value rule determine if it matches.
|
734 |
+
*
|
735 |
+
* @param DOMElement $node Node.
|
736 |
+
* @param string $attr_name Attribute name.
|
737 |
+
* @param array[]|string[] $attr_spec_rule Attribute spec rule.
|
738 |
+
*
|
739 |
+
* @return string:
|
740 |
+
* - AMP_Rule_Spec::PASS - $attr_name has a value that matches the rule.
|
741 |
+
* - AMP_Rule_Spec::FAIL - $attr_name has a value that does *not* match rule.
|
742 |
+
* - AMP_Rule_Spec::NOT_APPLICABLE - $attr_name does not exist or there
|
743 |
+
* is no rule for this attribute.
|
744 |
*/
|
745 |
private function check_attr_spec_rule_value_regex( $node, $attr_name, $attr_spec_rule ) {
|
746 |
+
// Check 'value_regex' - case sensitive regex match.
|
747 |
+
if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_REGEX ] ) && $node->hasAttribute( $attr_name ) ) {
|
748 |
+
$rule_value = $attr_spec_rule[ AMP_Rule_Spec::VALUE_REGEX ];
|
749 |
+
|
750 |
+
/*
|
751 |
+
* The regex pattern has '^' and '$' though they are not in the AMP spec.
|
752 |
+
* Leaving them out would allow both '_blank' and 'yyy_blankzzz' to be
|
753 |
+
* matched by a regex rule of '(_blank|_self|_top)'. As the AMP JS validator
|
754 |
+
* only accepts '_blank' we leave it this way for now.
|
755 |
+
*/
|
756 |
+
if ( preg_match( '@^' . $rule_value . '$@u', $node->getAttribute( $attr_name ) ) ) {
|
757 |
return AMP_Rule_Spec::PASS;
|
758 |
} else {
|
759 |
return AMP_Rule_Spec::FAIL;
|
763 |
}
|
764 |
|
765 |
/**
|
766 |
+
* Check if attribute has a case-insensitive regex value rule determine if it matches.
|
767 |
+
*
|
768 |
+
* @param DOMElement $node Node.
|
769 |
+
* @param string $attr_name Attribute name.
|
770 |
+
* @param array[]|string[] $attr_spec_rule Attribute spec rule.
|
771 |
+
*
|
772 |
+
* @return string:
|
773 |
+
* - AMP_Rule_Spec::PASS - $attr_name has a value that matches the rule.
|
774 |
+
* - AMP_Rule_Spec::FAIL - $attr_name has a value that does *not* match rule.
|
775 |
+
* - AMP_Rule_Spec::NOT_APPLICABLE - $attr_name does not exist or there
|
776 |
+
* is no rule for this attribute.
|
777 |
*/
|
778 |
private function check_attr_spec_rule_value_regex_casei( $node, $attr_name, $attr_spec_rule ) {
|
779 |
+
/**
|
780 |
+
* Check 'value_regex_casei' - case insensitive regex match
|
781 |
+
*/
|
782 |
+
if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_REGEX_CASEI ] ) && $node->hasAttribute( $attr_name ) ) {
|
783 |
+
$rule_value = $attr_spec_rule[ AMP_Rule_Spec::VALUE_REGEX_CASEI ];
|
784 |
+
|
785 |
// See note above regarding the '^' and '$' that are added here.
|
786 |
+
if ( preg_match( '/^' . $rule_value . '$/ui', $node->getAttribute( $attr_name ) ) ) {
|
787 |
return AMP_Rule_Spec::PASS;
|
788 |
} else {
|
789 |
return AMP_Rule_Spec::FAIL;
|
793 |
}
|
794 |
|
795 |
/**
|
796 |
+
* Check if attribute has a protocol value rule determine if it matches.
|
797 |
+
*
|
798 |
+
* @param DOMElement $node Node.
|
799 |
+
* @param string $attr_name Attribute name.
|
800 |
+
* @param array[]|string[] $attr_spec_rule Attribute spec rule.
|
801 |
+
*
|
802 |
+
* @return string:
|
803 |
+
* - AMP_Rule_Spec::PASS - $attr_name has a value that matches the rule.
|
804 |
+
* - AMP_Rule_Spec::FAIL - $attr_name has a value that does *not* match rule.
|
805 |
+
* - AMP_Rule_Spec::NOT_APPLICABLE - $attr_name does not exist or there
|
806 |
+
* is no rule for this attribute.
|
807 |
*/
|
808 |
private function check_attr_spec_rule_allowed_protocol( $node, $attr_name, $attr_spec_rule ) {
|
809 |
+
if ( isset( $attr_spec_rule[ AMP_Rule_Spec::ALLOWED_PROTOCOL ] ) ) {
|
810 |
if ( $node->hasAttribute( $attr_name ) ) {
|
811 |
+
$attr_value = $node->getAttribute( $attr_name );
|
812 |
+
$attr_value = preg_replace( '/\s*,\s*/', ',', $attr_value );
|
813 |
$urls_to_test = explode( ',', $attr_value );
|
814 |
foreach ( $urls_to_test as $url ) {
|
815 |
+
/*
|
816 |
+
* This seems to be an acceptable check since the AMP validator
|
817 |
+
* will allow a URL with no protocol to pass validation.
|
818 |
+
*/
|
819 |
+
$url_scheme = AMP_WP_Utils::parse_url( $url, PHP_URL_SCHEME );
|
820 |
+
if ( $url_scheme ) {
|
821 |
+
if ( ! in_array( strtolower( $url_scheme ), $attr_spec_rule[ AMP_Rule_Spec::ALLOWED_PROTOCOL ], true ) ) {
|
822 |
return AMP_Rule_Spec::FAIL;
|
823 |
}
|
824 |
}
|
825 |
}
|
826 |
return AMP_Rule_Spec::PASS;
|
827 |
+
} elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] ) ) {
|
828 |
+
foreach ( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] as $alternative_name ) {
|
829 |
if ( $node->hasAttribute( $alternative_name ) ) {
|
830 |
+
$attr_value = $node->getAttribute( $alternative_name );
|
831 |
+
$attr_value = preg_replace( '/\s*,\s*/', ',', $attr_value );
|
832 |
$urls_to_test = explode( ',', $attr_value );
|
833 |
foreach ( $urls_to_test as $url ) {
|
834 |
+
/*
|
835 |
+
* This seems to be an acceptable check since the AMP validator
|
836 |
+
* will allow a URL with no protocol to pass validation.
|
837 |
+
*/
|
838 |
+
$url_scheme = AMP_WP_Utils::parse_url( $url, PHP_URL_SCHEME );
|
839 |
+
if ( $url_scheme ) {
|
840 |
+
if ( ! in_array( strtolower( $url_scheme ), $attr_spec_rule[ AMP_Rule_Spec::ALLOWED_PROTOCOL ], true ) ) {
|
841 |
return AMP_Rule_Spec::FAIL;
|
842 |
}
|
843 |
}
|
851 |
}
|
852 |
|
853 |
/**
|
854 |
+
* Check if attribute has disallowed relative value rule determine if disallowed relative value matches.
|
855 |
+
*
|
856 |
+
* @param DOMElement $node Node.
|
857 |
+
* @param string $attr_name Attribute name.
|
858 |
+
* @param array[]|string[] $attr_spec_rule Attribute spec rule.
|
859 |
+
*
|
860 |
+
* @return string:
|
861 |
+
* - AMP_Rule_Spec::PASS - $attr_name has a value that matches the rule.
|
862 |
+
* - AMP_Rule_Spec::FAIL - $attr_name has a value that does *not* match rule.
|
863 |
+
* - AMP_Rule_Spec::NOT_APPLICABLE - $attr_name does not exist or there
|
864 |
+
* is no rule for this attribute.
|
865 |
*/
|
866 |
private function check_attr_spec_rule_disallowed_relative( $node, $attr_name, $attr_spec_rule ) {
|
867 |
+
if ( isset( $attr_spec_rule[ AMP_Rule_Spec::ALLOW_RELATIVE ] ) && ! ( $attr_spec_rule[ AMP_Rule_Spec::ALLOW_RELATIVE ] ) ) {
|
|
|
868 |
if ( $node->hasAttribute( $attr_name ) ) {
|
869 |
+
$attr_value = $node->getAttribute( $attr_name );
|
870 |
+
$attr_value = preg_replace( '/\s*,\s*/', ',', $attr_value );
|
871 |
$urls_to_test = explode( ',', $attr_value );
|
872 |
foreach ( $urls_to_test as $url ) {
|
873 |
$parsed_url = AMP_WP_Utils::parse_url( $url );
|
874 |
+
|
875 |
+
/*
|
876 |
+
* The JS AMP validator seems to consider 'relative' to mean
|
877 |
+
* *protocol* relative, not *host* relative for this rule. So,
|
878 |
+
* a url with an empty 'scheme' is considered "relative" by AMP.
|
879 |
+
* ie. '//domain.com/path' and '/path' should both be considered
|
880 |
+
* relative for purposes of AMP validation.
|
881 |
+
*/
|
882 |
if ( empty( $parsed_url['scheme'] ) ) {
|
883 |
return AMP_Rule_Spec::FAIL;
|
884 |
}
|
885 |
}
|
886 |
return AMP_Rule_Spec::PASS;
|
887 |
+
} elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] ) ) {
|
888 |
+
foreach ( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] as $alternative_name ) {
|
889 |
if ( $node->hasAttribute( $alternative_name ) ) {
|
890 |
+
$attr_value = $node->getAttribute( $alternative_name );
|
891 |
+
$attr_value = preg_replace( '/\s*,\s*/', ',', $attr_value );
|
892 |
$urls_to_test = explode( ',', $attr_value );
|
893 |
foreach ( $urls_to_test as $url ) {
|
894 |
$parsed_url = AMP_WP_Utils::parse_url( $url );
|
905 |
}
|
906 |
|
907 |
/**
|
908 |
+
* Check if attribute has disallowed empty value rule determine if value is empty.
|
909 |
+
*
|
910 |
+
* @param DOMElement $node Node.
|
911 |
+
* @param string $attr_name Attribute name.
|
912 |
+
* @param array[]|string[] $attr_spec_rule Attribute spec rule.
|
913 |
+
*
|
914 |
+
* @return string:
|
915 |
+
* - AMP_Rule_Spec::PASS - $attr_name has a value that matches the rule.
|
916 |
+
* - AMP_Rule_Spec::FAIL - $attr_name has a value that does *not* match rule.
|
917 |
+
* - AMP_Rule_Spec::NOT_APPLICABLE - $attr_name does not exist or there
|
918 |
+
* is no rule for this attribute.
|
919 |
*/
|
920 |
private function check_attr_spec_rule_disallowed_empty( $node, $attr_name, $attr_spec_rule ) {
|
921 |
+
if ( isset( $attr_spec_rule[ AMP_Rule_Spec::ALLOW_EMPTY ] ) && ! ( $attr_spec_rule[ AMP_Rule_Spec::ALLOW_EMPTY ] ) && $node->hasAttribute( $attr_name ) ) {
|
|
|
|
|
922 |
$attr_value = $node->getAttribute( $attr_name );
|
923 |
if ( empty( $attr_value ) ) {
|
924 |
return AMP_Rule_Spec::FAIL;
|
929 |
}
|
930 |
|
931 |
/**
|
932 |
+
* Check if attribute has disallowed domain value rule determine if value matches.
|
933 |
+
*
|
934 |
+
* @param DOMElement $node Node.
|
935 |
+
* @param string $attr_name Attribute name.
|
936 |
+
* @param array[]|string[] $attr_spec_rule Attribute spec rule.
|
937 |
+
*
|
938 |
+
* @return string:
|
939 |
+
* - AMP_Rule_Spec::PASS - $attr_name has a value that matches the rule.
|
940 |
+
* - AMP_Rule_Spec::FAIL - $attr_name has a value that does *not* match rule.
|
941 |
+
* - AMP_Rule_Spec::NOT_APPLICABLE - $attr_name does not exist or there
|
942 |
+
* is no rule for this attribute.
|
943 |
*/
|
944 |
private function check_attr_spec_rule_disallowed_domain( $node, $attr_name, $attr_spec_rule ) {
|
945 |
+
if ( isset( $attr_spec_rule[ AMP_Rule_Spec::DISALLOWED_DOMAIN ] ) && $node->hasAttribute( $attr_name ) ) {
|
|
|
946 |
$attr_value = $node->getAttribute( $attr_name );
|
947 |
$url_domain = AMP_WP_Utils::parse_url( $attr_value, PHP_URL_HOST );
|
948 |
if ( ! empty( $url_domain ) ) {
|
949 |
+
foreach ( $attr_spec_rule[ AMP_Rule_Spec::DISALLOWED_DOMAIN ] as $disallowed_domain ) {
|
950 |
+
if ( strtolower( $url_domain ) === strtolower( $disallowed_domain ) ) {
|
951 |
+
|
952 |
// Found a disallowed domain, fail validation.
|
953 |
return AMP_Rule_Spec::FAIL;
|
954 |
}
|
960 |
}
|
961 |
|
962 |
/**
|
963 |
+
* Check if attribute has blacklisted value via regex match determine if value matches.
|
964 |
+
*
|
965 |
+
* @since 0.5
|
966 |
+
*
|
967 |
+
* @param DOMElement $node Node.
|
968 |
+
* @param string $attr_name Attribute name.
|
969 |
+
* @param array[]|string[] $attr_spec_rule Attribute spec rule.
|
970 |
+
*
|
971 |
+
* @return string:
|
972 |
+
* - AMP_Rule_Spec::PASS - $attr_name has a value that matches the rule.
|
973 |
+
* - AMP_Rule_Spec::FAIL - $attr_name has a value that does *not* match rule.
|
974 |
+
* - AMP_Rule_Spec::NOT_APPLICABLE - $attr_name does not exist or there
|
975 |
+
* is no rule for this attribute.
|
976 |
*/
|
977 |
private function check_attr_spec_rule_blacklisted_value_regex( $node, $attr_name, $attr_spec_rule ) {
|
978 |
+
if ( isset( $attr_spec_rule[ AMP_Rule_Spec::BLACKLISTED_VALUE_REGEX ] ) ) {
|
979 |
+
$pattern = '/' . $attr_spec_rule[ AMP_Rule_Spec::BLACKLISTED_VALUE_REGEX ] . '/u';
|
980 |
if ( $node->hasAttribute( $attr_name ) ) {
|
981 |
$attr_value = $node->getAttribute( $attr_name );
|
982 |
if ( preg_match( $pattern, $attr_value ) ) {
|
984 |
} else {
|
985 |
return AMP_Rule_Spec::PASS;
|
986 |
}
|
987 |
+
} elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] ) ) {
|
988 |
+
foreach ( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] as $alternative_name ) {
|
989 |
if ( $node->hasAttribute( $alternative_name ) ) {
|
990 |
$attr_value = $node->getAttribute( $alternative_name );
|
991 |
if ( preg_match( $pattern, $attr_value ) ) {
|
1001 |
}
|
1002 |
|
1003 |
/**
|
1004 |
+
* Determine if the supplied attribute name is allowed for AMP.
|
1005 |
+
*
|
1006 |
+
* @since 0.5
|
1007 |
+
*
|
1008 |
+
* @param string $attr_name Attribute name.
|
1009 |
+
* @param array[]|string[] $attr_spec_list Attribute spec list.
|
1010 |
+
* @return bool Return true if attribute name is valid for this attr_spec_list, false otherwise.
|
1011 |
*/
|
1012 |
private function is_amp_allowed_attribute( $attr_name, $attr_spec_list ) {
|
1013 |
+
if ( isset( $this->globally_allowed_attributes[ $attr_name ] ) || isset( $this->layout_allowed_attributes[ $attr_name ] ) || isset( $attr_spec_list[ $attr_name ] ) ) {
|
|
|
|
|
1014 |
return true;
|
1015 |
} else {
|
1016 |
foreach ( AMP_Rule_Spec::$whitelisted_attr_regex as $whitelisted_attr_regex ) {
|
1023 |
}
|
1024 |
|
1025 |
/**
|
1026 |
+
* Determine if the supplied $node's HTML tag is allowed for AMP.
|
1027 |
+
*
|
1028 |
+
* @since 0.5
|
1029 |
+
*
|
1030 |
+
* @param DOMNode $node Node.
|
1031 |
+
* @return bool Return true if the specified node's name is an AMP allowed tag, false otherwise.
|
1032 |
*/
|
1033 |
private function is_amp_allowed_tag( $node ) {
|
1034 |
+
if ( ! $node instanceof DOMElement ) {
|
1035 |
+
return false;
|
1036 |
+
}
|
1037 |
+
/**
|
1038 |
+
* Return true if node is an allowed tags or is a text or comment node.
|
1039 |
+
*/
|
1040 |
+
return (
|
1041 |
+
( XML_TEXT_NODE === $node->nodeType ) ||
|
1042 |
isset( $this->allowed_tags[ $node->nodeName ] ) ||
|
1043 |
+
( XML_COMMENT_NODE === $node->nodeType ) ||
|
1044 |
+
( XML_CDATA_SECTION_NODE === $node->nodeType )
|
1045 |
+
);
|
1046 |
}
|
1047 |
|
1048 |
/**
|
1049 |
+
* Determine if the supplied $node has a parent with the specified tag name.
|
1050 |
+
*
|
1051 |
+
* @since 0.5
|
1052 |
+
*
|
1053 |
+
* @param DOMNode $node Node.
|
1054 |
+
* @param string $parent_tag_name Parent tag name.
|
1055 |
+
* @return bool Return true if given node has direct parent with the given name, false otherwise.
|
1056 |
*/
|
1057 |
private function has_parent( $node, $parent_tag_name ) {
|
1058 |
+
if ( $node && $node->parentNode && ( $node->parentNode->nodeName === $parent_tag_name ) ) {
|
1059 |
return true;
|
1060 |
}
|
1061 |
return false;
|
1062 |
}
|
1063 |
|
1064 |
/**
|
1065 |
+
* Determine if the supplied $node has an ancestor with the specified tag name.
|
1066 |
+
*
|
1067 |
+
* @since 0.5
|
1068 |
+
*
|
1069 |
+
* @param DOMNode $node Node.
|
1070 |
+
* @param string $ancestor_tag_name Ancestor tag name.
|
1071 |
+
* @return bool Return true if given node has any ancestor with the give name, false otherwise.
|
1072 |
*/
|
1073 |
private function has_ancestor( $node, $ancestor_tag_name ) {
|
1074 |
if ( $this->get_ancestor_with_tag_name( $node, $ancestor_tag_name ) ) {
|
1078 |
}
|
1079 |
|
1080 |
/**
|
1081 |
+
* Get the first ancestor node matching the specified tag name for the supplied $node.
|
1082 |
+
*
|
1083 |
+
* @since 0.5
|
1084 |
+
*
|
1085 |
+
* @param DOMNode $node Node.
|
1086 |
+
* @param string $ancestor_tag_name Ancestor tag name.
|
1087 |
+
* @return DOMNode|null Returns an ancestor node for the name specified, or null if not found.
|
1088 |
*/
|
1089 |
private function get_ancestor_with_tag_name( $node, $ancestor_tag_name ) {
|
1090 |
+
while ( $node && $node->parentNode ) {
|
1091 |
+
$node = $node->parentNode;
|
1092 |
+
if ( $node->nodeName === $ancestor_tag_name ) {
|
1093 |
return $node;
|
1094 |
}
|
1095 |
}
|
1097 |
}
|
1098 |
|
1099 |
/**
|
1100 |
+
* Replaces the given node with it's child nodes, if any
|
1101 |
+
*
|
1102 |
+
* Also adds them to the stack for processing by the sanitize() function.
|
1103 |
+
*
|
1104 |
+
* @since 0.3.3
|
1105 |
+
*
|
1106 |
+
* @param DOMNode $node Node.
|
1107 |
*/
|
1108 |
private function replace_node_with_children( $node ) {
|
|
|
|
|
1109 |
|
1110 |
+
if ( ! $node->hasChildNodes() || ! $node->parentNode ) {
|
1111 |
+
// If node has no children or no parent, just remove the node.
|
1112 |
+
$this->remove_node( $node );
|
1113 |
+
|
1114 |
+
} else {
|
1115 |
+
/*
|
1116 |
+
* If node has children, replace it with them and push children onto stack
|
1117 |
+
*
|
1118 |
+
* Create a DOM fragment to hold the children
|
1119 |
+
*/
|
1120 |
$fragment = $this->dom->createDocumentFragment();
|
1121 |
|
1122 |
+
// Add all children to fragment/stack.
|
1123 |
$child = $node->firstChild;
|
1124 |
+
while ( $child ) {
|
1125 |
$fragment->appendChild( $child );
|
1126 |
$this->stack[] = $child;
|
1127 |
+
$child = $node->firstChild;
|
1128 |
}
|
1129 |
|
1130 |
+
// Replace node with fragment.
|
1131 |
$node->parentNode->replaceChild( $fragment, $node );
|
1132 |
|
|
|
|
|
|
|
1133 |
}
|
1134 |
}
|
1135 |
|
1136 |
/**
|
1137 |
+
* Removes a node from its parent node.
|
1138 |
+
*
|
1139 |
+
* If removing the node makes the parent node empty, then it will remove the parent
|
1140 |
+
* too. It will Continue until a non-empty parent or the 'body' element is reached.
|
1141 |
+
*
|
1142 |
+
* @since 0.5
|
1143 |
+
*
|
1144 |
+
* @param DOMNode $node Node.
|
1145 |
*/
|
1146 |
private function remove_node( $node ) {
|
1147 |
+
/**
|
1148 |
+
* Parent.
|
1149 |
+
*
|
1150 |
+
* @var DOMNode $parent
|
1151 |
+
*/
|
1152 |
+
$parent = $node->parentNode;
|
1153 |
+
if ( $node && $parent ) {
|
1154 |
$parent->removeChild( $node );
|
1155 |
}
|
1156 |
+
while ( $parent && ! $parent->hasChildNodes() && 'body' !== $parent->nodeName ) {
|
1157 |
+
$node = $parent;
|
1158 |
$parent = $parent->parentNode;
|
1159 |
if ( $parent ) {
|
1160 |
$parent->removeChild( $node );
|
1163 |
}
|
1164 |
}
|
1165 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
includes/sanitizers/class-amp-video-sanitizer.php
CHANGED
@@ -1,35 +1,87 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
|
|
|
|
|
|
4 |
|
5 |
/**
|
|
|
|
|
|
|
|
|
6 |
* Converts <video> tags to <amp-video>
|
7 |
*/
|
8 |
class AMP_Video_Sanitizer extends AMP_Base_Sanitizer {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
const FALLBACK_HEIGHT = 400;
|
10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
public static $tag = 'video';
|
12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
private static $script_slug = 'amp-video';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
private static $script_src = 'https://cdn.ampproject.org/v0/amp-video-0.1.js';
|
15 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
public function get_scripts() {
|
17 |
if ( ! $this->did_convert_elements ) {
|
18 |
return array();
|
19 |
}
|
20 |
-
|
21 |
return array( self::$script_slug => self::$script_src );
|
22 |
}
|
23 |
|
|
|
|
|
|
|
|
|
|
|
24 |
public function sanitize() {
|
25 |
-
$nodes
|
26 |
$num_nodes = $nodes->length;
|
27 |
if ( 0 === $num_nodes ) {
|
28 |
return;
|
29 |
}
|
30 |
|
31 |
for ( $i = $num_nodes - 1; $i >= 0; $i-- ) {
|
32 |
-
$node
|
33 |
$old_attributes = AMP_DOM_Utils::get_node_attributes_as_assoc_array( $node );
|
34 |
|
35 |
$new_attributes = $this->filter_attributes( $old_attributes );
|
@@ -39,23 +91,43 @@ class AMP_Video_Sanitizer extends AMP_Base_Sanitizer {
|
|
39 |
|
40 |
$new_node = AMP_DOM_Utils::create_node( $this->dom, 'amp-video', $new_attributes );
|
41 |
|
42 |
-
// TODO: `source` does not have closing tag, and DOMDocument doesn't handle it well.
|
43 |
foreach ( $node->childNodes as $child_node ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
$new_child_node = $child_node->cloneNode( true );
|
|
|
|
|
|
|
|
|
45 |
$old_child_attributes = AMP_DOM_Utils::get_node_attributes_as_assoc_array( $new_child_node );
|
46 |
$new_child_attributes = $this->filter_attributes( $old_child_attributes );
|
47 |
|
48 |
-
|
49 |
-
|
50 |
-
|
|
|
|
|
51 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
}
|
53 |
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
|
|
|
|
59 |
if ( 0 === $new_node->childNodes->length && empty( $new_attributes['src'] ) ) {
|
60 |
$node->parentNode->removeChild( $node );
|
61 |
} else {
|
@@ -63,9 +135,30 @@ class AMP_Video_Sanitizer extends AMP_Base_Sanitizer {
|
|
63 |
}
|
64 |
|
65 |
$this->did_convert_elements = true;
|
|
|
66 |
}
|
67 |
}
|
68 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
private function filter_attributes( $attributes ) {
|
70 |
$out = array();
|
71 |
|
@@ -95,7 +188,7 @@ class AMP_Video_Sanitizer extends AMP_Base_Sanitizer {
|
|
95 |
}
|
96 |
break;
|
97 |
|
98 |
-
default
|
99 |
break;
|
100 |
}
|
101 |
}
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Video_Sanitizer.
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
|
8 |
/**
|
9 |
+
* Class AMP_Video_Sanitizer
|
10 |
+
*
|
11 |
+
* @since 0.2
|
12 |
+
*
|
13 |
* Converts <video> tags to <amp-video>
|
14 |
*/
|
15 |
class AMP_Video_Sanitizer extends AMP_Base_Sanitizer {
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Value used for height attribute when $attributes['height'] is empty.
|
19 |
+
*
|
20 |
+
* @since 0.2
|
21 |
+
*
|
22 |
+
* @const int
|
23 |
+
*/
|
24 |
const FALLBACK_HEIGHT = 400;
|
25 |
|
26 |
+
/**
|
27 |
+
* Tag.
|
28 |
+
*
|
29 |
+
* @var string HTML <video> tag to identify and replace with AMP version.
|
30 |
+
*
|
31 |
+
* @since 0.2
|
32 |
+
*/
|
33 |
public static $tag = 'video';
|
34 |
|
35 |
+
/**
|
36 |
+
* Script tag.
|
37 |
+
*
|
38 |
+
* @var string AMP HTML tag to use in place of HTML's <video> tag.
|
39 |
+
*
|
40 |
+
* @since 0.2
|
41 |
+
*/
|
42 |
private static $script_slug = 'amp-video';
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Script src.
|
46 |
+
*
|
47 |
+
* @var string URL to AMP Project's Video element's JavaScript file found at cdn.ampproject.org
|
48 |
+
*
|
49 |
+
* @since 0.2
|
50 |
+
*/
|
51 |
private static $script_src = 'https://cdn.ampproject.org/v0/amp-video-0.1.js';
|
52 |
|
53 |
+
/**
|
54 |
+
* Return one element array containing AMP HTML video tag and respective Javascript URL
|
55 |
+
*
|
56 |
+
* HTML tags and Javascript URLs found at cdn.ampproject.org
|
57 |
+
*
|
58 |
+
* @since 0.2
|
59 |
+
*
|
60 |
+
* @return string[] Returns AMP HTML video tag as array key and Javascript URL as array value,
|
61 |
+
* respectively. Will return an empty array if sanitization has yet to be run
|
62 |
+
* or if it did not find any HTML video elements to convert to AMP equivalents.
|
63 |
+
*/
|
64 |
public function get_scripts() {
|
65 |
if ( ! $this->did_convert_elements ) {
|
66 |
return array();
|
67 |
}
|
|
|
68 |
return array( self::$script_slug => self::$script_src );
|
69 |
}
|
70 |
|
71 |
+
/**
|
72 |
+
* Sanitize the <video> elements from the HTML contained in this instance's DOMDocument.
|
73 |
+
*
|
74 |
+
* @since 0.2
|
75 |
+
*/
|
76 |
public function sanitize() {
|
77 |
+
$nodes = $this->dom->getElementsByTagName( self::$tag );
|
78 |
$num_nodes = $nodes->length;
|
79 |
if ( 0 === $num_nodes ) {
|
80 |
return;
|
81 |
}
|
82 |
|
83 |
for ( $i = $num_nodes - 1; $i >= 0; $i-- ) {
|
84 |
+
$node = $nodes->item( $i );
|
85 |
$old_attributes = AMP_DOM_Utils::get_node_attributes_as_assoc_array( $node );
|
86 |
|
87 |
$new_attributes = $this->filter_attributes( $old_attributes );
|
91 |
|
92 |
$new_node = AMP_DOM_Utils::create_node( $this->dom, 'amp-video', $new_attributes );
|
93 |
|
|
|
94 |
foreach ( $node->childNodes as $child_node ) {
|
95 |
+
/**
|
96 |
+
* Child node.
|
97 |
+
*
|
98 |
+
* @todo: Fix when `source` has no closing tag as DOMDocument does not handle well.
|
99 |
+
*
|
100 |
+
* @var DOMNode $child_node
|
101 |
+
*/
|
102 |
$new_child_node = $child_node->cloneNode( true );
|
103 |
+
if ( ! $new_child_node instanceof DOMElement ) {
|
104 |
+
continue;
|
105 |
+
}
|
106 |
+
|
107 |
$old_child_attributes = AMP_DOM_Utils::get_node_attributes_as_assoc_array( $new_child_node );
|
108 |
$new_child_attributes = $this->filter_attributes( $old_child_attributes );
|
109 |
|
110 |
+
if ( empty( $new_child_attributes['src'] ) ) {
|
111 |
+
continue;
|
112 |
+
}
|
113 |
+
if ( 'source' !== $new_child_node->tagName ) {
|
114 |
+
continue;
|
115 |
}
|
116 |
+
|
117 |
+
/**
|
118 |
+
* Only append source tags with a valid src attribute
|
119 |
+
*/
|
120 |
+
$new_node->appendChild( $new_child_node );
|
121 |
+
|
122 |
}
|
123 |
|
124 |
+
/*
|
125 |
+
* If the node has at least one valid source, replace the old node with it.
|
126 |
+
* Otherwise, just remove the node.
|
127 |
+
*
|
128 |
+
* TODO: Add a fallback handler.
|
129 |
+
* See: https://github.com/ampproject/amphtml/issues/2261
|
130 |
+
*/
|
131 |
if ( 0 === $new_node->childNodes->length && empty( $new_attributes['src'] ) ) {
|
132 |
$node->parentNode->removeChild( $node );
|
133 |
} else {
|
135 |
}
|
136 |
|
137 |
$this->did_convert_elements = true;
|
138 |
+
|
139 |
}
|
140 |
}
|
141 |
|
142 |
+
/**
|
143 |
+
* "Filter" HTML attributes for <amp-audio> elements.
|
144 |
+
*
|
145 |
+
* @since 0.2
|
146 |
+
*
|
147 |
+
* @param string[] $attributes {
|
148 |
+
* Attributes.
|
149 |
+
*
|
150 |
+
* @type string $src Video URL - Empty if HTTPS required per $this->args['require_https_src']
|
151 |
+
* @type int $width <video> attribute - Set to numeric value if px or %
|
152 |
+
* @type int $height <video> attribute - Set to numeric value if px or %
|
153 |
+
* @type string $poster <video> attribute - Pass along if found
|
154 |
+
* @type string $class <video> attribute - Pass along if found
|
155 |
+
* @type bool $controls <video> attribute - Convert 'false' to empty string ''
|
156 |
+
* @type bool $loop <video> attribute - Convert 'false' to empty string ''
|
157 |
+
* @type bool $muted <video> attribute - Convert 'false' to empty string ''
|
158 |
+
* @type bool $autoplay <video> attribute - Convert 'false' to empty string ''
|
159 |
+
* }
|
160 |
+
* @return array Returns HTML attributes; removes any not specifically declared above from input.
|
161 |
+
*/
|
162 |
private function filter_attributes( $attributes ) {
|
163 |
$out = array();
|
164 |
|
188 |
}
|
189 |
break;
|
190 |
|
191 |
+
default:
|
192 |
break;
|
193 |
}
|
194 |
}
|
includes/settings/class-amp-customizer-design-settings.php
CHANGED
@@ -1,24 +1,84 @@
|
|
1 |
<?php
|
|
|
|
|
|
|
|
|
|
|
2 |
|
|
|
|
|
|
|
3 |
class AMP_Customizer_Design_Settings {
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
const DEFAULT_HEADER_COLOR = '#fff';
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
const DEFAULT_HEADER_BACKGROUND_COLOR = '#0a89c0';
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
const DEFAULT_COLOR_SCHEME = 'light';
|
7 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
public static function init() {
|
9 |
add_action( 'amp_customizer_init', array( __CLASS__, 'init_customizer' ) );
|
10 |
|
11 |
-
|
|
|
|
|
12 |
}
|
13 |
|
|
|
|
|
|
|
14 |
public static function init_customizer() {
|
15 |
-
|
16 |
-
|
17 |
-
|
|
|
|
|
18 |
}
|
19 |
|
|
|
|
|
|
|
|
|
|
|
20 |
public static function register_customizer_settings( $wp_customize ) {
|
21 |
-
|
|
|
22 |
$wp_customize->add_setting( 'amp_customizer[header_color]', array(
|
23 |
'type' => 'option',
|
24 |
'default' => self::DEFAULT_HEADER_COLOR,
|
@@ -26,7 +86,7 @@ class AMP_Customizer_Design_Settings {
|
|
26 |
'transport' => 'postMessage',
|
27 |
) );
|
28 |
|
29 |
-
// Header background color
|
30 |
$wp_customize->add_setting( 'amp_customizer[header_background_color]', array(
|
31 |
'type' => 'option',
|
32 |
'default' => self::DEFAULT_HEADER_BACKGROUND_COLOR,
|
@@ -34,15 +94,20 @@ class AMP_Customizer_Design_Settings {
|
|
34 |
'transport' => 'postMessage',
|
35 |
) );
|
36 |
|
37 |
-
// Background color scheme
|
38 |
$wp_customize->add_setting( 'amp_customizer[color_scheme]', array(
|
39 |
'type' => 'option',
|
40 |
'default' => self::DEFAULT_COLOR_SCHEME,
|
41 |
-
'sanitize_callback' => array( __CLASS__
|
42 |
'transport' => 'postMessage',
|
43 |
) );
|
44 |
}
|
45 |
|
|
|
|
|
|
|
|
|
|
|
46 |
public static function register_customizer_ui( $wp_customize ) {
|
47 |
$wp_customize->add_section( 'amp_design', array(
|
48 |
'title' => __( 'Design', 'amp' ),
|
@@ -52,7 +117,7 @@ class AMP_Customizer_Design_Settings {
|
|
52 |
// Header text color control.
|
53 |
$wp_customize->add_control(
|
54 |
new WP_Customize_Color_Control( $wp_customize, 'amp_header_color', array(
|
55 |
-
'settings'
|
56 |
'label' => __( 'Header Text Color', 'amp' ),
|
57 |
'section' => 'amp_design',
|
58 |
'priority' => 10,
|
@@ -62,14 +127,14 @@ class AMP_Customizer_Design_Settings {
|
|
62 |
// Header background color control.
|
63 |
$wp_customize->add_control(
|
64 |
new WP_Customize_Color_Control( $wp_customize, 'amp_header_background_color', array(
|
65 |
-
'settings'
|
66 |
'label' => __( 'Header Background & Link Color', 'amp' ),
|
67 |
'section' => 'amp_design',
|
68 |
'priority' => 20,
|
69 |
) )
|
70 |
);
|
71 |
|
72 |
-
// Background color scheme
|
73 |
$wp_customize->add_control( 'amp_color_scheme', array(
|
74 |
'settings' => 'amp_customizer[color_scheme]',
|
75 |
'label' => __( 'Color Scheme', 'amp' ),
|
@@ -77,22 +142,80 @@ class AMP_Customizer_Design_Settings {
|
|
77 |
'type' => 'radio',
|
78 |
'priority' => 30,
|
79 |
'choices' => self::get_color_scheme_names(),
|
80 |
-
));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
81 |
}
|
82 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
83 |
public static function enqueue_customizer_preview_scripts() {
|
|
|
|
|
84 |
wp_enqueue_script(
|
85 |
'amp-customizer-design-preview',
|
86 |
amp_get_asset_url( 'js/amp-customizer-design-preview.js' ),
|
87 |
-
array( 'amp-
|
88 |
false,
|
89 |
true
|
90 |
);
|
91 |
wp_localize_script( 'amp-customizer-design-preview', 'amp_customizer_design', array(
|
92 |
'color_schemes' => self::get_color_schemes(),
|
93 |
) );
|
|
|
|
|
|
|
|
|
|
|
|
|
94 |
}
|
95 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
public static function append_settings( $settings ) {
|
97 |
$settings = wp_parse_args( $settings, array(
|
98 |
'header_color' => self::DEFAULT_HEADER_COLOR,
|
@@ -107,6 +230,11 @@ class AMP_Customizer_Design_Settings {
|
|
107 |
) );
|
108 |
}
|
109 |
|
|
|
|
|
|
|
|
|
|
|
110 |
protected static function get_color_scheme_names() {
|
111 |
return array(
|
112 |
'light' => __( 'Light', 'amp' ),
|
@@ -114,17 +242,22 @@ class AMP_Customizer_Design_Settings {
|
|
114 |
);
|
115 |
}
|
116 |
|
|
|
|
|
|
|
|
|
|
|
117 |
protected static function get_color_schemes() {
|
118 |
return array(
|
119 |
'light' => array(
|
120 |
-
// Convert colors to greyscale for light theme color; see http://goo.gl/2gDLsp
|
121 |
'theme_color' => '#fff',
|
122 |
'text_color' => '#353535',
|
123 |
'muted_text_color' => '#696969',
|
124 |
'border_color' => '#c2c2c2',
|
125 |
),
|
126 |
'dark' => array(
|
127 |
-
// Convert and invert colors to greyscale for dark theme color; see http://goo.gl/uVB2cO
|
128 |
'theme_color' => '#0a0a0a',
|
129 |
'text_color' => '#dedede',
|
130 |
'muted_text_color' => '#b1b1b1',
|
@@ -133,6 +266,12 @@ class AMP_Customizer_Design_Settings {
|
|
133 |
);
|
134 |
}
|
135 |
|
|
|
|
|
|
|
|
|
|
|
|
|
136 |
protected static function get_colors_for_color_scheme( $scheme ) {
|
137 |
$color_schemes = self::get_color_schemes();
|
138 |
|
@@ -143,6 +282,12 @@ class AMP_Customizer_Design_Settings {
|
|
143 |
return $color_schemes[ self::DEFAULT_COLOR_SCHEME ];
|
144 |
}
|
145 |
|
|
|
|
|
|
|
|
|
|
|
|
|
146 |
public static function sanitize_color_scheme( $value ) {
|
147 |
$schemes = self::get_color_scheme_names();
|
148 |
$scheme_slugs = array_keys( $schemes );
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Customizer_Design_Settings
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
|
8 |
+
/**
|
9 |
+
* Class AMP_Customizer_Design_Settings
|
10 |
+
*/
|
11 |
class AMP_Customizer_Design_Settings {
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Default header color.
|
15 |
+
*
|
16 |
+
* @var string
|
17 |
+
*/
|
18 |
const DEFAULT_HEADER_COLOR = '#fff';
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Default header background color.
|
22 |
+
*
|
23 |
+
* @var string
|
24 |
+
*/
|
25 |
const DEFAULT_HEADER_BACKGROUND_COLOR = '#0a89c0';
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Default color scheme.
|
29 |
+
*
|
30 |
+
* @var string
|
31 |
+
*/
|
32 |
const DEFAULT_COLOR_SCHEME = 'light';
|
33 |
|
34 |
+
/**
|
35 |
+
* Returns whether the AMP design settings are enabled.
|
36 |
+
*
|
37 |
+
* @since 0.6
|
38 |
+
* @return bool AMP Customizer design settings enabled.
|
39 |
+
*/
|
40 |
+
public static function is_amp_customizer_enabled() {
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Filter whether to enable the AMP default template design settings.
|
44 |
+
*
|
45 |
+
* @since 0.4
|
46 |
+
* @since 0.6 This filter now controls whether or not the default settings, controls, and sections are registered for the Customizer. The AMP panel will be registered regardless.
|
47 |
+
* @param bool $enable Whether to enable the AMP default template design settings. Default true.
|
48 |
+
*/
|
49 |
+
return apply_filters( 'amp_customizer_is_enabled', true );
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Init.
|
54 |
+
*/
|
55 |
public static function init() {
|
56 |
add_action( 'amp_customizer_init', array( __CLASS__, 'init_customizer' ) );
|
57 |
|
58 |
+
if ( self::is_amp_customizer_enabled() ) {
|
59 |
+
add_filter( 'amp_customizer_get_settings', array( __CLASS__, 'append_settings' ) );
|
60 |
+
}
|
61 |
}
|
62 |
|
63 |
+
/**
|
64 |
+
* Init customizer.
|
65 |
+
*/
|
66 |
public static function init_customizer() {
|
67 |
+
if ( self::is_amp_customizer_enabled() ) {
|
68 |
+
add_action( 'amp_customizer_register_settings', array( __CLASS__, 'register_customizer_settings' ) );
|
69 |
+
add_action( 'amp_customizer_register_ui', array( __CLASS__, 'register_customizer_ui' ) );
|
70 |
+
add_action( 'amp_customizer_enqueue_preview_scripts', array( __CLASS__, 'enqueue_customizer_preview_scripts' ) );
|
71 |
+
}
|
72 |
}
|
73 |
|
74 |
+
/**
|
75 |
+
* Register default Customizer settings for AMP.
|
76 |
+
*
|
77 |
+
* @param WP_Customize_Manager $wp_customize Manager.
|
78 |
+
*/
|
79 |
public static function register_customizer_settings( $wp_customize ) {
|
80 |
+
|
81 |
+
// Header text color setting.
|
82 |
$wp_customize->add_setting( 'amp_customizer[header_color]', array(
|
83 |
'type' => 'option',
|
84 |
'default' => self::DEFAULT_HEADER_COLOR,
|
86 |
'transport' => 'postMessage',
|
87 |
) );
|
88 |
|
89 |
+
// Header background color.
|
90 |
$wp_customize->add_setting( 'amp_customizer[header_background_color]', array(
|
91 |
'type' => 'option',
|
92 |
'default' => self::DEFAULT_HEADER_BACKGROUND_COLOR,
|
94 |
'transport' => 'postMessage',
|
95 |
) );
|
96 |
|
97 |
+
// Background color scheme.
|
98 |
$wp_customize->add_setting( 'amp_customizer[color_scheme]', array(
|
99 |
'type' => 'option',
|
100 |
'default' => self::DEFAULT_COLOR_SCHEME,
|
101 |
+
'sanitize_callback' => array( __CLASS__, 'sanitize_color_scheme' ),
|
102 |
'transport' => 'postMessage',
|
103 |
) );
|
104 |
}
|
105 |
|
106 |
+
/**
|
107 |
+
* Register default Customizer sections and controls for AMP.
|
108 |
+
*
|
109 |
+
* @param WP_Customize_Manager $wp_customize Manager.
|
110 |
+
*/
|
111 |
public static function register_customizer_ui( $wp_customize ) {
|
112 |
$wp_customize->add_section( 'amp_design', array(
|
113 |
'title' => __( 'Design', 'amp' ),
|
117 |
// Header text color control.
|
118 |
$wp_customize->add_control(
|
119 |
new WP_Customize_Color_Control( $wp_customize, 'amp_header_color', array(
|
120 |
+
'settings' => 'amp_customizer[header_color]',
|
121 |
'label' => __( 'Header Text Color', 'amp' ),
|
122 |
'section' => 'amp_design',
|
123 |
'priority' => 10,
|
127 |
// Header background color control.
|
128 |
$wp_customize->add_control(
|
129 |
new WP_Customize_Color_Control( $wp_customize, 'amp_header_background_color', array(
|
130 |
+
'settings' => 'amp_customizer[header_background_color]',
|
131 |
'label' => __( 'Header Background & Link Color', 'amp' ),
|
132 |
'section' => 'amp_design',
|
133 |
'priority' => 20,
|
134 |
) )
|
135 |
);
|
136 |
|
137 |
+
// Background color scheme.
|
138 |
$wp_customize->add_control( 'amp_color_scheme', array(
|
139 |
'settings' => 'amp_customizer[color_scheme]',
|
140 |
'label' => __( 'Color Scheme', 'amp' ),
|
142 |
'type' => 'radio',
|
143 |
'priority' => 30,
|
144 |
'choices' => self::get_color_scheme_names(),
|
145 |
+
) );
|
146 |
+
|
147 |
+
// Header.
|
148 |
+
$wp_customize->selective_refresh->add_partial( 'amp-wp-header', array(
|
149 |
+
'selector' => '.amp-wp-header',
|
150 |
+
'settings' => array( 'blogname' ), // @todo Site Icon.
|
151 |
+
'render_callback' => array( __CLASS__, 'render_header_bar' ),
|
152 |
+
'fallback_refresh' => false,
|
153 |
+
) );
|
154 |
+
|
155 |
+
// Header.
|
156 |
+
$wp_customize->selective_refresh->add_partial( 'amp-wp-footer', array(
|
157 |
+
'selector' => '.amp-wp-footer',
|
158 |
+
'settings' => array( 'blogname' ),
|
159 |
+
'render_callback' => array( __CLASS__, 'render_footer' ),
|
160 |
+
'fallback_refresh' => false,
|
161 |
+
'container_inclusive' => true,
|
162 |
+
) );
|
163 |
+
}
|
164 |
+
|
165 |
+
/**
|
166 |
+
* Render header bar template.
|
167 |
+
*/
|
168 |
+
public static function render_header_bar() {
|
169 |
+
if ( is_singular() ) {
|
170 |
+
$post_template = new AMP_Post_Template( get_post() );
|
171 |
+
$post_template->load_parts( array( 'header-bar' ) );
|
172 |
+
}
|
173 |
}
|
174 |
|
175 |
+
/**
|
176 |
+
* Render footer template.
|
177 |
+
*/
|
178 |
+
public static function render_footer() {
|
179 |
+
if ( is_singular() ) {
|
180 |
+
$post_template = new AMP_Post_Template( get_post() );
|
181 |
+
$post_template->load_parts( array( 'footer' ) );
|
182 |
+
}
|
183 |
+
}
|
184 |
+
|
185 |
+
/**
|
186 |
+
* Enqueue scripts for default AMP Customizer preview.
|
187 |
+
*
|
188 |
+
* @global WP_Customize_Manager $wp_customize
|
189 |
+
*/
|
190 |
public static function enqueue_customizer_preview_scripts() {
|
191 |
+
global $wp_customize;
|
192 |
+
|
193 |
wp_enqueue_script(
|
194 |
'amp-customizer-design-preview',
|
195 |
amp_get_asset_url( 'js/amp-customizer-design-preview.js' ),
|
196 |
+
array( 'amp-customize-preview' ),
|
197 |
false,
|
198 |
true
|
199 |
);
|
200 |
wp_localize_script( 'amp-customizer-design-preview', 'amp_customizer_design', array(
|
201 |
'color_schemes' => self::get_color_schemes(),
|
202 |
) );
|
203 |
+
|
204 |
+
// Prevent a theme's registered blogname partial from causing full page refreshes.
|
205 |
+
$blogname_partial = $wp_customize->selective_refresh->get_partial( 'blogname' );
|
206 |
+
if ( $blogname_partial ) {
|
207 |
+
$blogname_partial->fallback_refresh = false;
|
208 |
+
}
|
209 |
}
|
210 |
|
211 |
+
/**
|
212 |
+
* Merge default Customizer settings on top of settings for merging into AMP post template.
|
213 |
+
*
|
214 |
+
* @see AMP_Post_Template::build_customizer_settings()
|
215 |
+
*
|
216 |
+
* @param array $settings Settings.
|
217 |
+
* @return array Merged settings.
|
218 |
+
*/
|
219 |
public static function append_settings( $settings ) {
|
220 |
$settings = wp_parse_args( $settings, array(
|
221 |
'header_color' => self::DEFAULT_HEADER_COLOR,
|
230 |
) );
|
231 |
}
|
232 |
|
233 |
+
/**
|
234 |
+
* Get color scheme names.
|
235 |
+
*
|
236 |
+
* @return array Color scheme names.
|
237 |
+
*/
|
238 |
protected static function get_color_scheme_names() {
|
239 |
return array(
|
240 |
'light' => __( 'Light', 'amp' ),
|
242 |
);
|
243 |
}
|
244 |
|
245 |
+
/**
|
246 |
+
* Get color schemes.
|
247 |
+
*
|
248 |
+
* @return array Color schemes.
|
249 |
+
*/
|
250 |
protected static function get_color_schemes() {
|
251 |
return array(
|
252 |
'light' => array(
|
253 |
+
// Convert colors to greyscale for light theme color; see <http://goo.gl/2gDLsp>.
|
254 |
'theme_color' => '#fff',
|
255 |
'text_color' => '#353535',
|
256 |
'muted_text_color' => '#696969',
|
257 |
'border_color' => '#c2c2c2',
|
258 |
),
|
259 |
'dark' => array(
|
260 |
+
// Convert and invert colors to greyscale for dark theme color; see <http://goo.gl/uVB2cO>.
|
261 |
'theme_color' => '#0a0a0a',
|
262 |
'text_color' => '#dedede',
|
263 |
'muted_text_color' => '#b1b1b1',
|
266 |
);
|
267 |
}
|
268 |
|
269 |
+
/**
|
270 |
+
* Get colors for color scheme.
|
271 |
+
*
|
272 |
+
* @param string $scheme Color scheme.
|
273 |
+
* @return array Colors.
|
274 |
+
*/
|
275 |
protected static function get_colors_for_color_scheme( $scheme ) {
|
276 |
$color_schemes = self::get_color_schemes();
|
277 |
|
282 |
return $color_schemes[ self::DEFAULT_COLOR_SCHEME ];
|
283 |
}
|
284 |
|
285 |
+
/**
|
286 |
+
* Sanitize color scheme.
|
287 |
+
*
|
288 |
+
* @param string $value Color scheme name.
|
289 |
+
* @return string Sanitized name.
|
290 |
+
*/
|
291 |
public static function sanitize_color_scheme( $value ) {
|
292 |
$schemes = self::get_color_scheme_names();
|
293 |
$scheme_slugs = array_keys( $schemes );
|
includes/templates/class-amp-content-sanitizer.php
ADDED
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Content_Sanitizer
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class AMP_Content_Sanitizer
|
10 |
+
*/
|
11 |
+
class AMP_Content_Sanitizer {
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Sanitize.
|
15 |
+
*
|
16 |
+
* @param string $content Content.
|
17 |
+
* @param string[] $sanitizer_classes Sanitizer classes.
|
18 |
+
* @param array $global_args Global args.
|
19 |
+
*
|
20 |
+
* @return array
|
21 |
+
*/
|
22 |
+
public static function sanitize( $content, array $sanitizer_classes, $global_args = array() ) {
|
23 |
+
$scripts = array();
|
24 |
+
$styles = array();
|
25 |
+
$dom = AMP_DOM_Utils::get_dom_from_content( $content );
|
26 |
+
|
27 |
+
foreach ( $sanitizer_classes as $sanitizer_class => $args ) {
|
28 |
+
if ( ! class_exists( $sanitizer_class ) ) {
|
29 |
+
/* translators: %s is sanitizer class */
|
30 |
+
_doing_it_wrong( __METHOD__, sprintf( esc_html__( 'Sanitizer (%s) class does not exist', 'amp' ), esc_html( $sanitizer_class ) ), '0.4.1' );
|
31 |
+
continue;
|
32 |
+
}
|
33 |
+
|
34 |
+
$sanitizer = new $sanitizer_class( $dom, array_merge( $global_args, $args ) );
|
35 |
+
|
36 |
+
if ( ! is_subclass_of( $sanitizer, 'AMP_Base_Sanitizer' ) ) {
|
37 |
+
/* translators: %s is sanitizer class */
|
38 |
+
_doing_it_wrong( __METHOD__, sprintf( esc_html__( 'Sanitizer (%s) must extend `AMP_Base_Sanitizer`', 'amp' ), esc_html( $sanitizer_class ) ), '0.1' );
|
39 |
+
continue;
|
40 |
+
}
|
41 |
+
|
42 |
+
$sanitizer->sanitize();
|
43 |
+
|
44 |
+
$scripts = array_merge( $scripts, $sanitizer->get_scripts() );
|
45 |
+
$styles = array_merge( $styles, $sanitizer->get_styles() );
|
46 |
+
}
|
47 |
+
|
48 |
+
$sanitized_content = AMP_DOM_Utils::get_content_from_dom( $dom );
|
49 |
+
|
50 |
+
return array( $sanitized_content, $scripts, $styles );
|
51 |
+
}
|
52 |
+
}
|
53 |
+
|
includes/{class-amp-content.php → templates/class-amp-content.php}
RENAMED
@@ -1,61 +1,148 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
|
|
|
|
|
|
|
|
7 |
class AMP_Content {
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
private $content;
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
private $amp_content = '';
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
private $amp_scripts = array();
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
private $amp_styles = array();
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
private $args = array();
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
private $embed_handler_classes = array();
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
private $sanitizer_classes = array();
|
15 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
public function __construct( $content, $embed_handler_classes, $sanitizer_classes, $args = array() ) {
|
17 |
-
$this->content
|
18 |
-
$this->args
|
19 |
$this->embed_handler_classes = $embed_handler_classes;
|
20 |
-
$this->sanitizer_classes
|
21 |
|
22 |
$this->transform();
|
23 |
}
|
24 |
|
|
|
|
|
|
|
|
|
|
|
25 |
public function get_amp_content() {
|
26 |
return $this->amp_content;
|
27 |
}
|
28 |
|
|
|
|
|
|
|
|
|
|
|
29 |
public function get_amp_scripts() {
|
30 |
return $this->amp_scripts;
|
31 |
}
|
32 |
|
|
|
|
|
|
|
|
|
|
|
33 |
public function get_amp_styles() {
|
34 |
return $this->amp_styles;
|
35 |
}
|
36 |
|
|
|
|
|
|
|
37 |
private function transform() {
|
38 |
$content = $this->content;
|
39 |
|
40 |
-
// First, embeds + the_content filter
|
41 |
$embed_handlers = $this->register_embed_handlers();
|
42 |
-
$content
|
43 |
$this->unregister_embed_handlers( $embed_handlers );
|
44 |
|
45 |
-
// Then, sanitize to strip and/or convert non-amp content
|
46 |
$content = $this->sanitize( $content );
|
47 |
|
48 |
$this->amp_content = $content;
|
49 |
}
|
50 |
|
|
|
|
|
|
|
|
|
|
|
51 |
private function add_scripts( $scripts ) {
|
52 |
$this->amp_scripts = array_merge( $this->amp_scripts, $scripts );
|
53 |
}
|
54 |
|
|
|
|
|
|
|
|
|
|
|
55 |
private function add_styles( $styles ) {
|
56 |
$this->amp_styles = array_merge( $this->amp_styles, $styles );
|
57 |
}
|
58 |
|
|
|
|
|
|
|
|
|
|
|
59 |
private function register_embed_handlers() {
|
60 |
$embed_handlers = array();
|
61 |
|
@@ -63,7 +150,8 @@ class AMP_Content {
|
|
63 |
$embed_handler = new $embed_handler_class( array_merge( $this->args, $args ) );
|
64 |
|
65 |
if ( ! is_subclass_of( $embed_handler, 'AMP_Base_Embed_Handler' ) ) {
|
66 |
-
|
|
|
67 |
continue;
|
68 |
}
|
69 |
|
@@ -74,13 +162,25 @@ class AMP_Content {
|
|
74 |
return $embed_handlers;
|
75 |
}
|
76 |
|
|
|
|
|
|
|
|
|
|
|
77 |
private function unregister_embed_handlers( $embed_handlers ) {
|
78 |
foreach ( $embed_handlers as $embed_handler ) {
|
79 |
-
|
80 |
-
|
81 |
}
|
82 |
}
|
83 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
private function sanitize( $content ) {
|
85 |
list( $sanitized_content, $scripts, $styles ) = AMP_Content_Sanitizer::sanitize( $content, $this->sanitizer_classes, $this->args );
|
86 |
|
@@ -90,34 +190,3 @@ class AMP_Content {
|
|
90 |
return $sanitized_content;
|
91 |
}
|
92 |
}
|
93 |
-
|
94 |
-
class AMP_Content_Sanitizer {
|
95 |
-
public static function sanitize( $content, $sanitizer_classes, $global_args = array() ) {
|
96 |
-
$scripts = array();
|
97 |
-
$styles = array();
|
98 |
-
$dom = AMP_DOM_Utils::get_dom_from_content( $content );
|
99 |
-
|
100 |
-
foreach ( $sanitizer_classes as $sanitizer_class => $args ) {
|
101 |
-
if ( ! class_exists( $sanitizer_class ) ) {
|
102 |
-
_doing_it_wrong( __METHOD__, sprintf( esc_html__( 'Sanitizer (%s) class does not exist', 'amp' ), esc_html( $sanitizer_class ) ), '0.4.1' );
|
103 |
-
continue;
|
104 |
-
}
|
105 |
-
|
106 |
-
$sanitizer = new $sanitizer_class( $dom, array_merge( $global_args, $args ) );
|
107 |
-
|
108 |
-
if ( ! is_subclass_of( $sanitizer, 'AMP_Base_Sanitizer' ) ) {
|
109 |
-
_doing_it_wrong( __METHOD__, sprintf( esc_html__( 'Sanitizer (%s) must extend `AMP_Base_Sanitizer`', 'amp' ), esc_html( $sanitizer_class ) ), '0.1' );
|
110 |
-
continue;
|
111 |
-
}
|
112 |
-
|
113 |
-
$sanitizer->sanitize();
|
114 |
-
|
115 |
-
$scripts = array_merge( $scripts, $sanitizer->get_scripts() );
|
116 |
-
$styles = array_merge( $styles, $sanitizer->get_styles() );
|
117 |
-
}
|
118 |
-
|
119 |
-
$sanitized_content = AMP_DOM_Utils::get_content_from_dom( $dom );
|
120 |
-
|
121 |
-
return array( $sanitized_content, $scripts, $styles );
|
122 |
-
}
|
123 |
-
}
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_Content
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class AMP_Content
|
10 |
+
*/
|
11 |
class AMP_Content {
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Content.
|
15 |
+
*
|
16 |
+
* @var string
|
17 |
+
*/
|
18 |
private $content;
|
19 |
+
|
20 |
+
/**
|
21 |
+
* AMP content.
|
22 |
+
*
|
23 |
+
* @var string
|
24 |
+
*/
|
25 |
private $amp_content = '';
|
26 |
+
|
27 |
+
/**
|
28 |
+
* AMP scripts.
|
29 |
+
*
|
30 |
+
* @var array
|
31 |
+
*/
|
32 |
private $amp_scripts = array();
|
33 |
+
|
34 |
+
/**
|
35 |
+
* AMP styles.
|
36 |
+
*
|
37 |
+
* @var array
|
38 |
+
*/
|
39 |
private $amp_styles = array();
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Args.
|
43 |
+
*
|
44 |
+
* @var array
|
45 |
+
*/
|
46 |
private $args = array();
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Embed handler class names.
|
50 |
+
*
|
51 |
+
* @var string[]
|
52 |
+
*/
|
53 |
private $embed_handler_classes = array();
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Sanitizer class names.
|
57 |
+
*
|
58 |
+
* @var string[]
|
59 |
+
*/
|
60 |
private $sanitizer_classes = array();
|
61 |
|
62 |
+
/**
|
63 |
+
* AMP_Content constructor.
|
64 |
+
*
|
65 |
+
* @param string $content Content.
|
66 |
+
* @param string[] $embed_handler_classes Embed handler class names.
|
67 |
+
* @param string[] $sanitizer_classes Sanitizer class names.
|
68 |
+
* @param array $args Args.
|
69 |
+
*/
|
70 |
public function __construct( $content, $embed_handler_classes, $sanitizer_classes, $args = array() ) {
|
71 |
+
$this->content = $content;
|
72 |
+
$this->args = $args;
|
73 |
$this->embed_handler_classes = $embed_handler_classes;
|
74 |
+
$this->sanitizer_classes = $sanitizer_classes;
|
75 |
|
76 |
$this->transform();
|
77 |
}
|
78 |
|
79 |
+
/**
|
80 |
+
* Get AMP content.
|
81 |
+
*
|
82 |
+
* @return string
|
83 |
+
*/
|
84 |
public function get_amp_content() {
|
85 |
return $this->amp_content;
|
86 |
}
|
87 |
|
88 |
+
/**
|
89 |
+
* Get AMP scripts.
|
90 |
+
*
|
91 |
+
* @return array
|
92 |
+
*/
|
93 |
public function get_amp_scripts() {
|
94 |
return $this->amp_scripts;
|
95 |
}
|
96 |
|
97 |
+
/**
|
98 |
+
* Get AMP styles.
|
99 |
+
*
|
100 |
+
* @return array
|
101 |
+
*/
|
102 |
public function get_amp_styles() {
|
103 |
return $this->amp_styles;
|
104 |
}
|
105 |
|
106 |
+
/**
|
107 |
+
* Transform.
|
108 |
+
*/
|
109 |
private function transform() {
|
110 |
$content = $this->content;
|
111 |
|
112 |
+
// First, embeds + the_content filter.
|
113 |
$embed_handlers = $this->register_embed_handlers();
|
114 |
+
$content = apply_filters( 'the_content', $content );
|
115 |
$this->unregister_embed_handlers( $embed_handlers );
|
116 |
|
117 |
+
// Then, sanitize to strip and/or convert non-amp content.
|
118 |
$content = $this->sanitize( $content );
|
119 |
|
120 |
$this->amp_content = $content;
|
121 |
}
|
122 |
|
123 |
+
/**
|
124 |
+
* Add scripts.
|
125 |
+
*
|
126 |
+
* @param array $scripts Scripts.
|
127 |
+
*/
|
128 |
private function add_scripts( $scripts ) {
|
129 |
$this->amp_scripts = array_merge( $this->amp_scripts, $scripts );
|
130 |
}
|
131 |
|
132 |
+
/**
|
133 |
+
* Add styles.
|
134 |
+
*
|
135 |
+
* @param array $styles Styles.
|
136 |
+
*/
|
137 |
private function add_styles( $styles ) {
|
138 |
$this->amp_styles = array_merge( $this->amp_styles, $styles );
|
139 |
}
|
140 |
|
141 |
+
/**
|
142 |
+
* Register embed handlers.
|
143 |
+
*
|
144 |
+
* @return array
|
145 |
+
*/
|
146 |
private function register_embed_handlers() {
|
147 |
$embed_handlers = array();
|
148 |
|
150 |
$embed_handler = new $embed_handler_class( array_merge( $this->args, $args ) );
|
151 |
|
152 |
if ( ! is_subclass_of( $embed_handler, 'AMP_Base_Embed_Handler' ) ) {
|
153 |
+
/* translators: %s is embed handler */
|
154 |
+
_doing_it_wrong( __METHOD__, esc_html( sprintf( __( 'Embed Handler (%s) must extend `AMP_Embed_Handler`', 'amp' ), $embed_handler_class ) ), '0.1' );
|
155 |
continue;
|
156 |
}
|
157 |
|
162 |
return $embed_handlers;
|
163 |
}
|
164 |
|
165 |
+
/**
|
166 |
+
* Unregister embed handlers.
|
167 |
+
*
|
168 |
+
* @param array $embed_handlers Embed handlers.
|
169 |
+
*/
|
170 |
private function unregister_embed_handlers( $embed_handlers ) {
|
171 |
foreach ( $embed_handlers as $embed_handler ) {
|
172 |
+
$this->add_scripts( $embed_handler->get_scripts() );
|
173 |
+
$embed_handler->unregister_embed();
|
174 |
}
|
175 |
}
|
176 |
|
177 |
+
/**
|
178 |
+
* Sanitize.
|
179 |
+
*
|
180 |
+
* @see AMP_Content_Sanitizer::sanitize()
|
181 |
+
* @param string $content Content.
|
182 |
+
* @return array Sanitized content.
|
183 |
+
*/
|
184 |
private function sanitize( $content ) {
|
185 |
list( $sanitized_content, $scripts, $styles ) = AMP_Content_Sanitizer::sanitize( $content, $this->sanitizer_classes, $this->args );
|
186 |
|
190 |
return $sanitized_content;
|
191 |
}
|
192 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
includes/{class-amp-post-template.php → templates/class-amp-post-template.php}
RENAMED
@@ -1,48 +1,100 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-img-sanitizer.php' );
|
14 |
-
require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-video-sanitizer.php' );
|
15 |
-
require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-iframe-sanitizer.php' );
|
16 |
-
require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-audio-sanitizer.php' );
|
17 |
-
require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-playbuzz-sanitizer.php' );
|
18 |
-
|
19 |
-
require_once( AMP__DIR__ . '/includes/embeds/class-amp-twitter-embed.php' );
|
20 |
-
require_once( AMP__DIR__ . '/includes/embeds/class-amp-youtube-embed.php' );
|
21 |
-
require_once( AMP__DIR__ . '/includes/embeds/class-amp-dailymotion-embed.php' );
|
22 |
-
require_once( AMP__DIR__ . '/includes/embeds/class-amp-vimeo-embed.php' );
|
23 |
-
require_once( AMP__DIR__ . '/includes/embeds/class-amp-soundcloud-embed.php' );
|
24 |
-
require_once( AMP__DIR__ . '/includes/embeds/class-amp-gallery-embed.php' );
|
25 |
-
require_once( AMP__DIR__ . '/includes/embeds/class-amp-instagram-embed.php' );
|
26 |
-
require_once( AMP__DIR__ . '/includes/embeds/class-amp-vine-embed.php' );
|
27 |
-
require_once( AMP__DIR__ . '/includes/embeds/class-amp-facebook-embed.php' );
|
28 |
-
require_once( AMP__DIR__ . '/includes/embeds/class-amp-pinterest-embed.php' );
|
29 |
-
|
30 |
class AMP_Post_Template {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
const SITE_ICON_SIZE = 32;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
const CONTENT_MAX_WIDTH = 600;
|
33 |
|
34 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
const DEFAULT_NAVBAR_BACKGROUND = '#0a89c0';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
const DEFAULT_NAVBAR_COLOR = '#fff';
|
37 |
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
private $template_dir;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
private $data;
|
40 |
|
41 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
$this->template_dir = apply_filters( 'amp_post_template_dir', AMP__DIR__ . '/templates' );
|
43 |
|
44 |
-
$
|
45 |
-
|
|
|
|
|
|
|
|
|
46 |
|
47 |
$content_max_width = self::CONTENT_MAX_WIDTH;
|
48 |
if ( isset( $GLOBALS['content_width'] ) && $GLOBALS['content_width'] > 0 ) {
|
@@ -51,33 +103,33 @@ class AMP_Post_Template {
|
|
51 |
$content_max_width = apply_filters( 'amp_content_max_width', $content_max_width );
|
52 |
|
53 |
$this->data = array(
|
54 |
-
'content_max_width'
|
55 |
|
56 |
-
'document_title'
|
57 |
-
'canonical_url'
|
58 |
-
'home_url'
|
59 |
-
'blog_name'
|
60 |
|
61 |
-
'html_tag_attributes'
|
62 |
-
'body_class'
|
63 |
|
64 |
-
'site_icon_url'
|
65 |
'placeholder_image_url' => amp_get_asset_url( 'images/placeholder-icon.png' ),
|
66 |
|
67 |
-
'featured_image'
|
68 |
-
'comments_link_url'
|
69 |
-
'comments_link_text'
|
70 |
|
71 |
-
'amp_runtime_script'
|
72 |
'amp_component_scripts' => array(),
|
73 |
|
74 |
-
'customizer_settings'
|
75 |
|
76 |
-
'font_urls'
|
77 |
'merriweather' => 'https://fonts.googleapis.com/css?family=Merriweather:400,400italic,700,700italic',
|
78 |
),
|
79 |
|
80 |
-
'post_amp_styles'
|
81 |
|
82 |
/**
|
83 |
* Add amp-analytics tags.
|
@@ -85,31 +137,55 @@ class AMP_Post_Template {
|
|
85 |
* This filter allows you to easily insert any amp-analytics tags without needing much heavy lifting.
|
86 |
*
|
87 |
* @since 0.4
|
88 |
-
|
89 |
-
* @param
|
90 |
-
* @param
|
91 |
*/
|
92 |
-
'amp_analytics'
|
93 |
-
|
94 |
|
95 |
$this->build_post_content();
|
96 |
$this->build_post_data();
|
97 |
$this->build_customizer_settings();
|
98 |
$this->build_html_tag_attributes();
|
99 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
$this->data = apply_filters( 'amp_post_template_data', $this->data, $this->post );
|
101 |
}
|
102 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
public function get( $property, $default = null ) {
|
104 |
if ( isset( $this->data[ $property ] ) ) {
|
105 |
return $this->data[ $property ];
|
106 |
} else {
|
107 |
-
|
|
|
108 |
}
|
109 |
|
110 |
return $default;
|
111 |
}
|
112 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
public function get_customizer_setting( $name, $default = null ) {
|
114 |
$settings = $this->get( 'customizer_settings' );
|
115 |
if ( ! empty( $settings[ $name ] ) ) {
|
@@ -119,10 +195,20 @@ class AMP_Post_Template {
|
|
119 |
return $default;
|
120 |
}
|
121 |
|
|
|
|
|
|
|
122 |
public function load() {
|
123 |
-
$
|
|
|
|
|
124 |
}
|
125 |
|
|
|
|
|
|
|
|
|
|
|
126 |
public function load_parts( $templates ) {
|
127 |
foreach ( $templates as $template ) {
|
128 |
$file = $this->get_template_path( $template );
|
@@ -130,18 +216,41 @@ class AMP_Post_Template {
|
|
130 |
}
|
131 |
}
|
132 |
|
|
|
|
|
|
|
|
|
|
|
|
|
133 |
private function get_template_path( $template ) {
|
134 |
return sprintf( '%s/%s.php', $this->template_dir, $template );
|
135 |
}
|
136 |
|
|
|
|
|
|
|
|
|
|
|
137 |
private function add_data( $data ) {
|
138 |
$this->data = array_merge( $this->data, $data );
|
139 |
}
|
140 |
|
|
|
|
|
|
|
|
|
|
|
|
|
141 |
private function add_data_by_key( $key, $value ) {
|
142 |
$this->data[ $key ] = $value;
|
143 |
}
|
144 |
|
|
|
|
|
|
|
|
|
|
|
|
|
145 |
private function merge_data_for_key( $key, $value ) {
|
146 |
if ( is_array( $this->data[ $key ] ) ) {
|
147 |
$this->data[ $key ] = array_merge( $this->data[ $key ], $value );
|
@@ -150,45 +259,54 @@ class AMP_Post_Template {
|
|
150 |
}
|
151 |
}
|
152 |
|
|
|
|
|
|
|
|
|
|
|
153 |
private function build_post_data() {
|
154 |
-
$post_title
|
155 |
-
$post_publish_timestamp
|
156 |
$post_modified_timestamp = get_post_modified_time( 'U', false, $this->post );
|
157 |
-
$post_author
|
158 |
|
159 |
-
$this->add_data(
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
|
|
|
|
167 |
|
168 |
$metadata = array(
|
169 |
-
'@context'
|
170 |
-
'@type'
|
171 |
'mainEntityOfPage' => $this->get( 'canonical_url' ),
|
172 |
-
'publisher'
|
173 |
'@type' => 'Organization',
|
174 |
-
'name'
|
175 |
-
),
|
176 |
-
'headline' => $post_title,
|
177 |
-
'datePublished' => date( 'c', $post_publish_timestamp ),
|
178 |
-
'dateModified' => date( 'c', $post_modified_timestamp ),
|
179 |
-
'author' => array(
|
180 |
-
'@type' => 'Person',
|
181 |
-
'name' => $post_author->display_name,
|
182 |
),
|
|
|
|
|
|
|
183 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
184 |
|
185 |
$site_icon_url = $this->get( 'site_icon_url' );
|
186 |
if ( $site_icon_url ) {
|
187 |
$metadata['publisher']['logo'] = array(
|
188 |
-
'@type'
|
189 |
-
'url'
|
190 |
'height' => self::SITE_ICON_SIZE,
|
191 |
-
'width'
|
192 |
);
|
193 |
}
|
194 |
|
@@ -203,6 +321,9 @@ class AMP_Post_Template {
|
|
203 |
$this->build_post_commments_data();
|
204 |
}
|
205 |
|
|
|
|
|
|
|
206 |
private function build_post_commments_data() {
|
207 |
if ( ! post_type_supports( $this->post->post_type, 'comments' ) ) {
|
208 |
return;
|
@@ -210,49 +331,59 @@ class AMP_Post_Template {
|
|
210 |
|
211 |
$comments_open = comments_open( $this->ID );
|
212 |
|
213 |
-
// Don't show link if close and no comments
|
214 |
if ( ! $comments_open
|
215 |
&& ! $this->post->comment_count ) {
|
216 |
return;
|
217 |
}
|
218 |
|
219 |
-
$comments_link_url
|
220 |
$comments_link_text = $comments_open
|
221 |
? __( 'Leave a Comment', 'amp' )
|
222 |
: __( 'View Comments', 'amp' );
|
223 |
|
224 |
-
$this->add_data(
|
225 |
-
|
226 |
-
|
227 |
-
|
|
|
|
|
228 |
}
|
229 |
|
|
|
|
|
|
|
230 |
private function build_post_content() {
|
231 |
-
$amp_content = new AMP_Content(
|
232 |
-
|
233 |
-
|
234 |
-
'
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
|
|
|
|
|
|
|
|
|
|
256 |
array(
|
257 |
'content_max_width' => $this->get( 'content_max_width' ),
|
258 |
)
|
@@ -263,8 +394,11 @@ class AMP_Post_Template {
|
|
263 |
$this->merge_data_for_key( 'post_amp_styles', $amp_content->get_amp_styles() );
|
264 |
}
|
265 |
|
|
|
|
|
|
|
266 |
private function build_post_featured_image() {
|
267 |
-
$post_id
|
268 |
$featured_html = get_the_post_thumbnail( $post_id, 'large' );
|
269 |
|
270 |
// Skip featured image if no featured image is available.
|
@@ -293,10 +427,12 @@ class AMP_Post_Template {
|
|
293 |
)
|
294 |
);
|
295 |
|
296 |
-
$this->add_data_by_key(
|
297 |
-
'
|
298 |
-
|
299 |
-
|
|
|
|
|
300 |
|
301 |
if ( $featured_scripts ) {
|
302 |
$this->merge_data_for_key( 'amp_component_scripts', $featured_scripts );
|
@@ -307,6 +443,9 @@ class AMP_Post_Template {
|
|
307 |
}
|
308 |
}
|
309 |
|
|
|
|
|
|
|
310 |
private function build_customizer_settings() {
|
311 |
$settings = AMP_Customizer_Settings::get_settings();
|
312 |
|
@@ -334,21 +473,23 @@ class AMP_Post_Template {
|
|
334 |
*/
|
335 |
private function get_post_image_metadata() {
|
336 |
$post_image_meta = null;
|
337 |
-
$post_image_id
|
338 |
|
339 |
if ( has_post_thumbnail( $this->ID ) ) {
|
340 |
$post_image_id = get_post_thumbnail_id( $this->ID );
|
341 |
} else {
|
342 |
-
$attached_image_ids = get_posts(
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
|
|
|
|
352 |
|
353 |
if ( ! empty( $attached_image_ids ) ) {
|
354 |
$post_image_id = array_shift( $attached_image_ids );
|
@@ -363,9 +504,9 @@ class AMP_Post_Template {
|
|
363 |
|
364 |
if ( is_array( $post_image_src ) ) {
|
365 |
$post_image_meta = array(
|
366 |
-
'@type'
|
367 |
-
'url'
|
368 |
-
'width'
|
369 |
'height' => $post_image_src[2],
|
370 |
);
|
371 |
}
|
@@ -373,6 +514,9 @@ class AMP_Post_Template {
|
|
373 |
return $post_image_meta;
|
374 |
}
|
375 |
|
|
|
|
|
|
|
376 |
private function build_html_tag_attributes() {
|
377 |
$attributes = array();
|
378 |
|
@@ -388,6 +532,12 @@ class AMP_Post_Template {
|
|
388 |
$this->add_data_by_key( 'html_tag_attributes', $attributes );
|
389 |
}
|
390 |
|
|
|
|
|
|
|
|
|
|
|
|
|
391 |
private function verify_and_include( $file, $template_type ) {
|
392 |
$located_file = $this->locate_template( $file );
|
393 |
if ( $located_file ) {
|
@@ -396,20 +546,32 @@ class AMP_Post_Template {
|
|
396 |
|
397 |
$file = apply_filters( 'amp_post_template_file', $file, $template_type, $this->post );
|
398 |
if ( ! $this->is_valid_template( $file ) ) {
|
399 |
-
|
|
|
400 |
return;
|
401 |
}
|
402 |
|
403 |
do_action( 'amp_post_template_include_' . $template_type, $this );
|
404 |
-
include
|
405 |
}
|
406 |
|
407 |
-
|
|
|
|
|
|
|
|
|
|
|
408 |
private function locate_template( $file ) {
|
409 |
$search_file = sprintf( 'amp/%s', basename( $file ) );
|
410 |
return locate_template( array( $search_file ), false );
|
411 |
}
|
412 |
|
|
|
|
|
|
|
|
|
|
|
|
|
413 |
private function is_valid_template( $template ) {
|
414 |
if ( false !== strpos( $template, '..' ) ) {
|
415 |
return false;
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* AMP_Post_Template class.
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class AMP_Post_Template
|
10 |
+
*
|
11 |
+
* @since 0.2
|
12 |
+
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
class AMP_Post_Template {
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Site icon size.
|
17 |
+
*
|
18 |
+
* @since 0.2
|
19 |
+
* @var int
|
20 |
+
*/
|
21 |
const SITE_ICON_SIZE = 32;
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Content max width.
|
25 |
+
*
|
26 |
+
* @since 0.4
|
27 |
+
* @var int
|
28 |
+
*/
|
29 |
const CONTENT_MAX_WIDTH = 600;
|
30 |
|
31 |
+
/**
|
32 |
+
* Default navbar background.
|
33 |
+
*
|
34 |
+
* Needed for 0.3 back-compat
|
35 |
+
*
|
36 |
+
* @since 0.4
|
37 |
+
* @var string
|
38 |
+
*/
|
39 |
const DEFAULT_NAVBAR_BACKGROUND = '#0a89c0';
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Default navbar color.
|
43 |
+
*
|
44 |
+
* Needed for 0.3 back-compat
|
45 |
+
*
|
46 |
+
* @since 0.4
|
47 |
+
* @var string
|
48 |
+
*/
|
49 |
const DEFAULT_NAVBAR_COLOR = '#fff';
|
50 |
|
51 |
+
/**
|
52 |
+
* Template directory.
|
53 |
+
*
|
54 |
+
* @since 0.2
|
55 |
+
* @var string
|
56 |
+
*/
|
57 |
private $template_dir;
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Post template data.
|
61 |
+
*
|
62 |
+
* @since 0.2
|
63 |
+
* @var array
|
64 |
+
*/
|
65 |
private $data;
|
66 |
|
67 |
+
/**
|
68 |
+
* Post ID.
|
69 |
+
*
|
70 |
+
* @since 0.2
|
71 |
+
* @var int
|
72 |
+
*/
|
73 |
+
public $ID;
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Post.
|
77 |
+
*
|
78 |
+
* @since 0.2
|
79 |
+
* @var WP_Post
|
80 |
+
*/
|
81 |
+
public $post;
|
82 |
+
|
83 |
+
/**
|
84 |
+
* AMP_Post_Template constructor.
|
85 |
+
*
|
86 |
+
* @param WP_Post|int $post Post.
|
87 |
+
*/
|
88 |
+
public function __construct( $post ) {
|
89 |
+
|
90 |
$this->template_dir = apply_filters( 'amp_post_template_dir', AMP__DIR__ . '/templates' );
|
91 |
|
92 |
+
if ( $post instanceof WP_Post ) {
|
93 |
+
$this->post = $post;
|
94 |
+
} else {
|
95 |
+
$this->post = get_post( $post );
|
96 |
+
}
|
97 |
+
$this->ID = $this->post->ID;
|
98 |
|
99 |
$content_max_width = self::CONTENT_MAX_WIDTH;
|
100 |
if ( isset( $GLOBALS['content_width'] ) && $GLOBALS['content_width'] > 0 ) {
|
103 |
$content_max_width = apply_filters( 'amp_content_max_width', $content_max_width );
|
104 |
|
105 |
$this->data = array(
|
106 |
+
'content_max_width' => $content_max_width,
|
107 |
|
108 |
+
'document_title' => function_exists( 'wp_get_document_title' ) ? wp_get_document_title() : wp_title( '', false ), // Back-compat with 4.3.
|
109 |
+
'canonical_url' => get_permalink( $this->ID ),
|
110 |
+
'home_url' => home_url(),
|
111 |
+
'blog_name' => get_bloginfo( 'name' ),
|
112 |
|
113 |
+
'html_tag_attributes' => array(),
|
114 |
+
'body_class' => '',
|
115 |
|
116 |
+
'site_icon_url' => apply_filters( 'amp_site_icon_url', function_exists( 'get_site_icon_url' ) ? get_site_icon_url( self::SITE_ICON_SIZE ) : '' ),
|
117 |
'placeholder_image_url' => amp_get_asset_url( 'images/placeholder-icon.png' ),
|
118 |
|
119 |
+
'featured_image' => false,
|
120 |
+
'comments_link_url' => false,
|
121 |
+
'comments_link_text' => false,
|
122 |
|
123 |
+
'amp_runtime_script' => 'https://cdn.ampproject.org/v0.js',
|
124 |
'amp_component_scripts' => array(),
|
125 |
|
126 |
+
'customizer_settings' => array(),
|
127 |
|
128 |
+
'font_urls' => array(
|
129 |
'merriweather' => 'https://fonts.googleapis.com/css?family=Merriweather:400,400italic,700,700italic',
|
130 |
),
|
131 |
|
132 |
+
'post_amp_styles' => array(),
|
133 |
|
134 |
/**
|
135 |
* Add amp-analytics tags.
|
137 |
* This filter allows you to easily insert any amp-analytics tags without needing much heavy lifting.
|
138 |
*
|
139 |
* @since 0.4
|
140 |
+
*
|
141 |
+
* @param array $analytics An associative array of the analytics entries we want to output. Each array entry must have a unique key, and the value should be an array with the following keys: `type`, `attributes`, `script_data`. See readme for more details.
|
142 |
+
* @param WP_Post $post The current post.
|
143 |
*/
|
144 |
+
'amp_analytics' => apply_filters( 'amp_post_template_analytics', array(), $this->post ),
|
145 |
+
);
|
146 |
|
147 |
$this->build_post_content();
|
148 |
$this->build_post_data();
|
149 |
$this->build_customizer_settings();
|
150 |
$this->build_html_tag_attributes();
|
151 |
|
152 |
+
/**
|
153 |
+
* Filters AMP template data.
|
154 |
+
*
|
155 |
+
* @since 0.2
|
156 |
+
*
|
157 |
+
* @param array $data Template data.
|
158 |
+
* @param WP_Post $post Post.
|
159 |
+
*/
|
160 |
$this->data = apply_filters( 'amp_post_template_data', $this->data, $this->post );
|
161 |
}
|
162 |
|
163 |
+
/**
|
164 |
+
* Getter.
|
165 |
+
*
|
166 |
+
* @param string $property Property name.
|
167 |
+
* @param mixed $default Default value.
|
168 |
+
*
|
169 |
+
* @return mixed Value.
|
170 |
+
*/
|
171 |
public function get( $property, $default = null ) {
|
172 |
if ( isset( $this->data[ $property ] ) ) {
|
173 |
return $this->data[ $property ];
|
174 |
} else {
|
175 |
+
/* translators: %s is key name */
|
176 |
+
_doing_it_wrong( __METHOD__, esc_html( sprintf( __( 'Called for non-existent key ("%s").', 'amp' ), $property ) ), '0.1' );
|
177 |
}
|
178 |
|
179 |
return $default;
|
180 |
}
|
181 |
|
182 |
+
/**
|
183 |
+
* Get customizer setting.
|
184 |
+
*
|
185 |
+
* @param string $name Name.
|
186 |
+
* @param mixed $default Default value.
|
187 |
+
* @return mixed value.
|
188 |
+
*/
|
189 |
public function get_customizer_setting( $name, $default = null ) {
|
190 |
$settings = $this->get( 'customizer_settings' );
|
191 |
if ( ! empty( $settings[ $name ] ) ) {
|
195 |
return $default;
|
196 |
}
|
197 |
|
198 |
+
/**
|
199 |
+
* Load and print the template parts for the given post.
|
200 |
+
*/
|
201 |
public function load() {
|
202 |
+
global $wp_query;
|
203 |
+
$template = is_page() || $wp_query->is_posts_page ? 'page' : 'single';
|
204 |
+
$this->load_parts( array( $template ) );
|
205 |
}
|
206 |
|
207 |
+
/**
|
208 |
+
* Load template parts.
|
209 |
+
*
|
210 |
+
* @param string[] $templates Templates.
|
211 |
+
*/
|
212 |
public function load_parts( $templates ) {
|
213 |
foreach ( $templates as $template ) {
|
214 |
$file = $this->get_template_path( $template );
|
216 |
}
|
217 |
}
|
218 |
|
219 |
+
/**
|
220 |
+
* Get template path.
|
221 |
+
*
|
222 |
+
* @param string $template Template name.
|
223 |
+
* @return string Template path.
|
224 |
+
*/
|
225 |
private function get_template_path( $template ) {
|
226 |
return sprintf( '%s/%s.php', $this->template_dir, $template );
|
227 |
}
|
228 |
|
229 |
+
/**
|
230 |
+
* Add data.
|
231 |
+
*
|
232 |
+
* @param array $data Data.
|
233 |
+
*/
|
234 |
private function add_data( $data ) {
|
235 |
$this->data = array_merge( $this->data, $data );
|
236 |
}
|
237 |
|
238 |
+
/**
|
239 |
+
* Add data by key.
|
240 |
+
*
|
241 |
+
* @param string $key Key.
|
242 |
+
* @param mixed $value Value.
|
243 |
+
*/
|
244 |
private function add_data_by_key( $key, $value ) {
|
245 |
$this->data[ $key ] = $value;
|
246 |
}
|
247 |
|
248 |
+
/**
|
249 |
+
* Merge data for key.
|
250 |
+
*
|
251 |
+
* @param string $key Key.
|
252 |
+
* @param mixed $value Value.
|
253 |
+
*/
|
254 |
private function merge_data_for_key( $key, $value ) {
|
255 |
if ( is_array( $this->data[ $key ] ) ) {
|
256 |
$this->data[ $key ] = array_merge( $this->data[ $key ], $value );
|
259 |
}
|
260 |
}
|
261 |
|
262 |
+
/**
|
263 |
+
* Build post data.
|
264 |
+
*
|
265 |
+
* @since 0.2
|
266 |
+
*/
|
267 |
private function build_post_data() {
|
268 |
+
$post_title = get_the_title( $this->ID );
|
269 |
+
$post_publish_timestamp = get_the_date( 'U', $this->ID );
|
270 |
$post_modified_timestamp = get_post_modified_time( 'U', false, $this->post );
|
271 |
+
$post_author = get_userdata( $this->post->post_author );
|
272 |
|
273 |
+
$this->add_data(
|
274 |
+
array(
|
275 |
+
'post' => $this->post,
|
276 |
+
'post_id' => $this->ID,
|
277 |
+
'post_title' => $post_title,
|
278 |
+
'post_publish_timestamp' => $post_publish_timestamp,
|
279 |
+
'post_modified_timestamp' => $post_modified_timestamp,
|
280 |
+
'post_author' => $post_author,
|
281 |
+
)
|
282 |
+
);
|
283 |
|
284 |
$metadata = array(
|
285 |
+
'@context' => 'http://schema.org',
|
286 |
+
'@type' => is_page() ? 'WebPage' : 'BlogPosting',
|
287 |
'mainEntityOfPage' => $this->get( 'canonical_url' ),
|
288 |
+
'publisher' => array(
|
289 |
'@type' => 'Organization',
|
290 |
+
'name' => $this->get( 'blog_name' ),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
291 |
),
|
292 |
+
'headline' => $post_title,
|
293 |
+
'datePublished' => date( 'c', $post_publish_timestamp ),
|
294 |
+
'dateModified' => date( 'c', $post_modified_timestamp ),
|
295 |
);
|
296 |
+
if ( $post_author ) {
|
297 |
+
$metadata['author'] = array(
|
298 |
+
'@type' => 'Person',
|
299 |
+
'name' => html_entity_decode( $post_author->display_name, ENT_QUOTES, get_bloginfo( 'charset' ) ),
|
300 |
+
);
|
301 |
+
}
|
302 |
|
303 |
$site_icon_url = $this->get( 'site_icon_url' );
|
304 |
if ( $site_icon_url ) {
|
305 |
$metadata['publisher']['logo'] = array(
|
306 |
+
'@type' => 'ImageObject',
|
307 |
+
'url' => $site_icon_url,
|
308 |
'height' => self::SITE_ICON_SIZE,
|
309 |
+
'width' => self::SITE_ICON_SIZE,
|
310 |
);
|
311 |
}
|
312 |
|
321 |
$this->build_post_commments_data();
|
322 |
}
|
323 |
|
324 |
+
/**
|
325 |
+
* Buuild post comments data.
|
326 |
+
*/
|
327 |
private function build_post_commments_data() {
|
328 |
if ( ! post_type_supports( $this->post->post_type, 'comments' ) ) {
|
329 |
return;
|
331 |
|
332 |
$comments_open = comments_open( $this->ID );
|
333 |
|
334 |
+
// Don't show link if close and no comments.
|
335 |
if ( ! $comments_open
|
336 |
&& ! $this->post->comment_count ) {
|
337 |
return;
|
338 |
}
|
339 |
|
340 |
+
$comments_link_url = get_comments_link( $this->ID );
|
341 |
$comments_link_text = $comments_open
|
342 |
? __( 'Leave a Comment', 'amp' )
|
343 |
: __( 'View Comments', 'amp' );
|
344 |
|
345 |
+
$this->add_data(
|
346 |
+
array(
|
347 |
+
'comments_link_url' => $comments_link_url,
|
348 |
+
'comments_link_text' => $comments_link_text,
|
349 |
+
)
|
350 |
+
);
|
351 |
}
|
352 |
|
353 |
+
/**
|
354 |
+
* Build post content.
|
355 |
+
*/
|
356 |
private function build_post_content() {
|
357 |
+
$amp_content = new AMP_Content(
|
358 |
+
$this->post->post_content,
|
359 |
+
apply_filters(
|
360 |
+
'amp_content_embed_handlers', array(
|
361 |
+
'AMP_Twitter_Embed_Handler' => array(),
|
362 |
+
'AMP_YouTube_Embed_Handler' => array(),
|
363 |
+
'AMP_DailyMotion_Embed_Handler' => array(),
|
364 |
+
'AMP_Vimeo_Embed_Handler' => array(),
|
365 |
+
'AMP_SoundCloud_Embed_Handler' => array(),
|
366 |
+
'AMP_Instagram_Embed_Handler' => array(),
|
367 |
+
'AMP_Vine_Embed_Handler' => array(),
|
368 |
+
'AMP_Facebook_Embed_Handler' => array(),
|
369 |
+
'AMP_Pinterest_Embed_Handler' => array(),
|
370 |
+
'AMP_Gallery_Embed_Handler' => array(),
|
371 |
+
'WPCOM_AMP_Polldaddy_Embed' => array(),
|
372 |
+
), $this->post
|
373 |
+
),
|
374 |
+
apply_filters(
|
375 |
+
'amp_content_sanitizers', array(
|
376 |
+
'AMP_Style_Sanitizer' => array(),
|
377 |
+
'AMP_Img_Sanitizer' => array(),
|
378 |
+
'AMP_Video_Sanitizer' => array(),
|
379 |
+
'AMP_Audio_Sanitizer' => array(),
|
380 |
+
'AMP_Playbuzz_Sanitizer' => array(),
|
381 |
+
'AMP_Iframe_Sanitizer' => array(
|
382 |
+
'add_placeholder' => true,
|
383 |
+
),
|
384 |
+
'AMP_Tag_And_Attribute_Sanitizer' => array(), // Note: This whitelist sanitizer must come at the end to clean up any remaining issues the other sanitizers didn't catch.
|
385 |
+
), $this->post
|
386 |
+
),
|
387 |
array(
|
388 |
'content_max_width' => $this->get( 'content_max_width' ),
|
389 |
)
|
394 |
$this->merge_data_for_key( 'post_amp_styles', $amp_content->get_amp_styles() );
|
395 |
}
|
396 |
|
397 |
+
/**
|
398 |
+
* Build post featured image.
|
399 |
+
*/
|
400 |
private function build_post_featured_image() {
|
401 |
+
$post_id = $this->ID;
|
402 |
$featured_html = get_the_post_thumbnail( $post_id, 'large' );
|
403 |
|
404 |
// Skip featured image if no featured image is available.
|
427 |
)
|
428 |
);
|
429 |
|
430 |
+
$this->add_data_by_key(
|
431 |
+
'featured_image', array(
|
432 |
+
'amp_html' => $sanitized_html,
|
433 |
+
'caption' => $featured_image->post_excerpt,
|
434 |
+
)
|
435 |
+
);
|
436 |
|
437 |
if ( $featured_scripts ) {
|
438 |
$this->merge_data_for_key( 'amp_component_scripts', $featured_scripts );
|
443 |
}
|
444 |
}
|
445 |
|
446 |
+
/**
|
447 |
+
* Build customizer settings.
|
448 |
+
*/
|
449 |
private function build_customizer_settings() {
|
450 |
$settings = AMP_Customizer_Settings::get_settings();
|
451 |
|
473 |
*/
|
474 |
private function get_post_image_metadata() {
|
475 |
$post_image_meta = null;
|
476 |
+
$post_image_id = false;
|
477 |
|
478 |
if ( has_post_thumbnail( $this->ID ) ) {
|
479 |
$post_image_id = get_post_thumbnail_id( $this->ID );
|
480 |
} else {
|
481 |
+
$attached_image_ids = get_posts(
|
482 |
+
array(
|
483 |
+
'post_parent' => $this->ID,
|
484 |
+
'post_type' => 'attachment',
|
485 |
+
'post_mime_type' => 'image',
|
486 |
+
'posts_per_page' => 1,
|
487 |
+
'orderby' => 'menu_order',
|
488 |
+
'order' => 'ASC',
|
489 |
+
'fields' => 'ids',
|
490 |
+
'suppress_filters' => false,
|
491 |
+
)
|
492 |
+
);
|
493 |
|
494 |
if ( ! empty( $attached_image_ids ) ) {
|
495 |
$post_image_id = array_shift( $attached_image_ids );
|
504 |
|
505 |
if ( is_array( $post_image_src ) ) {
|
506 |
$post_image_meta = array(
|
507 |
+
'@type' => 'ImageObject',
|
508 |
+
'url' => $post_image_src[0],
|
509 |
+
'width' => $post_image_src[1],
|
510 |
'height' => $post_image_src[2],
|
511 |
);
|
512 |
}
|
514 |
return $post_image_meta;
|
515 |
}
|
516 |
|
517 |
+
/**
|
518 |
+
* Build HTML tag attributes.
|
519 |
+
*/
|
520 |
private function build_html_tag_attributes() {
|
521 |
$attributes = array();
|
522 |
|
532 |
$this->add_data_by_key( 'html_tag_attributes', $attributes );
|
533 |
}
|
534 |
|
535 |
+
/**
|
536 |
+
* Verify and include.
|
537 |
+
*
|
538 |
+
* @param string $file File.
|
539 |
+
* @param string $template_type Template type.
|
540 |
+
*/
|
541 |
private function verify_and_include( $file, $template_type ) {
|
542 |
$located_file = $this->locate_template( $file );
|
543 |
if ( $located_file ) {
|
546 |
|
547 |
$file = apply_filters( 'amp_post_template_file', $file, $template_type, $this->post );
|
548 |
if ( ! $this->is_valid_template( $file ) ) {
|
549 |
+
/* translators: %1$s is template file, %2$s is 'WP_CONTENT_DIR' string. */
|
550 |
+
_doing_it_wrong( __METHOD__, sprintf( esc_html__( 'Path validation for template (%1$s) failed. Path cannot traverse and must be located in `%2$s`.', 'amp' ), esc_html( $file ), 'WP_CONTENT_DIR' ), '0.1' );
|
551 |
return;
|
552 |
}
|
553 |
|
554 |
do_action( 'amp_post_template_include_' . $template_type, $this );
|
555 |
+
include $file;
|
556 |
}
|
557 |
|
558 |
+
/**
|
559 |
+
* Locate template.
|
560 |
+
*
|
561 |
+
* @param string $file File.
|
562 |
+
* @return string The template filename if one is located.
|
563 |
+
*/
|
564 |
private function locate_template( $file ) {
|
565 |
$search_file = sprintf( 'amp/%s', basename( $file ) );
|
566 |
return locate_template( array( $search_file ), false );
|
567 |
}
|
568 |
|
569 |
+
/**
|
570 |
+
* Is valid template.
|
571 |
+
*
|
572 |
+
* @param string $template Template name.
|
573 |
+
* @return bool Whether valid.
|
574 |
+
*/
|
575 |
private function is_valid_template( $template ) {
|
576 |
if ( false !== strpos( $template, '..' ) ) {
|
577 |
return false;
|
includes/utils/class-amp-dom-utils.php
CHANGED
@@ -1,14 +1,40 @@
|
|
1 |
<?php
|
|
|
|
|
|
|
|
|
|
|
2 |
|
|
|
|
|
|
|
|
|
|
|
3 |
class AMP_DOM_Utils {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
public static function get_dom_from_content( $content ) {
|
5 |
$libxml_previous_state = libxml_use_internal_errors( true );
|
6 |
|
7 |
-
$dom = new DOMDocument;
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
|
|
|
|
|
|
|
|
12 |
$result = $dom->loadHTML( '<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body>' . $content . '</body></html>' );
|
13 |
|
14 |
libxml_clear_errors();
|
@@ -21,28 +47,124 @@ class AMP_DOM_Utils {
|
|
21 |
return $dom;
|
22 |
}
|
23 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
public static function get_content_from_dom( $dom ) {
|
25 |
-
|
26 |
-
|
|
|
|
|
27 |
$body = $dom->getElementsByTagName( 'body' )->item( 0 );
|
28 |
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
|
|
|
|
|
|
|
|
33 |
|
34 |
-
foreach ( $body->childNodes as $
|
35 |
-
$out .= $dom
|
36 |
}
|
|
|
37 |
return $out;
|
38 |
}
|
39 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
public static function create_node( $dom, $tag, $attributes ) {
|
41 |
$node = $dom->createElement( $tag );
|
42 |
self::add_attributes_to_node( $node, $attributes );
|
|
|
43 |
return $node;
|
44 |
}
|
45 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
public static function get_node_attributes_as_assoc_array( $node ) {
|
47 |
$attributes = array();
|
48 |
if ( ! $node->hasAttributes() ) {
|
@@ -52,48 +174,110 @@ class AMP_DOM_Utils {
|
|
52 |
foreach ( $node->attributes as $attribute ) {
|
53 |
$attributes[ $attribute->nodeName ] = $attribute->nodeValue;
|
54 |
}
|
|
|
55 |
return $attributes;
|
56 |
}
|
57 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
public static function add_attributes_to_node( $node, $attributes ) {
|
59 |
foreach ( $attributes as $name => $value ) {
|
60 |
$node->setAttribute( $name, $value );
|
61 |
}
|
62 |
}
|
63 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
public static function is_node_empty( $node ) {
|
65 |
-
return false === $node->hasChildNodes()
|
66 |
-
&& empty( $node->textContent );
|
67 |
}
|
68 |
|
69 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
if ( XML_ELEMENT_NODE !== $node->nodeType ) {
|
71 |
return;
|
72 |
}
|
73 |
|
74 |
if ( self::is_self_closing_tag( $node->nodeName ) ) {
|
|
|
|
|
|
|
|
|
75 |
return;
|
76 |
}
|
77 |
|
78 |
if ( self::is_node_empty( $node ) ) {
|
79 |
$text_node = $dom->createTextNode( '' );
|
80 |
$node->appendChild( $text_node );
|
|
|
81 |
return;
|
82 |
}
|
83 |
|
84 |
$num_children = $node->childNodes->length;
|
85 |
-
for ( $i = $num_children - 1; $i >= 0; $i-- ) {
|
86 |
$child = $node->childNodes->item( $i );
|
87 |
self::recursive_force_closing_tags( $dom, $child );
|
88 |
}
|
|
|
89 |
}
|
90 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
91 |
private static function is_self_closing_tag( $tag ) {
|
92 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
93 |
static $self_closing_tags;
|
94 |
if ( ! isset( $self_closing_tags ) ) {
|
95 |
-
|
96 |
-
|
|
|
|
|
97 |
$self_closing_tags = array(
|
98 |
'area',
|
99 |
'base',
|
@@ -115,7 +299,6 @@ class AMP_DOM_Utils {
|
|
115 |
'wbr',
|
116 |
);
|
117 |
}
|
118 |
-
|
119 |
-
return in_array( $tag, $self_closing_tags, true );
|
120 |
}
|
121 |
}
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Class AMP_DOM_Utils.
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
|
8 |
+
/**
|
9 |
+
* Class AMP_DOM_Utils
|
10 |
+
*
|
11 |
+
* Functionality to simplify working with DOMDocuments and DOMElements.
|
12 |
+
*/
|
13 |
class AMP_DOM_Utils {
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Return a valid DOMDocument representing arbitrary HTML content passed as a parameter.
|
17 |
+
*
|
18 |
+
* @see Reciprocal function get_content_from_dom()
|
19 |
+
*
|
20 |
+
* @since 0.2
|
21 |
+
*
|
22 |
+
* @param string $content Valid HTML content to be represented by a DOMDocument.
|
23 |
+
*
|
24 |
+
* @return DOMDocument|false Returns DOMDocument, or false if conversion failed.
|
25 |
+
*/
|
26 |
public static function get_dom_from_content( $content ) {
|
27 |
$libxml_previous_state = libxml_use_internal_errors( true );
|
28 |
|
29 |
+
$dom = new DOMDocument();
|
30 |
+
|
31 |
+
/*
|
32 |
+
* Wrap in dummy tags, since XML needs one parent node.
|
33 |
+
* It also makes it easier to loop through nodes.
|
34 |
+
* We can later use this to extract our nodes.
|
35 |
+
* Add utf-8 charset so loadHTML does not have problems parsing it.
|
36 |
+
* See: http://php.net/manual/en/domdocument.loadhtml.php#78243
|
37 |
+
*/
|
38 |
$result = $dom->loadHTML( '<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body>' . $content . '</body></html>' );
|
39 |
|
40 |
libxml_clear_errors();
|
47 |
return $dom;
|
48 |
}
|
49 |
|
50 |
+
/**
|
51 |
+
* Return valid HTML content extracted from the DOMDocument passed as a parameter.
|
52 |
+
*
|
53 |
+
* @see Reciprocal function get_dom_from_content()
|
54 |
+
*
|
55 |
+
* @since 0.2
|
56 |
+
*
|
57 |
+
* @param DOMDocument $dom Represents an HTML document from which to extract HTML content.
|
58 |
+
*
|
59 |
+
* @return string Returns the HTML content represented in the DOMDocument
|
60 |
+
*/
|
61 |
public static function get_content_from_dom( $dom ) {
|
62 |
+
|
63 |
+
/**
|
64 |
+
* We only want children of the body tag, since we have a subset of HTML.
|
65 |
+
*/
|
66 |
$body = $dom->getElementsByTagName( 'body' )->item( 0 );
|
67 |
|
68 |
+
/**
|
69 |
+
* The DOMDocument may contain no body. In which case return nothing.
|
70 |
+
*/
|
71 |
+
if ( is_null( $body ) ) {
|
72 |
+
return '';
|
73 |
+
}
|
74 |
+
|
75 |
+
$out = '';
|
76 |
|
77 |
+
foreach ( $body->childNodes as $child_node ) {
|
78 |
+
$out .= self::get_content_from_dom_node( $dom, $child_node );
|
79 |
}
|
80 |
+
|
81 |
return $out;
|
82 |
}
|
83 |
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Return valid HTML content extracted from the DOMNode passed as a parameter.
|
87 |
+
*
|
88 |
+
* @see Called by function get_content_from_dom()
|
89 |
+
*
|
90 |
+
* @since 0.6
|
91 |
+
*
|
92 |
+
* @param DOMDocument $dom Represents an HTML document.
|
93 |
+
* @param DOMNode $node Represents an HTML element of the $dom from which to extract HTML content.
|
94 |
+
* @return string Returns the HTML content represented in the DOMNode
|
95 |
+
*/
|
96 |
+
public static function get_content_from_dom_node( $dom, $node ) {
|
97 |
+
/**
|
98 |
+
* Self closing tags regex.
|
99 |
+
*
|
100 |
+
* @var string Regular expression to match self-closing tags
|
101 |
+
* that saveXML() has generated a closing tag for.
|
102 |
+
*/
|
103 |
+
static $self_closing_tags_regex;
|
104 |
+
|
105 |
+
/*
|
106 |
+
* Most AMP elements need closing tags. To force them, we cannot use
|
107 |
+
* saveHTML (node support is 5.3+) and LIBXML_NOEMPTYTAG results in
|
108 |
+
* issues with self-closing tags like `br` and `hr`. So, we're manually
|
109 |
+
* forcing closing tags.
|
110 |
+
*/
|
111 |
+
self::recursive_force_closing_tags( $dom, $node );
|
112 |
+
|
113 |
+
/*
|
114 |
+
* Cache this regex so we don't have to recreate it every call.
|
115 |
+
*/
|
116 |
+
if ( ! isset( $self_closing_tags_regex ) ) {
|
117 |
+
$self_closing_tags = implode( '|', self::get_self_closing_tags() );
|
118 |
+
$self_closing_tags_regex = "#></({$self_closing_tags})>#i";
|
119 |
+
}
|
120 |
+
|
121 |
+
$html = $dom->saveXML( $node );
|
122 |
+
|
123 |
+
// Whitespace just causes unit tests to fail... so whitespace begone.
|
124 |
+
if ( '' === trim( $html ) ) {
|
125 |
+
return '';
|
126 |
+
}
|
127 |
+
|
128 |
+
/*
|
129 |
+
* Travis w/PHP 7.1 generates <br></br> and <hr></hr> vs. <br/> and <hr/>, respectively.
|
130 |
+
* Travis w/PHP 7.x generates <source ...></source> vs. <source ... />. Etc.
|
131 |
+
* Seems like LIBXML_NOEMPTYTAG was passed, but as you can see it was not.
|
132 |
+
* This does not happen in my (@mikeschinkel) local testing, btw.
|
133 |
+
*/
|
134 |
+
$html = preg_replace( $self_closing_tags_regex, '/>', $html );
|
135 |
+
|
136 |
+
return $html;
|
137 |
+
|
138 |
+
}
|
139 |
+
|
140 |
+
/**
|
141 |
+
* Create a new node w/attributes (a DOMElement) and add to the passed DOMDocument.
|
142 |
+
*
|
143 |
+
* @since 0.2
|
144 |
+
*
|
145 |
+
* @param DOMDocument $dom A representation of an HTML document to add the new node to.
|
146 |
+
* @param string $tag A valid HTML element tag for the element to be added.
|
147 |
+
* @param string[] $attributes One of more valid attributes for the new node.
|
148 |
+
*
|
149 |
+
* @return DOMElement|false The DOMElement for the given $tag, or false on failure
|
150 |
+
*/
|
151 |
public static function create_node( $dom, $tag, $attributes ) {
|
152 |
$node = $dom->createElement( $tag );
|
153 |
self::add_attributes_to_node( $node, $attributes );
|
154 |
+
|
155 |
return $node;
|
156 |
}
|
157 |
|
158 |
+
/**
|
159 |
+
* Extract a DOMElement node's HTML element attributes and return as an array.
|
160 |
+
*
|
161 |
+
* @since 0.2
|
162 |
+
*
|
163 |
+
* @param DOMNode $node Represents an HTML element for which to extract attributes.
|
164 |
+
*
|
165 |
+
* @return string[] The attributes for the passed node, or an
|
166 |
+
* empty array if it has no attributes.
|
167 |
+
*/
|
168 |
public static function get_node_attributes_as_assoc_array( $node ) {
|
169 |
$attributes = array();
|
170 |
if ( ! $node->hasAttributes() ) {
|
174 |
foreach ( $node->attributes as $attribute ) {
|
175 |
$attributes[ $attribute->nodeName ] = $attribute->nodeValue;
|
176 |
}
|
177 |
+
|
178 |
return $attributes;
|
179 |
}
|
180 |
|
181 |
+
/**
|
182 |
+
* Add one or more HTML element attributes to a node's DOMElement.
|
183 |
+
*
|
184 |
+
* @since 0.2
|
185 |
+
*
|
186 |
+
* @param DOMElement $node Represents an HTML element.
|
187 |
+
* @param string[] $attributes One or more attributes for the node's HTML element.
|
188 |
+
*/
|
189 |
public static function add_attributes_to_node( $node, $attributes ) {
|
190 |
foreach ( $attributes as $name => $value ) {
|
191 |
$node->setAttribute( $name, $value );
|
192 |
}
|
193 |
}
|
194 |
|
195 |
+
/**
|
196 |
+
* Determines if a DOMElement's node is empty or not..
|
197 |
+
*
|
198 |
+
* @since 0.2
|
199 |
+
*
|
200 |
+
* @param DOMElement $node Represents an HTML element.
|
201 |
+
* @return bool Returns true if the DOMElement has no child nodes and
|
202 |
+
* the textContent property of the DOMElement is empty;
|
203 |
+
* Otherwise it returns false.
|
204 |
+
*/
|
205 |
public static function is_node_empty( $node ) {
|
206 |
+
return false === $node->hasChildNodes() && empty( $node->textContent );
|
|
|
207 |
}
|
208 |
|
209 |
+
/**
|
210 |
+
* Forces HTML element closing tags given a DOMDocument and optional DOMElement
|
211 |
+
*
|
212 |
+
* @since 0.2
|
213 |
+
*
|
214 |
+
* @param DOMDocument $dom Represents HTML document on which to force closing tags.
|
215 |
+
* @param DOMElement $node Represents HTML element to start closing tags on.
|
216 |
+
* If not passed, defaults to first child of body.
|
217 |
+
*/
|
218 |
+
public static function recursive_force_closing_tags( $dom, $node = null ) {
|
219 |
+
|
220 |
+
if ( is_null( $node ) ) {
|
221 |
+
$node = $dom->getElementsByTagName( 'body' )->item( 0 );
|
222 |
+
}
|
223 |
+
|
224 |
if ( XML_ELEMENT_NODE !== $node->nodeType ) {
|
225 |
return;
|
226 |
}
|
227 |
|
228 |
if ( self::is_self_closing_tag( $node->nodeName ) ) {
|
229 |
+
/*
|
230 |
+
* Ensure there is no text content to accidentally force a child
|
231 |
+
*/
|
232 |
+
$node->textContent = null;
|
233 |
return;
|
234 |
}
|
235 |
|
236 |
if ( self::is_node_empty( $node ) ) {
|
237 |
$text_node = $dom->createTextNode( '' );
|
238 |
$node->appendChild( $text_node );
|
239 |
+
|
240 |
return;
|
241 |
}
|
242 |
|
243 |
$num_children = $node->childNodes->length;
|
244 |
+
for ( $i = $num_children - 1; $i >= 0; $i -- ) {
|
245 |
$child = $node->childNodes->item( $i );
|
246 |
self::recursive_force_closing_tags( $dom, $child );
|
247 |
}
|
248 |
+
|
249 |
}
|
250 |
|
251 |
+
/**
|
252 |
+
* Determines if an HTML element tag is validly a self-closing tag per W3C HTML5 specs.
|
253 |
+
*
|
254 |
+
* @since 0.2
|
255 |
+
*
|
256 |
+
* @param string $tag Tag.
|
257 |
+
* @return bool Returns true if a valid self-closing tag, false if not.
|
258 |
+
*/
|
259 |
private static function is_self_closing_tag( $tag ) {
|
260 |
+
return in_array( $tag, self::get_self_closing_tags(), true );
|
261 |
+
}
|
262 |
+
|
263 |
+
/**
|
264 |
+
* Returns array of self closing tags
|
265 |
+
*
|
266 |
+
* @since 0.6
|
267 |
+
*
|
268 |
+
* @return string[]
|
269 |
+
*/
|
270 |
+
private static function get_self_closing_tags() {
|
271 |
+
/*
|
272 |
+
* As this function is called a lot the static var
|
273 |
+
* prevents having to re-create the array every time.
|
274 |
+
*/
|
275 |
static $self_closing_tags;
|
276 |
if ( ! isset( $self_closing_tags ) ) {
|
277 |
+
/*
|
278 |
+
* https://www.w3.org/TR/html5/syntax.html#serializing-html-fragments
|
279 |
+
* Not all are valid AMP, but we include them for completeness.
|
280 |
+
*/
|
281 |
$self_closing_tags = array(
|
282 |
'area',
|
283 |
'base',
|
299 |
'wbr',
|
300 |
);
|
301 |
}
|
302 |
+
return $self_closing_tags;
|
|
|
303 |
}
|
304 |
}
|
includes/utils/class-amp-image-dimension-extractor.php
CHANGED
@@ -172,12 +172,9 @@ class AMP_Image_Dimension_Extractor {
|
|
172 |
* @param array $images Array to populate with results of image/dimension inspection.
|
173 |
*/
|
174 |
private static function fetch_images_via_fast_image( $urls_to_fetch, &$images ) {
|
175 |
-
if ( ! class_exists( 'FastImage' ) ) {
|
176 |
-
require_once( AMP__DIR__ . '/includes/lib/fastimage/class-fastimage.php' );
|
177 |
-
}
|
178 |
|
179 |
$image = new FastImage();
|
180 |
-
$urls
|
181 |
|
182 |
foreach ( $urls as $url ) {
|
183 |
$result = $image->load( $url );
|
@@ -185,6 +182,7 @@ class AMP_Image_Dimension_Extractor {
|
|
185 |
$images[ $url ]['size'] = self::STATUS_IMAGE_EXTRACTION_FAILED;
|
186 |
} else {
|
187 |
$size = $image->getSize();
|
|
|
188 |
$images[ $url ]['size'] = $size;
|
189 |
}
|
190 |
}
|
172 |
* @param array $images Array to populate with results of image/dimension inspection.
|
173 |
*/
|
174 |
private static function fetch_images_via_fast_image( $urls_to_fetch, &$images ) {
|
|
|
|
|
|
|
175 |
|
176 |
$image = new FastImage();
|
177 |
+
$urls = array_keys( $urls_to_fetch );
|
178 |
|
179 |
foreach ( $urls as $url ) {
|
180 |
$result = $image->load( $url );
|
182 |
$images[ $url ]['size'] = self::STATUS_IMAGE_EXTRACTION_FAILED;
|
183 |
} else {
|
184 |
$size = $image->getSize();
|
185 |
+
|
186 |
$images[ $url ]['size'] = $size;
|
187 |
}
|
188 |
}
|
readme-assets/amp-options-analytics.png
DELETED
Binary file
|
readme-assets/analytics-option-entries.png
DELETED
Binary file
|
readme-assets/invalid-input.png
DELETED
Binary file
|
readme-assets/options-saved.png
DELETED
Binary file
|
readme.md
DELETED
@@ -1,684 +0,0 @@
|
|
1 |
-
# AMP for WordPress
|
2 |
-
|
3 |
-
## Overview
|
4 |
-
|
5 |
-
This plugin adds support for the [Accelerated Mobile Pages](https://www.ampproject.org) (AMP) Project, which is an open source initiative that aims to provide mobile optimized content that can load instantly everywhere.
|
6 |
-
|
7 |
-
With the plugin active, all posts on your site will have dynamically generated AMP-compatible versions, accessible by appending `/amp/` to the end your post URLs. For example, if your post URL is `http://example.com/2016/01/01/amp-on/`, you can access the AMP version at `http://example.com/2016/01/01/amp-on/amp/`. If you do not have [pretty permalinks](https://codex.wordpress.org/Using_Permalinks#mod_rewrite:_.22Pretty_Permalinks.22) enabled, you can do the same thing by appending `?amp=1`, i.e. `http://example.com/?p=123&=1`
|
8 |
-
|
9 |
-
Note #1: that Pages and archives are not currently supported.
|
10 |
-
|
11 |
-
Note #2: this plugin only creates AMP content but does not automatically display it to your users when they visit from a mobile device. That is handled by AMP consumers such as Google Search. For more details, see the [AMP Project FAQ](https://www.ampproject.org/docs/support/faqs.html).
|
12 |
-
|
13 |
-
## Customization / Templating
|
14 |
-
|
15 |
-
The plugin ships with a default template that looks nice and clean and we tried to find a good balance between ease and extensibility when it comes to customization.
|
16 |
-
|
17 |
-
You can tweak small pieces of the template or the entire thing depending on your needs.
|
18 |
-
|
19 |
-
### Where Do I Put My Code?
|
20 |
-
|
21 |
-
The code snippets below and any other code-level customizations should happen in one of the following locations.
|
22 |
-
|
23 |
-
If you're using an off-the-shelf theme (like from the WordPress.org Theme Directory):
|
24 |
-
|
25 |
-
- A [child theme](https://developer.wordpress.org/themes/advanced-topics/child-themes/).
|
26 |
-
- A custom plugin that you activate via the Dashboard.
|
27 |
-
- A [mu-plugin](https://codex.wordpress.org/Must_Use_Plugins).
|
28 |
-
|
29 |
-
If you're using a custom theme:
|
30 |
-
|
31 |
-
- `functions.php` (or via a 'require' call to files that load from `functions.php`).
|
32 |
-
- Any of the options above.
|
33 |
-
|
34 |
-
### Theme Mods
|
35 |
-
|
36 |
-
The default template will attempt to draw from various theme mods, such as site icon, if supported by the active theme.
|
37 |
-
|
38 |
-
#### Site Icon
|
39 |
-
|
40 |
-
If you add a site icon, we will automatically replace the WordPress logo in the template.
|
41 |
-
|
42 |
-
If you'd prefer to do it via code:
|
43 |
-
|
44 |
-
```php
|
45 |
-
add_filter( 'amp_post_template_data', 'xyz_amp_set_site_icon_url' );
|
46 |
-
|
47 |
-
function xyz_amp_set_site_icon_url( $data ) {
|
48 |
-
// Ideally a 32x32 image
|
49 |
-
$data[ 'site_icon_url' ] = get_stylesheet_directory_uri() . '/images/amp-site-icon.png';
|
50 |
-
return $data;
|
51 |
-
}
|
52 |
-
```
|
53 |
-
|
54 |
-
#### Logo Only
|
55 |
-
|
56 |
-
If you want to hide the site text and just show a logo, use the `amp_post_template_css` action. The following colors the title bar black, hides the site title, and replaces it with a centered logo:
|
57 |
-
|
58 |
-
```php
|
59 |
-
add_action( 'amp_post_template_css', 'xyz_amp_additional_css_styles' );
|
60 |
-
|
61 |
-
function xyz_amp_additional_css_styles( $amp_template ) {
|
62 |
-
// only CSS here please...
|
63 |
-
?>
|
64 |
-
header.amp-wp-header {
|
65 |
-
padding: 12px 0;
|
66 |
-
background: #000;
|
67 |
-
}
|
68 |
-
header.amp-wp-header a {
|
69 |
-
background-image: url( 'https://example.com/path/to/logo.png' );
|
70 |
-
background-repeat: no-repeat;
|
71 |
-
background-size: contain;
|
72 |
-
display: block;
|
73 |
-
height: 28px;
|
74 |
-
width: 94px;
|
75 |
-
margin: 0 auto;
|
76 |
-
text-indent: -9999px;
|
77 |
-
}
|
78 |
-
<?php
|
79 |
-
}
|
80 |
-
```
|
81 |
-
|
82 |
-
Note: you will need to adjust the colors and sizes based on your brand.
|
83 |
-
|
84 |
-
### Template Tweaks
|
85 |
-
|
86 |
-
You can tweak various parts of the template via code.
|
87 |
-
|
88 |
-
#### Featured Image
|
89 |
-
|
90 |
-
The default template displays the featured image. If you don't want to display the featured image in your amp page, use the following code:
|
91 |
-
|
92 |
-
```php
|
93 |
-
add_filter( 'amp_post_template_data', 'xyz_amp_remove_featured_image' );
|
94 |
-
|
95 |
-
function xyz_amp_remove_featured_image( $data ) {
|
96 |
-
$data['featured_image'] = false;
|
97 |
-
return $data;
|
98 |
-
}
|
99 |
-
```
|
100 |
-
|
101 |
-
#### Content Width
|
102 |
-
|
103 |
-
By default, your theme's `$content_width` value will be used to determine the size of the `amp` content well. You can change this:
|
104 |
-
|
105 |
-
```php
|
106 |
-
add_filter( 'amp_content_max_width', 'xyz_amp_change_content_width' );
|
107 |
-
|
108 |
-
function xyz_amp_change_content_width( $content_max_width ) {
|
109 |
-
return 1200;
|
110 |
-
}
|
111 |
-
```
|
112 |
-
|
113 |
-
#### Template Data
|
114 |
-
|
115 |
-
Use the `amp_post_template_data` filter to override default template data. The following changes the placeholder image used for iframes to a file located in the current theme:
|
116 |
-
|
117 |
-
```php
|
118 |
-
add_filter( 'amp_post_template_data', 'xyz_amp_set_custom_placeholder_image' );
|
119 |
-
|
120 |
-
function xyz_set_custom_placeholder_image( $data ) {
|
121 |
-
$data[ 'placeholder_image_url' ] = get_stylesheet_directory_uri() . '/images/amp-iframe-placeholder.png';
|
122 |
-
return $data;
|
123 |
-
}
|
124 |
-
```
|
125 |
-
|
126 |
-
Note: The path must pass the default criteria set out by [`validate_file`](https://developer.wordpress.org/reference/functions/validate_file/) and must be somewhere in a subfolder of `WP_CONTENT_DIR`.
|
127 |
-
|
128 |
-
#### Schema.org (JSON) Metadata
|
129 |
-
|
130 |
-
The plugin adds some default metadata to enable ["Rich Snippet" support](https://developers.google.com/structured-data/rich-snippets/articles). You can modify this using the `amp_post_template_metadata` filter. The following changes the type annotation to `NewsArticle` (from the default `BlogPosting`) and overrides the default Publisher Logo.
|
131 |
-
|
132 |
-
```php
|
133 |
-
add_filter( 'amp_post_template_metadata', 'xyz_amp_modify_json_metadata', 10, 2 );
|
134 |
-
|
135 |
-
function xyz_amp_modify_json_metadata( $metadata, $post ) {
|
136 |
-
$metadata['@type'] = 'NewsArticle';
|
137 |
-
|
138 |
-
$metadata['publisher']['logo'] = array(
|
139 |
-
'@type' => 'ImageObject',
|
140 |
-
'url' => get_template_directory_uri() . '/images/my-amp-metadata-logo.png',
|
141 |
-
'height' => 60,
|
142 |
-
'width' => 600,
|
143 |
-
);
|
144 |
-
|
145 |
-
return $metadata;
|
146 |
-
}
|
147 |
-
```
|
148 |
-
|
149 |
-
#### Template Meta (Author, Date, etc.)
|
150 |
-
|
151 |
-
For the meta section of the template (i.e. author, date, taxonomies, etc.), you can override templates for the existing sections, remove them, add new ones.
|
152 |
-
|
153 |
-
##### Example: Override Author Template from Theme
|
154 |
-
|
155 |
-
Create a folder in your theme called `amp` and add a file called `meta-author.php` with the following:
|
156 |
-
|
157 |
-
```php
|
158 |
-
<li class="xyz-byline">
|
159 |
-
<span>Anonymous</span>
|
160 |
-
</li>
|
161 |
-
```
|
162 |
-
|
163 |
-
Replace the contents, as needed.
|
164 |
-
|
165 |
-
##### Example: Override Taxonomy Template via filter
|
166 |
-
|
167 |
-
This will load the file `t/meta-custom-tax.php` for the `taxonomy` section:
|
168 |
-
|
169 |
-
```php
|
170 |
-
add_filter( 'amp_post_template_file', 'xyz_amp_set_custom_tax_meta_template', 10, 3 );
|
171 |
-
|
172 |
-
function xyz_amp_set_custom_tax_meta_template( $file, $type, $post ) {
|
173 |
-
if ( 'meta-taxonomy' === $type ) {
|
174 |
-
$file = dirname( __FILE__ ) . '/t/meta-custom-tax.php';
|
175 |
-
}
|
176 |
-
return $file;
|
177 |
-
}
|
178 |
-
```
|
179 |
-
|
180 |
-
In `t/meta-custom-tax.php`, you can add something like the following to replace the default category and tags with your custom `author` taxonomy:
|
181 |
-
|
182 |
-
```php
|
183 |
-
<li class="xyz-tax-authors">
|
184 |
-
<?php echo get_the_term_list( $this->get( 'post_id' ), 'xyz-author', '', ', ' ); ?>
|
185 |
-
</li>
|
186 |
-
```
|
187 |
-
|
188 |
-
##### Example: Remove Author from `header_meta`
|
189 |
-
|
190 |
-
This will completely remove the author section:
|
191 |
-
|
192 |
-
```php
|
193 |
-
add_filter( 'amp_post_article_header_meta', 'xyz_amp_remove_author_meta' );
|
194 |
-
|
195 |
-
function xyz_amp_remove_author_meta( $meta_parts ) {
|
196 |
-
foreach ( array_keys( $meta_parts, 'meta-author', true ) as $key ) {
|
197 |
-
unset( $meta_parts[ $key ] );
|
198 |
-
}
|
199 |
-
return $meta_parts;
|
200 |
-
}
|
201 |
-
```
|
202 |
-
|
203 |
-
##### Example: Add Comment Count to `footer_meta`
|
204 |
-
|
205 |
-
This adds a new section to display the comment count:
|
206 |
-
|
207 |
-
```php
|
208 |
-
add_filter( 'amp_post_article_footer_meta', 'xyz_amp_add_comment_count_meta' );
|
209 |
-
|
210 |
-
function xyz_amp_add_comment_count_meta( $meta_parts ) {
|
211 |
-
$meta_parts[] = 'xyz-meta-comment-count';
|
212 |
-
return $meta_parts;
|
213 |
-
}
|
214 |
-
|
215 |
-
add_filter( 'amp_post_template_file', 'xyz_amp_set_comment_count_meta_path', 10, 3 );
|
216 |
-
|
217 |
-
function xyz_amp_set_comment_count_meta_path( $file, $type, $post ) {
|
218 |
-
if ( 'xyz-meta-comment-count' === $type ) {
|
219 |
-
$file = dirname( __FILE__ ) . '/templates/xyz-meta-comment-count.php';
|
220 |
-
}
|
221 |
-
return $file;
|
222 |
-
}
|
223 |
-
```
|
224 |
-
|
225 |
-
Then, in `templates/xyz-meta-comment-count.php`:
|
226 |
-
|
227 |
-
```php
|
228 |
-
<li>
|
229 |
-
<?php printf( _n( '%d comment', '%d comments', $this->get( 'post' )->comment_count, 'xyz-text-domain' ) ); ?>
|
230 |
-
</li>
|
231 |
-
```
|
232 |
-
|
233 |
-
#### Custom CSS
|
234 |
-
|
235 |
-
##### Rule Additions
|
236 |
-
|
237 |
-
If you want to append to the existing CSS rules (e.g. styles for a custom embed handler), you can use the `amp_post_template_css` action:
|
238 |
-
|
239 |
-
```php
|
240 |
-
add_action( 'amp_post_template_css', 'xyz_amp_my_additional_css_styles' );
|
241 |
-
|
242 |
-
function xyz_amp_my_additional_css_styles( $amp_template ) {
|
243 |
-
// only CSS here please...
|
244 |
-
?>
|
245 |
-
.amp-wp-byline amp-img {
|
246 |
-
border-radius: 0; /* we don't want round avatars! */
|
247 |
-
}
|
248 |
-
.my-custom-class {
|
249 |
-
color: blue;
|
250 |
-
}
|
251 |
-
<?php
|
252 |
-
}
|
253 |
-
```
|
254 |
-
|
255 |
-
##### Completely Override CSS
|
256 |
-
|
257 |
-
If you'd prefer to use your own styles, you can either:
|
258 |
-
|
259 |
-
- Create a folder in your theme called `amp` and add a file called `style.php` with your custom CSS.
|
260 |
-
- Specify a custom template using the `amp_post_template_file` filter for `'style' === $type`. See the "Override" examples in the "Meta" section for examples.
|
261 |
-
|
262 |
-
Note: the file should only include CSS, not the `<style>` opening and closing tag.
|
263 |
-
|
264 |
-
#### Head and Footer
|
265 |
-
|
266 |
-
If you want to add stuff to the head or footer of the default AMP template, use the `amp_post_template_head` and `amp_post_template_footer` actions.
|
267 |
-
|
268 |
-
```php
|
269 |
-
add_action( 'amp_post_template_footer', 'xyz_amp_add_pixel' );
|
270 |
-
|
271 |
-
function xyz_amp_add_pixel( $amp_template ) {
|
272 |
-
$post_id = $amp_template->get( 'post_id' );
|
273 |
-
?>
|
274 |
-
<amp-pixel src="https://example.com/hi.gif?x=RANDOM"></amp-pixel>
|
275 |
-
<?php
|
276 |
-
}
|
277 |
-
```
|
278 |
-
|
279 |
-
#### AMP Endpoint
|
280 |
-
|
281 |
-
If you don't want to use the default `/amp` endpoint, use the `amp_query_var` filter to change it to anything else.
|
282 |
-
|
283 |
-
```php
|
284 |
-
add_filter( 'amp_query_var' , 'xyz_amp_change_endpoint' );
|
285 |
-
|
286 |
-
function xyz_amp_change_endpoint( $amp_endpoint ) {
|
287 |
-
return 'foo';
|
288 |
-
}
|
289 |
-
```
|
290 |
-
|
291 |
-
### Custom Template
|
292 |
-
|
293 |
-
If you want complete control over the look and feel of your AMP content, you can override the default template using the `amp_post_template_file` filter and pass it the path to a custom template:
|
294 |
-
|
295 |
-
```php
|
296 |
-
add_filter( 'amp_post_template_file', 'xyz_amp_set_custom_template', 10, 3 );
|
297 |
-
|
298 |
-
function xyz_amp_set_custom_template( $file, $type, $post ) {
|
299 |
-
if ( 'single' === $type ) {
|
300 |
-
$file = dirname( __FILE__ ) . '/templates/my-amp-template.php';
|
301 |
-
}
|
302 |
-
return $file;
|
303 |
-
}
|
304 |
-
```
|
305 |
-
|
306 |
-
Note: there are some requirements for a custom template:
|
307 |
-
|
308 |
-
* You must trigger the `amp_post_template_head` action in the `<head>` section:
|
309 |
-
|
310 |
-
```php
|
311 |
-
do_action( 'amp_post_template_head', $this );
|
312 |
-
```
|
313 |
-
|
314 |
-
* You must trigger the `amp_post_template_footer` action right before the `</body>` tag:
|
315 |
-
|
316 |
-
```php
|
317 |
-
do_action( 'amp_post_template_footer', $this );
|
318 |
-
```
|
319 |
-
|
320 |
-
* Within your `amp-custom` `style` tags, you must trigger the `amp_post_template_css` action:
|
321 |
-
|
322 |
-
```php
|
323 |
-
do_action( 'amp_post_template_css', $this );
|
324 |
-
```
|
325 |
-
|
326 |
-
* You must include [all required mark-up](https://www.ampproject.org/docs/get_started/create/basic_markup.html) that isn't already output via the `amp_post_template_head` action.
|
327 |
-
|
328 |
-
## Handling Media
|
329 |
-
|
330 |
-
By default, the plugin attempts to gracefully handle the following media elements in your content:
|
331 |
-
|
332 |
-
- images (converted from `img` => `amp-img` or `amp-anim`)
|
333 |
-
- videos (converted from `video` => `amp-video`; Note: Flash is not supported)
|
334 |
-
- audio (converted from `audio` => `amp-audio`)
|
335 |
-
- iframes (converted from `iframes` => `amp-iframes`)
|
336 |
-
- YouTube, Instagram, Twitter, and Vine oEmbeds and shortcodes (converted from the embed to the matching `amp-` component)
|
337 |
-
|
338 |
-
For additional media content such as custom shortcodes, oEmbeds or manually inserted embeds, ads, etc. there are several customization options available and outlined below.
|
339 |
-
|
340 |
-
### Do Nothing
|
341 |
-
|
342 |
-
If your embeds/media use standard iframes, you can choose to do nothing and let the plugin handle things. They should "just work" in most cases.
|
343 |
-
|
344 |
-
### `the_content` filter
|
345 |
-
|
346 |
-
All existing hooks on `the_content` will continue to work. This can be a good or bad thing. Good, because existing plugin integrations will continue to work. Bad, because not all added content may make sense in an AMP context.
|
347 |
-
|
348 |
-
You can add additional callbacks to `the_content` filter to output additional content as needed. Use the `is_amp_endpoint()` function to check if an AMP version of a post is being viewed. However, we recommend using an Embed Handler instead.
|
349 |
-
|
350 |
-
Caveat: with this method, if you add a custom component that requires inclusion of a script, you will need to add that script manually to the template using the `amp_post_template_head` action.
|
351 |
-
|
352 |
-
### Update Existing Shortcodes
|
353 |
-
|
354 |
-
In your existing shortcode or oEmbed callbacks, you can branch using the `is_amp_endpoint()` and output customized content for AMP content.
|
355 |
-
|
356 |
-
The same caveat about scripts for custom AMP components applies.
|
357 |
-
|
358 |
-
### Custom Embed Handler
|
359 |
-
|
360 |
-
Embed Handlers are helper classes to inject AMP-specific content for your oEmbeds and shortcodes.
|
361 |
-
|
362 |
-
Embed Handlers register the embeds they handle using standard WordPress functions such as `add_shortcode`. For working examples, check out the existing implementations for Instagram, Twitter, etc. as guides to build your own.
|
363 |
-
|
364 |
-
While the primary purpose of Embed Handlers is for use with embeds, you can use them for adding AMP-specific `the_content` callbacks as well.
|
365 |
-
|
366 |
-
#### Step 1: Build the Embed Handler
|
367 |
-
|
368 |
-
Your Embed Handler class needs to extend the `AMP_Base_Embed_Handler` class.
|
369 |
-
|
370 |
-
Note: make sure to set proper priorities or remove existing callbacks for your regular content.
|
371 |
-
|
372 |
-
In `classes/class-amp-related-posts-embed.php`:
|
373 |
-
|
374 |
-
```php
|
375 |
-
class XYZ_AMP_Related_Posts_Embed extends AMP_Base_Embed_Handler {
|
376 |
-
public function register_embed() {
|
377 |
-
// If we have an existing callback we are overriding, remove it.
|
378 |
-
remove_filter( 'the_content', 'xyz_add_related_posts' );
|
379 |
-
|
380 |
-
// Add our new callback
|
381 |
-
add_filter( 'the_content', array( $this, 'add_related_posts' ) );
|
382 |
-
}
|
383 |
-
|
384 |
-
public function unregister_embed() {
|
385 |
-
// Let's clean up after ourselves, just in case.
|
386 |
-
add_filter( 'the_content', 'xyz_add_related_posts' );
|
387 |
-
remove_filter( 'the_content', array( $this, 'add_related_posts' ) );
|
388 |
-
}
|
389 |
-
|
390 |
-
public function get_scripts() {
|
391 |
-
return array(
|
392 |
-
'amp-mustache' => 'https://cdn.ampproject.org/v0/amp-mustache-0.1.js',
|
393 |
-
'amp-list' => 'https://cdn.ampproject.org/v0/amp-list-0.1.js',
|
394 |
-
);
|
395 |
-
}
|
396 |
-
|
397 |
-
public function add_related_posts( $content ) {
|
398 |
-
// See https://github.com/ampproject/amphtml/blob/master/extensions/amp-list/amp-list.md for details on amp-list
|
399 |
-
$related_posts_list = '
|
400 |
-
<amp-list src="https://data.com/articles.json?ref=CANONICAL_URL" width=300 height=200 layout=responsive>
|
401 |
-
<template type="amp-mustache">
|
402 |
-
<div>
|
403 |
-
<amp-img src="{{imageUrl}}" width=50 height=50></amp-img>
|
404 |
-
{{title}}
|
405 |
-
</div>
|
406 |
-
</template>
|
407 |
-
<div overflow role=button aria-label="Show more" class="list-overflow">
|
408 |
-
Show more
|
409 |
-
</div>
|
410 |
-
</amp-list>';
|
411 |
-
|
412 |
-
$content .= $related_posts_list;
|
413 |
-
|
414 |
-
return $content;
|
415 |
-
}
|
416 |
-
}
|
417 |
-
```
|
418 |
-
|
419 |
-
#### Step 2: Load the Embed Handler
|
420 |
-
|
421 |
-
```php
|
422 |
-
add_filter( 'amp_content_embed_handlers', 'xyz_amp_add_related_embed', 10, 2 );
|
423 |
-
|
424 |
-
function xyz_amp_add_related_embed( $embed_handler_classes, $post ) {
|
425 |
-
require_once( dirname( __FILE__ ) . '/classes/class-amp-related-posts-embed.php' );
|
426 |
-
$embed_handler_classes[ 'XYZ_AMP_Related_Posts_Embed' ] = array();
|
427 |
-
return $embed_handler_classes;
|
428 |
-
}
|
429 |
-
```
|
430 |
-
|
431 |
-
### Custom Sanitizer
|
432 |
-
|
433 |
-
The name "sanitizer" is a bit of a misnomer. These are primarily used internally in the plugin to make your site's content compatible with the amp spec. This involves stripping unsupported tags and attributes and transforming media elements to their matching amp version (e.g. `img` => `amp-img`).
|
434 |
-
|
435 |
-
Sanitizers are pretty versatile and, unlike Embed Handlers -- which work with HTML content as a string -- they can be used to manipulate your post's AMP content using [PHP's `DOM` library](http://php.net/manual/en/book.dom.php). We've included an example that shows you how to use a custom sanitizer to inject ads into your content. You can, of course, do many other things such as add related content.
|
436 |
-
|
437 |
-
#### Step 1: Build the Sanitizer
|
438 |
-
|
439 |
-
Your sanitizer needs to extend the `AMP_Base_Sanitizer`. In `classes/class-ad-inject-sanitizer.php`:
|
440 |
-
|
441 |
-
```php
|
442 |
-
class XYZ_AMP_Ad_Injection_Sanitizer extends AMP_Base_Sanitizer {
|
443 |
-
public function sanitize() {
|
444 |
-
$body = $this->get_body_node();
|
445 |
-
|
446 |
-
// Build our amp-ad tag
|
447 |
-
$ad_node = AMP_DOM_Utils::create_node( $this->dom, 'amp-ad', array(
|
448 |
-
// Taken from example at https://github.com/ampproject/amphtml/blob/master/builtins/amp-ad.md
|
449 |
-
'width' => 300,
|
450 |
-
'height' => 250,
|
451 |
-
'type' => 'a9',
|
452 |
-
'data-aax_size' => '300x250',
|
453 |
-
'data-aax_pubname' => 'test123',
|
454 |
-
'data-aax_src' => '302',
|
455 |
-
) );
|
456 |
-
|
457 |
-
// Add a placeholder to show while loading
|
458 |
-
$fallback_node = AMP_DOM_Utils::create_node( $this->dom, 'amp-img', array(
|
459 |
-
'placeholder' => '',
|
460 |
-
'layout' => 'fill',
|
461 |
-
'src' => 'https://placehold.it/300X250',
|
462 |
-
) );
|
463 |
-
$ad_node->appendChild( $fallback_node );
|
464 |
-
|
465 |
-
// If we have a lot of paragraphs, insert before the 4th one.
|
466 |
-
// Otherwise, add it to the end.
|
467 |
-
$p_nodes = $body->getElementsByTagName( 'p' );
|
468 |
-
if ( $p_nodes->length > 6 ) {
|
469 |
-
$p_nodes->item( 4 )->parentNode->insertBefore( $ad_node, $p_nodes->item( 4 ));
|
470 |
-
} else {
|
471 |
-
$body->appendChild( $ad_node );
|
472 |
-
}
|
473 |
-
}
|
474 |
-
}
|
475 |
-
```
|
476 |
-
|
477 |
-
#### Step 2: Load the Sanitizer
|
478 |
-
|
479 |
-
```php
|
480 |
-
add_filter( 'amp_content_sanitizers', 'xyz_amp_add_ad_sanitizer', 10, 2 );
|
481 |
-
|
482 |
-
function xyz_amp_add_ad_sanitizer( $sanitizer_classes, $post ) {
|
483 |
-
require_once( dirname( __FILE__ ) . '/classes/class-ad-inject-sanitizer.php' );
|
484 |
-
$sanitizer_classes[ 'XYZ_AMP_Ad_Injection_Sanitizer' ] = array(); // the array can be used to pass args to your sanitizer and accessed within the class via `$this->args`
|
485 |
-
return $sanitizer_classes;
|
486 |
-
}
|
487 |
-
```
|
488 |
-
|
489 |
-
## Extracting Image Dimensions
|
490 |
-
|
491 |
-
AMP requires images to have width and height attributes. When these attributes aren't present in an image tag, AMP-WP will
|
492 |
-
attempt to determine them for the image.
|
493 |
-
|
494 |
-
### Extraction Methods
|
495 |
-
|
496 |
-
#### Concurrent Dimension Extraction - PHP 5.3+ and cURL
|
497 |
-
If you're using PHP 5.3+ and have the cURL extension installed, AMP-WP will attempt to determine dimensions for all images
|
498 |
-
that need them concurrently. Only the minimum number of bytes required to determine the dimensions for a given image type
|
499 |
-
are retrieved. Dimensions are then cached via transients for subsequent requests. This is the fastest and therefore recommended method.
|
500 |
-
#### Sequential Dimension Extraction - PHP 5.2 or no cURL
|
501 |
-
If you're using PHP 5.2 or do not have the cURL extension installed, AMP-WP will attempt to determine image dimensions
|
502 |
-
sequentially. Only the minimum number of bytes required to determine the dimensions for a given image type are retrieved,
|
503 |
-
but the time it takes to retrieve each image's dimensions sequentially can still add up. Dimensions are then cached via transients for subsequent requests.
|
504 |
-
#### Custom Dimension Extraction
|
505 |
-
You can implement your own image dimension extraction method by adding a callback to the **amp_extract_image_dimensions_batch** filter.
|
506 |
-
|
507 |
-
amp_extract_image_dimensions_batch callback functions take a single argument, *$dimensions* by convention, which is a map/array of image urls to either an array containing the
|
508 |
-
dimensions of the image at the url (if another callback for the filter was able to determine them), or false if the dimensions have yet to be determined, e.g.
|
509 |
-
|
510 |
-
```php
|
511 |
-
array(
|
512 |
-
'http://i0.wp.com/placehold.it/350x150.png' => array(
|
513 |
-
'width' => 350,
|
514 |
-
'height' => 150,
|
515 |
-
),
|
516 |
-
'http://i0.wp.com/placehold.it/1024x768.png' => false,
|
517 |
-
);
|
518 |
-
```
|
519 |
-
Your custom dimension extraction callback would iterate through the mappings contained in this single argument, determining
|
520 |
-
dimensions via your custom method for all image url keys whose values are not arrays of dimensions, e.g.
|
521 |
-
```php
|
522 |
-
function my_custom_dimension_extraction_callback( $dimensions ) {
|
523 |
-
foreach ( $dimensions as $url => $value ) {
|
524 |
-
// Skip if dimensions have already been determined for this image.
|
525 |
-
if ( is_array( $value ) ) {
|
526 |
-
continue;
|
527 |
-
}
|
528 |
-
$width = <YOUR CUSTOM CODE TO DETERMINE WIDTH>
|
529 |
-
$height = <YOUR CUSTOM CODE TO DETERMINE HEIGHT>
|
530 |
-
$dimensions[ $url ] = array(
|
531 |
-
'width' => $width,
|
532 |
-
'height' => $height,
|
533 |
-
);
|
534 |
-
}
|
535 |
-
|
536 |
-
return $dimensions;
|
537 |
-
```
|
538 |
-
Your callback needs to return $dimensions so that the value either cascades to the next callback that was added to the *amp_extract_image_dimensions_batch* filter or is
|
539 |
-
returned to the apply_filter() call (if there are no more unprocessed callbacks).
|
540 |
-
|
541 |
-
The default callback provided by WP-AMP described above, *extract_by_downloading_images*, will fire unless explicitly removed, so be sure
|
542 |
-
to remove it from the callback chain if you don't want it to, e.g.
|
543 |
-
|
544 |
-
```php
|
545 |
-
remove_filter( 'amp_extract_image_dimensions_batch', array( 'AMP_Image_Dimension_Extractor', 'extract_by_downloading_images' ), 999, 1 );
|
546 |
-
````
|
547 |
-
|
548 |
-
**Note that if you previously added a custom dimension extraction callback to the *amp_extract_image_dimensions* filter,
|
549 |
-
you need to update it to hook into the *amp_extract_image_dimensions_batch* filter instead and iterate over the key value
|
550 |
-
pairs in the single argument as per the example above.**
|
551 |
-
|
552 |
-
## Analytics
|
553 |
-
|
554 |
-
There are two options you can follow to include analytics tags in your posts.
|
555 |
-
|
556 |
-
### Plugin Analytics Options
|
557 |
-
|
558 |
-
The plugin defines an analytics option to enable the addition of
|
559 |
-
[amp-analytics](https://www.ampproject.org/docs/reference/components/amp-analytics) in your posts. When the plugin is
|
560 |
-
active, an AMP top-level menu appears in the Dashboard with one inner sub-menu called 'Analytics':
|
561 |
-
|
562 |
-
![AMP Options Menu](https://github.com/Automattic/amp-wp/blob/amedina/amp-analytics-customizer/readme-assets/amp-options-analytics.png)
|
563 |
-
|
564 |
-
Selecting the `Analytics` sub-menu in the AMP options menu takes us to an Analytics Options entry page, where we can
|
565 |
-
define the analytics tags we want to have, by specifying the vendor type (e.g. Parsely), and the associated JSON
|
566 |
-
configuration.
|
567 |
-
|
568 |
-
![AMP Options Menu](https://github.com/Automattic/amp-wp/blob/amedina/amp-analytics-customizer/readme-assets/analytics-option-entries.png)
|
569 |
-
|
570 |
-
Notice that the goal of this option of the plugin is to provide a simple mechanism to insert analytics tags;
|
571 |
-
it provides very simple validation based solely on the validity of the JSON string provided. It is the users
|
572 |
-
responsibility to make sure that the values in the configuration string and the vendor type used are coherent with
|
573 |
-
the analytics requirements of their site . Please review the documentation in the [AMP project ](https://github.com/ampproject/amphtml/blob/master/extensions/amp-analytics/amp-analytics.md) and in [AMPByExample](https://ampbyexample.com/components/amp-analytics/).
|
574 |
-
|
575 |
-
The AMP Analytics options entry form provides a very simple validation feedback mechanism: if the JSON configuration
|
576 |
-
string entered is invalid (i.e. not valid JSON), an error message (in red) is displayed below the title of the
|
577 |
-
options window and the entry form is reloaded:
|
578 |
-
|
579 |
-
![AMP Options Menu](https://github.com/Automattic/amp-wp/blob/amedina/amp-analytics-customizer/readme-assets/invalid-input.png)
|
580 |
-
|
581 |
-
And, if the configuration provided is actually a valid JSON string, a success message (in green) is displayed at the
|
582 |
-
top of the window below the title, and again the entry form is reloaded.
|
583 |
-
|
584 |
-
![AMP Options Menu](https://github.com/Automattic/amp-wp/blob/amedina/amp-analytics-customizer/readme-assets/options-saved.png)
|
585 |
-
|
586 |
-
### Manually
|
587 |
-
|
588 |
-
Alaternatively, you can use the `amp_post_template_analytics` filter:
|
589 |
-
|
590 |
-
```php
|
591 |
-
add_filter( 'amp_post_template_analytics', 'xyz_amp_add_custom_analytics' );
|
592 |
-
function xyz_amp_add_custom_analytics( $analytics ) {
|
593 |
-
if ( ! is_array( $analytics ) ) {
|
594 |
-
$analytics = array();
|
595 |
-
}
|
596 |
-
|
597 |
-
// https://developers.google.com/analytics/devguides/collection/amp-analytics/
|
598 |
-
$analytics['xyz-googleanalytics'] = array(
|
599 |
-
'type' => 'googleanalytics',
|
600 |
-
'attributes' => array(
|
601 |
-
// 'data-credentials' => 'include',
|
602 |
-
),
|
603 |
-
'config_data' => array(
|
604 |
-
'vars' => array(
|
605 |
-
'account' => "UA-XXXXX-Y"
|
606 |
-
),
|
607 |
-
'triggers' => array(
|
608 |
-
'trackPageview' => array(
|
609 |
-
'on' => 'visible',
|
610 |
-
'request' => 'pageview',
|
611 |
-
),
|
612 |
-
),
|
613 |
-
),
|
614 |
-
);
|
615 |
-
|
616 |
-
// https://www.parsely.com/docs/integration/tracking/google-amp.html
|
617 |
-
$analytics['xyz-parsely'] = array(
|
618 |
-
'type' => 'parsely',
|
619 |
-
'attributes' => array(),
|
620 |
-
'config_data' => array(
|
621 |
-
'vars' => array(
|
622 |
-
'apikey' => 'YOUR APIKEY GOES HERE',
|
623 |
-
)
|
624 |
-
),
|
625 |
-
);
|
626 |
-
|
627 |
-
return $analytics;
|
628 |
-
}
|
629 |
-
```
|
630 |
-
|
631 |
-
Each analytics entry must include a unique array key and the following attributes:
|
632 |
-
|
633 |
-
- `type`: `(string)` one of the [valid vendors](https://github.com/ampproject/amphtml/blob/master/extensions/amp-analytics/amp-analytics.md#analytics-vendors) for amp-analytics.
|
634 |
-
- `attributes`: `(array)` any [additional valid attributes](https://github.com/ampproject/amphtml/blob/master/extensions/amp-analytics/amp-analytics.md#attributes) to add to the `amp-analytics` element.
|
635 |
-
- `config_data`: `(array)` the [config data](https://github.com/ampproject/amphtml/blob/master/extensions/amp-analytics/amp-analytics.md#configuration) to include in the `amp-analytics` script tag. This is `json_encode`-d on output.
|
636 |
-
|
637 |
-
## Custom Post Type Support
|
638 |
-
|
639 |
-
By default, the plugin only creates AMP content for posts. You can add support for other post_types using the post_type parameter used when registering the custom post type (assume our post_type is `xyz-review`):
|
640 |
-
|
641 |
-
```php
|
642 |
-
add_action( 'amp_init', 'xyz_amp_add_review_cpt' );
|
643 |
-
function xyz_amp_add_review_cpt() {
|
644 |
-
add_post_type_support( 'xyz-review', AMP_QUERY_VAR );
|
645 |
-
}
|
646 |
-
```
|
647 |
-
|
648 |
-
You'll need to flush your rewrite rules after this.
|
649 |
-
|
650 |
-
If you want a custom template for your post type:
|
651 |
-
|
652 |
-
```php
|
653 |
-
add_filter( 'amp_post_template_file', 'xyz_amp_set_review_template', 10, 3 );
|
654 |
-
|
655 |
-
function xyz_amp_set_review_template( $file, $type, $post ) {
|
656 |
-
if ( 'single' === $type && 'xyz-review' === $post->post_type ) {
|
657 |
-
$file = dirname( __FILE__ ) . '/templates/my-amp-review-template.php';
|
658 |
-
}
|
659 |
-
return $file;
|
660 |
-
}
|
661 |
-
```
|
662 |
-
|
663 |
-
We may provide better ways to handle this in the future.
|
664 |
-
|
665 |
-
## Plugin integrations
|
666 |
-
|
667 |
-
### Jetpack
|
668 |
-
|
669 |
-
Jetpack integration is baked in. More support for things like Related Posts to come.
|
670 |
-
|
671 |
-
### Parse.ly
|
672 |
-
|
673 |
-
[Parse.ly's WordPress plugin](https://wordpress.org/plugins/wp-parsely/) automatically tracks AMP pages when enabled along with this plugin.
|
674 |
-
|
675 |
-
|
676 |
-
### Yoast SEO
|
677 |
-
|
678 |
-
If you're using [Yoast SEO](https://wordpress.org/plugins/wordpress-seo/), check out the companion plugin here: https://github.com/Yoast/yoastseo-amp
|
679 |
-
|
680 |
-
## Compatibility Issues
|
681 |
-
|
682 |
-
The following plugins have been known to cause issues with this plugin:
|
683 |
-
|
684 |
-
- Cloudflare Rocket Loader (modifies the output of the AMP page, which breaks validation.)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
readme.txt
CHANGED
@@ -1,25 +1,34 @@
|
|
1 |
-
=== AMP ===
|
2 |
-
Contributors: batmoo, joen, automattic, potatomaster, albertomedina
|
3 |
Tags: amp, mobile
|
4 |
Requires at least: 4.7
|
5 |
-
Tested up to: 4.
|
6 |
-
Stable tag: 0.
|
7 |
License: GPLv2 or later
|
8 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
|
|
9 |
|
10 |
Enable Accelerated Mobile Pages (AMP) on your WordPress site.
|
11 |
|
12 |
== Description ==
|
13 |
|
14 |
-
This plugin adds support for the [Accelerated Mobile Pages](https://www.ampproject.org) (AMP) Project, which is an
|
15 |
|
16 |
With the plugin active, all posts on your site will have dynamically generated AMP-compatible versions, accessible by appending `/amp/` to the end your post URLs. For example, if your post URL is `http://example.com/2016/01/01/amp-on/`, you can access the AMP version at `http://example.com/2016/01/01/amp-on/amp/`. If you do not have [pretty permalinks](https://codex.wordpress.org/Using_Permalinks#mod_rewrite:_.22Pretty_Permalinks.22) enabled, you can do the same thing by appending `?amp=1`, i.e. `http://example.com/?p=123&=1`
|
17 |
|
18 |
-
Note #1:
|
19 |
|
20 |
Note #2: this plugin only creates AMP content but does not automatically display it to your users when they visit from a mobile device. That is handled by AMP consumers such as Google Search. For more details, see the [AMP Project FAQ](https://www.ampproject.org/docs/support/faqs.html).
|
21 |
|
22 |
-
Follow along with or contribute to the development of this plugin
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
|
24 |
== Installation ==
|
25 |
|
@@ -27,31 +36,23 @@ Follow along with or contribute to the development of this plugin at https://git
|
|
27 |
1. Activate the plugin through the 'Plugins' menu in WordPress
|
28 |
1. You may need to refresh your permalinks by going to `Settings > Permalinks` and tapping the `Save` button.
|
29 |
|
30 |
-
==
|
31 |
-
|
32 |
-
= How do I customize the AMP output for my site? =
|
33 |
-
|
34 |
-
You can tweak a few things like colors from the AMP Customizer. From the Dashboard, go to `Appearance > AMP`.
|
35 |
-
|
36 |
-
For deeper level customizations, please see the readme at https://github.com/Automattic/amp-wp/blob/master/readme.md
|
37 |
-
|
38 |
-
= What about ads and shortcodes and such? =
|
39 |
-
|
40 |
-
Check out https://github.com/Automattic/amp-wp/blob/master/readme.md#handling-media
|
41 |
-
|
42 |
-
= What about analytics? =
|
43 |
-
|
44 |
-
Many plugins are adding AMP support already. If you handling analytics yourself, please see https://github.com/Automattic/amp-wp/blob/master/readme.md#analytics
|
45 |
-
|
46 |
-
= Google Webmaster Tools is reporting validation errors for my site. How do I fix them? =
|
47 |
-
|
48 |
-
The best place to start is to open a new discussion in the [support forum](https://wordpress.org/support/plugin/amp) with details on what the specific validation error is.
|
49 |
|
50 |
-
=
|
51 |
|
52 |
-
A
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
|
54 |
-
|
55 |
|
56 |
= 0.5.1 (2017-08-17) =
|
57 |
|
@@ -167,11 +168,11 @@ A wise green Yoda once said, "Patience you must have, my young padawan." We're w
|
|
167 |
|
168 |
* Breaking change: The new template has changes to markup, class names, and styles that may not work with existing customizations. If you want to stay on the old template for now, you can use the following code snippet:
|
169 |
|
170 |
-
|
171 |
if ( function_exists( 'amp_backcompat_use_v03_templates' ) ) {
|
172 |
-
|
173 |
}
|
174 |
-
|
175 |
|
176 |
For more details, please see https://wordpress.org/support/topic/v0-4-whats-new-and-possible-breaking-changes/
|
177 |
|
1 |
+
=== AMP for WordPress ===
|
2 |
+
Contributors: batmoo, joen, automattic, potatomaster, albertomedina, google, xwp, westonruter
|
3 |
Tags: amp, mobile
|
4 |
Requires at least: 4.7
|
5 |
+
Tested up to: 4.9
|
6 |
+
Stable tag: 0.6.0
|
7 |
License: GPLv2 or later
|
8 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
9 |
+
Requires PHP: 5.2
|
10 |
|
11 |
Enable Accelerated Mobile Pages (AMP) on your WordPress site.
|
12 |
|
13 |
== Description ==
|
14 |
|
15 |
+
This plugin adds support for the [Accelerated Mobile Pages](https://www.ampproject.org) (AMP) Project, which is an open source initiative that aims to provide mobile optimized content that can load instantly everywhere.
|
16 |
|
17 |
With the plugin active, all posts on your site will have dynamically generated AMP-compatible versions, accessible by appending `/amp/` to the end your post URLs. For example, if your post URL is `http://example.com/2016/01/01/amp-on/`, you can access the AMP version at `http://example.com/2016/01/01/amp-on/amp/`. If you do not have [pretty permalinks](https://codex.wordpress.org/Using_Permalinks#mod_rewrite:_.22Pretty_Permalinks.22) enabled, you can do the same thing by appending `?amp=1`, i.e. `http://example.com/?p=123&=1`
|
18 |
|
19 |
+
Note #1: homepage, the blog index, and archives are not currently supported.
|
20 |
|
21 |
Note #2: this plugin only creates AMP content but does not automatically display it to your users when they visit from a mobile device. That is handled by AMP consumers such as Google Search. For more details, see the [AMP Project FAQ](https://www.ampproject.org/docs/support/faqs.html).
|
22 |
|
23 |
+
Follow along with or [contribute](https://github.com/Automattic/amp-wp/blob/develop/contributing.md) to the development of this plugin [on GitHub](https://github.com/Automattic/amp-wp). For more information on the plugin, how the plugin works and how to configure and extend it, please see the [project wiki](https://github.com/Automattic/amp-wp/wiki).
|
24 |
+
|
25 |
+
== Screenshots ==
|
26 |
+
|
27 |
+
1. Post rendered in AMP template.
|
28 |
+
1. Customizing appearance of AMP template.
|
29 |
+
1. Article from New York Post showing customized AMP template.
|
30 |
+
1. Article from TNW showing customized AMP template.
|
31 |
+
1. Article from Halfbrick showing customized AMP template.
|
32 |
|
33 |
== Installation ==
|
34 |
|
36 |
1. Activate the plugin through the 'Plugins' menu in WordPress
|
37 |
1. You may need to refresh your permalinks by going to `Settings > Permalinks` and tapping the `Save` button.
|
38 |
|
39 |
+
== Changelog ==
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
|
41 |
+
= 0.6.0 (2018-01-23) =
|
42 |
|
43 |
+
- Add support for the "page" post type. A new `page.php` is introduced with template parts factored out (`html-start.php`, `header.php`, `footer.php`, `html-end.php`) and re-used from `single.php`. Note that AMP URLs will end in `?amp` instead of `/amp/`. See [#825](https://github.com/Automattic/amp-wp/pull/825). Props technosailor, ThierryA, westonruter.
|
44 |
+
- Add AMP post preview button alongside non-AMP preview button. See [#813](https://github.com/Automattic/amp-wp/pull/813). Props ThierryA, westonruter.
|
45 |
+
- Add ability to disable AMP on a per-post basis via toggle in publish metabox. See [#813](https://github.com/Automattic/amp-wp/pull/813). Props ThierryA, westonruter.
|
46 |
+
- Add AMP settings admin screen for managing which post types have AMP support, eliminating the requirement to add `add_post_type_support()` calls in theme or plugin. See [#811](https://github.com/Automattic/amp-wp/pull/811). Props ThierryA, westonruter.
|
47 |
+
- Add generator meta tag for AMP. See [#810](https://github.com/Automattic/amp-wp/pull/810). Props vaporwavre.
|
48 |
+
- Add code quality checking via phpcs, eslint, jscs, and jshint. See [#795](https://github.com/Automattic/amp-wp/pull/795). Props westonruter.
|
49 |
+
- Add autoloader to reduce complexity. See [#828](https://github.com/Automattic/amp-wp/pull/828). Props mikeschinkel, westonruter, ThierryA.
|
50 |
+
- Fix Polldaddy amd SoundCloud embeds. Add vanilla WordPress "embed" test page. A new `bin/create-embed-test-post.php` wp-cli script is introduced. See [#829](https://github.com/Automattic/amp-wp/pull/829). Props kienstra, westonruter, ThierryA.
|
51 |
+
- Merge AMP Customizer into main Customizer. See [#819](https://github.com/Automattic/amp-wp/pull/819). Props kaitnyl, westonruter.
|
52 |
+
- Update AMP HTML tags and attributes. A new `bin/amphtml-update.sh` bash script is introduced. Fixes Playbuzz. See [#823](https://github.com/Automattic/amp-wp/pull/823). Props kienstra, ThierryA, westonruter.
|
53 |
+
- Remove erroneous hash from id on amp-wp-header. See [#853](https://github.com/Automattic/amp-wp/pull/853). Props eshannon3.
|
54 |
|
55 |
+
See [0.6 milestone](https://github.com/Automattic/amp-wp/milestone/5?closed=1).
|
56 |
|
57 |
= 0.5.1 (2017-08-17) =
|
58 |
|
168 |
|
169 |
* Breaking change: The new template has changes to markup, class names, and styles that may not work with existing customizations. If you want to stay on the old template for now, you can use the following code snippet:
|
170 |
|
171 |
+
<pre lang="php">
|
172 |
if ( function_exists( 'amp_backcompat_use_v03_templates' ) ) {
|
173 |
+
amp_backcompat_use_v03_templates();
|
174 |
}
|
175 |
+
</pre>
|
176 |
|
177 |
For more details, please see https://wordpress.org/support/topic/v0-4-whats-new-and-possible-breaking-changes/
|
178 |
|
screenshot-1.png
DELETED
Binary file
|
screenshot-2.png
DELETED
Binary file
|
screenshot-3.png
DELETED
Binary file
|
screenshot-4.png
DELETED
Binary file
|
screenshot-5.png
DELETED
Binary file
|
templates/admin/amp-status.php
ADDED
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* AMP status option in the submit meta box.
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
// Check referrer.
|
9 |
+
if ( ! ( $this instanceof AMP_Post_Meta_Box ) ) {
|
10 |
+
return;
|
11 |
+
}
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Inherited template vars.
|
15 |
+
*
|
16 |
+
* @var array $labels Labels for enabled or disabled.
|
17 |
+
* @var string $status Enabled or disabled.
|
18 |
+
* @var array $errors Support errors.
|
19 |
+
*/
|
20 |
+
?>
|
21 |
+
<div class="misc-pub-section misc-amp-status">
|
22 |
+
<span class="amp-icon"></span>
|
23 |
+
<?php esc_html_e( 'AMP:', 'amp' ); ?>
|
24 |
+
<strong class="amp-status-text"><?php echo esc_html( $labels[ $status ] ); ?></strong>
|
25 |
+
<a href="#amp_status" class="edit-amp-status hide-if-no-js" role="button">
|
26 |
+
<span aria-hidden="true"><?php esc_html_e( 'Edit', 'amp' ); ?></span>
|
27 |
+
<span class="screen-reader-text"><?php esc_html_e( 'Edit Status', 'amp' ); ?></span>
|
28 |
+
</a>
|
29 |
+
<div id="amp-status-select" class="hide-if-js" data-amp-status="<?php echo esc_attr( $status ); ?>">
|
30 |
+
<?php if ( empty( $errors ) ) : ?>
|
31 |
+
<fieldset>
|
32 |
+
<input id="amp-status-enabled" type="radio" name="<?php echo esc_attr( self::STATUS_INPUT_NAME ); ?>" value="<?php echo esc_attr( self::ENABLED_STATUS ); ?>" <?php checked( self::ENABLED_STATUS, $status ); ?>>
|
33 |
+
<label for="amp-status-enabled" class="selectit"><?php echo esc_html( $labels['enabled'] ); ?></label>
|
34 |
+
<br />
|
35 |
+
<input id="amp-status-disabled" type="radio" name="<?php echo esc_attr( self::STATUS_INPUT_NAME ); ?>" value="<?php echo esc_attr( self::DISABLED_STATUS ); ?>" <?php checked( self::DISABLED_STATUS, $status ); ?>>
|
36 |
+
<label for="amp-status-disabled" class="selectit"><?php echo esc_html( $labels['disabled'] ); ?></label>
|
37 |
+
<br />
|
38 |
+
<?php wp_nonce_field( self::NONCE_ACTION, self::NONCE_NAME ); ?>
|
39 |
+
</fieldset>
|
40 |
+
<?php else : ?>
|
41 |
+
<div class="inline notice notice-warning notice-alt">
|
42 |
+
<p>
|
43 |
+
<?php
|
44 |
+
$support_errors_codes = AMP_Post_Type_Support::get_support_errors( $post );
|
45 |
+
$support_errors = array();
|
46 |
+
if ( in_array( 'password-protected', $support_errors_codes, true ) ) {
|
47 |
+
$support_errors[] = __( 'AMP cannot be enabled on password protected posts.', 'amp' );
|
48 |
+
}
|
49 |
+
if ( in_array( 'post-type-support', $support_errors_codes, true ) ) {
|
50 |
+
/* translators: %s is URL to AMP settings screen */
|
51 |
+
$support_errors[] = wp_kses_post( sprintf( __( 'AMP cannot be enabled because this <a href="%s">post type does not support it</a>.', 'amp' ), admin_url( 'admin.php?page=amp-options' ) ) );
|
52 |
+
}
|
53 |
+
if ( in_array( 'skip-post', $support_errors_codes, true ) ) {
|
54 |
+
$support_errors[] = __( 'A plugin or theme has disabled AMP support.', 'amp' );
|
55 |
+
}
|
56 |
+
if ( count( array_diff( $support_errors_codes, array( 'page-on-front', 'page-for-posts', 'password-protected', 'post-type-support', 'skip-post' ) ) ) > 0 ) {
|
57 |
+
$support_errors[] = __( 'Unavailable for an unknown reason.', 'amp' );
|
58 |
+
}
|
59 |
+
echo implode( ' ', $support_errors ); // WPCS: xss ok.
|
60 |
+
?>
|
61 |
+
</p>
|
62 |
+
</div>
|
63 |
+
<?php endif; ?>
|
64 |
+
<div class="amp-status-actions">
|
65 |
+
<?php if ( empty( $errors ) ) : ?>
|
66 |
+
<a href="#amp_status" class="save-amp-status hide-if-no-js button"><?php esc_html_e( 'OK', 'amp' ); ?></a>
|
67 |
+
<?php endif; ?>
|
68 |
+
<a href="#amp_status" class="cancel-amp-status hide-if-no-js button-cancel"><?php esc_html_e( 'Cancel', 'amp' ); ?></a>
|
69 |
+
</div>
|
70 |
+
</div>
|
71 |
+
</div>
|
templates/footer.php
CHANGED
@@ -1,8 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
<footer class="amp-wp-footer">
|
2 |
<div>
|
3 |
-
<h2><?php echo esc_html( $this->get( 'blog_name' ) ); ?></h2>
|
4 |
<p>
|
5 |
-
<a href="<?php echo esc_url( esc_html__( 'https://wordpress.org/', 'amp' ) ); ?>"
|
|
|
|
|
|
|
|
|
|
|
6 |
</p>
|
7 |
<a href="#top" class="back-to-top"><?php esc_html_e( 'Back to top', 'amp' ); ?></a>
|
8 |
</div>
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Footer template part.
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Context.
|
10 |
+
*
|
11 |
+
* @var AMP_Post_Template $this
|
12 |
+
*/
|
13 |
+
?>
|
14 |
<footer class="amp-wp-footer">
|
15 |
<div>
|
16 |
+
<h2><?php echo esc_html( wptexturize( $this->get( 'blog_name' ) ) ); ?></h2>
|
17 |
<p>
|
18 |
+
<a href="<?php echo esc_url( esc_html__( 'https://wordpress.org/', 'amp' ) ); ?>">
|
19 |
+
<?php
|
20 |
+
// translators: %s is WordPress.
|
21 |
+
echo esc_html( sprintf( __( 'Powered by %s', 'amp' ), 'WordPress' ) );
|
22 |
+
?>
|
23 |
+
</a>
|
24 |
</p>
|
25 |
<a href="#top" class="back-to-top"><?php esc_html_e( 'Back to top', 'amp' ); ?></a>
|
26 |
</div>
|
templates/header-bar.php
CHANGED
@@ -1,11 +1,21 @@
|
|
1 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
<div>
|
3 |
<a href="<?php echo esc_url( $this->get( 'home_url' ) ); ?>">
|
4 |
-
<?php $site_icon_url = $this->get( 'site_icon_url' );
|
5 |
-
if ( $site_icon_url ) : ?>
|
6 |
<amp-img src="<?php echo esc_url( $site_icon_url ); ?>" width="32" height="32" class="amp-wp-site-icon"></amp-img>
|
7 |
<?php endif; ?>
|
8 |
-
|
|
|
|
|
9 |
</a>
|
10 |
</div>
|
11 |
</header>
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Header bar template part.
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
?>
|
9 |
+
<header id="top" class="amp-wp-header">
|
10 |
<div>
|
11 |
<a href="<?php echo esc_url( $this->get( 'home_url' ) ); ?>">
|
12 |
+
<?php $site_icon_url = $this->get( 'site_icon_url' ); ?>
|
13 |
+
<?php if ( $site_icon_url ) : ?>
|
14 |
<amp-img src="<?php echo esc_url( $site_icon_url ); ?>" width="32" height="32" class="amp-wp-site-icon"></amp-img>
|
15 |
<?php endif; ?>
|
16 |
+
<span class="amp-site-title">
|
17 |
+
<?php echo esc_html( wptexturize( $this->get( 'blog_name' ) ) ); ?>
|
18 |
+
</span>
|
19 |
</a>
|
20 |
</div>
|
21 |
</header>
|
templates/header.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Header template part.
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Context.
|
10 |
+
*
|
11 |
+
* @var AMP_Post_Template $this
|
12 |
+
*/
|
13 |
+
|
14 |
+
$this->load_parts( array( 'header-bar' ) );
|
templates/html-end.php
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* HTML end template part.
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Context.
|
10 |
+
*
|
11 |
+
* @var AMP_Post_Template $this
|
12 |
+
*/
|
13 |
+
?>
|
14 |
+
|
15 |
+
<?php do_action( 'amp_post_template_footer', $this ); ?>
|
16 |
+
|
17 |
+
</body>
|
18 |
+
</html>
|
templates/html-start.php
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* HTML start template part.
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Context.
|
10 |
+
*
|
11 |
+
* @var AMP_Post_Template $this
|
12 |
+
*/
|
13 |
+
?>
|
14 |
+
<!doctype html>
|
15 |
+
<html amp <?php echo AMP_HTML_Utils::build_attributes_string( $this->get( 'html_tag_attributes' ) ); // WPCS: XSS ok. ?>>
|
16 |
+
<head>
|
17 |
+
<meta charset="utf-8">
|
18 |
+
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
|
19 |
+
<?php do_action( 'amp_post_template_head', $this ); ?>
|
20 |
+
<style amp-custom>
|
21 |
+
<?php $this->load_parts( array( 'style' ) ); ?>
|
22 |
+
<?php do_action( 'amp_post_template_css', $this ); ?>
|
23 |
+
</style>
|
24 |
+
</head>
|
25 |
+
|
26 |
+
<body class="<?php echo esc_attr( $this->get( 'body_class' ) ); ?>">
|
templates/page.php
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Page view template.
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Context.
|
10 |
+
*
|
11 |
+
* @var AMP_Post_Template $this
|
12 |
+
*/
|
13 |
+
|
14 |
+
$this->load_parts( array( 'html-start' ) );
|
15 |
+
?>
|
16 |
+
|
17 |
+
<?php $this->load_parts( array( 'header' ) ); ?>
|
18 |
+
|
19 |
+
<article class="amp-wp-article">
|
20 |
+
<header class="amp-wp-article-header">
|
21 |
+
<h1 class="amp-wp-title"><?php echo esc_html( $this->get( 'post_title' ) ); ?></h1>
|
22 |
+
</header>
|
23 |
+
|
24 |
+
<?php $this->load_parts( array( 'featured-image' ) ); ?>
|
25 |
+
|
26 |
+
<div class="amp-wp-article-content">
|
27 |
+
<?php echo $this->get( 'post_amp_content' ); // WPCS: XSS ok. Handled in AMP_Content::transform(). ?>
|
28 |
+
</div>
|
29 |
+
</article>
|
30 |
+
|
31 |
+
<?php $this->load_parts( array( 'footer' ) ); ?>
|
32 |
+
|
33 |
+
<?php
|
34 |
+
$this->load_parts( array( 'html-end' ) );
|
templates/single.php
CHANGED
@@ -1,41 +1,39 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
<style amp-custom>
|
8 |
-
<?php $this->load_parts( array( 'style' ) ); ?>
|
9 |
-
<?php do_action( 'amp_post_template_css', $this ); ?>
|
10 |
-
</style>
|
11 |
-
</head>
|
12 |
-
|
13 |
-
<body class="<?php echo esc_attr( $this->get( 'body_class' ) ); ?>">
|
14 |
-
|
15 |
-
<?php $this->load_parts( array( 'header-bar' ) ); ?>
|
16 |
|
17 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
|
|
|
19 |
<header class="amp-wp-article-header">
|
20 |
-
<h1 class="amp-wp-title"><?php echo
|
21 |
<?php $this->load_parts( apply_filters( 'amp_post_article_header_meta', array( 'meta-author', 'meta-time' ) ) ); ?>
|
22 |
</header>
|
23 |
|
24 |
<?php $this->load_parts( array( 'featured-image' ) ); ?>
|
25 |
|
26 |
<div class="amp-wp-article-content">
|
27 |
-
<?php echo $this->get( 'post_amp_content' ); //
|
28 |
</div>
|
29 |
|
30 |
<footer class="amp-wp-article-footer">
|
31 |
<?php $this->load_parts( apply_filters( 'amp_post_article_footer_meta', array( 'meta-taxonomy', 'meta-comments-link' ) ) ); ?>
|
32 |
</footer>
|
33 |
-
|
34 |
</article>
|
35 |
|
36 |
<?php $this->load_parts( array( 'footer' ) ); ?>
|
37 |
|
38 |
-
<?php
|
39 |
-
|
40 |
-
</body>
|
41 |
-
</html>
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Single view template.
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
|
8 |
+
/**
|
9 |
+
* Context.
|
10 |
+
*
|
11 |
+
* @var AMP_Post_Template $this
|
12 |
+
*/
|
13 |
+
|
14 |
+
$this->load_parts( array( 'html-start' ) );
|
15 |
+
?>
|
16 |
+
|
17 |
+
<?php $this->load_parts( array( 'header' ) ); ?>
|
18 |
|
19 |
+
<article class="amp-wp-article">
|
20 |
<header class="amp-wp-article-header">
|
21 |
+
<h1 class="amp-wp-title"><?php echo esc_html( $this->get( 'post_title' ) ); ?></h1>
|
22 |
<?php $this->load_parts( apply_filters( 'amp_post_article_header_meta', array( 'meta-author', 'meta-time' ) ) ); ?>
|
23 |
</header>
|
24 |
|
25 |
<?php $this->load_parts( array( 'featured-image' ) ); ?>
|
26 |
|
27 |
<div class="amp-wp-article-content">
|
28 |
+
<?php echo $this->get( 'post_amp_content' ); // WPCS: XSS ok. Handled in AMP_Content::transform(). ?>
|
29 |
</div>
|
30 |
|
31 |
<footer class="amp-wp-article-footer">
|
32 |
<?php $this->load_parts( apply_filters( 'amp_post_article_footer_meta', array( 'meta-taxonomy', 'meta-comments-link' ) ) ); ?>
|
33 |
</footer>
|
|
|
34 |
</article>
|
35 |
|
36 |
<?php $this->load_parts( array( 'footer' ) ); ?>
|
37 |
|
38 |
+
<?php
|
39 |
+
$this->load_parts( array( 'html-end' ) );
|
|
|
|
templates/style.php
CHANGED
@@ -1,8 +1,17 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
|
5 |
-
|
6 |
$theme_color = $this->get_customizer_setting( 'theme_color' );
|
7 |
$text_color = $this->get_customizer_setting( 'text_color' );
|
8 |
$muted_text_color = $this->get_customizer_setting( 'muted_text_color' );
|
@@ -160,7 +169,7 @@ blockquote p:last-child {
|
|
160 |
display: flex;
|
161 |
flex-wrap: wrap;
|
162 |
justify-content: space-between;
|
163 |
-
margin: 1.5em 16px
|
164 |
}
|
165 |
|
166 |
.amp-wp-title {
|
@@ -180,7 +189,7 @@ blockquote p:last-child {
|
|
180 |
flex: 2 1 50%;
|
181 |
font-size: .875em;
|
182 |
line-height: 1.5em;
|
183 |
-
margin: 0;
|
184 |
padding: 0;
|
185 |
}
|
186 |
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Style template.
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Context.
|
10 |
+
*
|
11 |
+
* @var AMP_Post_Template $this
|
12 |
+
*/
|
13 |
|
14 |
+
$content_max_width = absint( $this->get( 'content_max_width' ) );
|
15 |
$theme_color = $this->get_customizer_setting( 'theme_color' );
|
16 |
$text_color = $this->get_customizer_setting( 'text_color' );
|
17 |
$muted_text_color = $this->get_customizer_setting( 'muted_text_color' );
|
169 |
display: flex;
|
170 |
flex-wrap: wrap;
|
171 |
justify-content: space-between;
|
172 |
+
margin: 1.5em 16px 0;
|
173 |
}
|
174 |
|
175 |
.amp-wp-title {
|
189 |
flex: 2 1 50%;
|
190 |
font-size: .875em;
|
191 |
line-height: 1.5em;
|
192 |
+
margin: 0 0 1.5em;
|
193 |
padding: 0;
|
194 |
}
|
195 |
|
wpcom-helper.php
ADDED
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// WPCOM-specific things
|
4 |
+
add_action( 'pre_amp_render_post', 'jetpack_amp_disable_the_content_filters' );
|
5 |
+
|
6 |
+
// Disable admin menu
|
7 |
+
add_filter( 'amp_options_menu_is_enabled', '__return_false', 9999 );
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Disable the_content filters for Jetpack.
|
11 |
+
*
|
12 |
+
* @param int $post_id Post ID.
|
13 |
+
*/
|
14 |
+
function jetpack_amp_disable_the_content_filters( $post_id ) {
|
15 |
+
add_filter( 'post_flair_disable', '__return_true', 99 );
|
16 |
+
add_filter( 'videopress_show_2015_player', '__return_true' );
|
17 |
+
add_filter( 'protected_embeds_use_form_post', '__return_false' );
|
18 |
+
|
19 |
+
remove_filter( 'the_title', 'widont' );
|
20 |
+
|
21 |
+
remove_filter( 'pre_kses', array( 'Filter_Embedded_HTML_Objects', 'filter' ), 11 );
|
22 |
+
remove_filter( 'pre_kses', array( 'Filter_Embedded_HTML_Objects', 'maybe_create_links' ), 100 );
|
23 |
+
}
|
24 |
+
|
25 |
+
add_action( 'amp_post_template_head', 'jetpack_amp_add_og_tags' );
|
26 |
+
|
27 |
+
function jetpack_amp_add_og_tags( $amp_template ) {
|
28 |
+
if ( function_exists( 'jetpack_og_tags' ) ) {
|
29 |
+
jetpack_og_tags();
|
30 |
+
}
|
31 |
+
}
|
32 |
+
|
33 |
+
add_filter( 'amp_post_template_metadata', 'jetpack_amp_post_template_metadata', 10, 2 );
|
34 |
+
|
35 |
+
function jetpack_amp_post_template_metadata( $metadata, $post ) {
|
36 |
+
if ( isset( $metadata['publisher'] ) && ! isset( $metadata['publisher']['logo'] ) ) {
|
37 |
+
$metadata = wpcom_amp_add_blavatar_to_metadata( $metadata, $post );
|
38 |
+
}
|
39 |
+
|
40 |
+
if ( ! isset( $metadata['image'] ) ) {
|
41 |
+
$metadata = wpcom_amp_add_image_to_metadata( $metadata, $post );
|
42 |
+
}
|
43 |
+
|
44 |
+
return $metadata;
|
45 |
+
}
|
46 |
+
|
47 |
+
function wpcom_amp_add_blavatar_to_metadata( $metadata, $post ) {
|
48 |
+
if ( ! function_exists( 'blavatar_domain' ) ) {
|
49 |
+
return $metadata;
|
50 |
+
}
|
51 |
+
|
52 |
+
$size = 60;
|
53 |
+
$metadata['publisher']['logo'] = array(
|
54 |
+
'@type' => 'ImageObject',
|
55 |
+
'url' => blavatar_url( blavatar_domain( site_url() ), 'img', $size, staticize_subdomain( 'https://wordpress.com/i/favicons/apple-touch-icon-60x60.png' ) ),
|
56 |
+
'width' => $size,
|
57 |
+
'height' => $size,
|
58 |
+
);
|
59 |
+
|
60 |
+
return $metadata;
|
61 |
+
}
|
62 |
+
|
63 |
+
function wpcom_amp_add_image_to_metadata( $metadata, $post ) {
|
64 |
+
if ( ! class_exists( 'Jetpack_PostImages' ) ) {
|
65 |
+
return wpcom_amp_add_fallback_image_to_metadata( $metadata );
|
66 |
+
}
|
67 |
+
|
68 |
+
$image = Jetpack_PostImages::get_image( $post->ID, array(
|
69 |
+
'fallback_to_avatars' => true,
|
70 |
+
'avatar_size' => 200,
|
71 |
+
// AMP already attempts these
|
72 |
+
'from_thumbnail' => false,
|
73 |
+
'from_attachment' => false,
|
74 |
+
) );
|
75 |
+
|
76 |
+
if ( empty( $image ) ) {
|
77 |
+
return wpcom_amp_add_fallback_image_to_metadata( $metadata );
|
78 |
+
}
|
79 |
+
|
80 |
+
if ( ! isset( $image['src_width'] ) ) {
|
81 |
+
$dimensions = wpcom_amp_extract_image_dimensions_from_getimagesize( array(
|
82 |
+
$image['src'] => false,
|
83 |
+
)
|
84 |
+
);
|
85 |
+
|
86 |
+
if ( false !== $dimensions[ $image['src'] ] ) {
|
87 |
+
$image['src_width'] = $dimensions['width'];
|
88 |
+
$image['src_height'] = $dimensions['height'];
|
89 |
+
}
|
90 |
+
}
|
91 |
+
|
92 |
+
$metadata['image'] = array(
|
93 |
+
'@type' => 'ImageObject',
|
94 |
+
'url' => $image['src'],
|
95 |
+
'width' => $image['src_width'],
|
96 |
+
'height' => $image['src_height'],
|
97 |
+
);
|
98 |
+
|
99 |
+
return $metadata;
|
100 |
+
}
|
101 |
+
|
102 |
+
function wpcom_amp_add_fallback_image_to_metadata( $metadata ) {
|
103 |
+
$metadata['image'] = array(
|
104 |
+
'@type' => 'ImageObject',
|
105 |
+
'url' => staticize_subdomain( 'https://wordpress.com/i/blank.jpg' ),
|
106 |
+
'width' => 200,
|
107 |
+
'height' => 200,
|
108 |
+
);
|
109 |
+
|
110 |
+
return $metadata;
|
111 |
+
}
|
112 |
+
|
113 |
+
add_action( 'amp_extract_image_dimensions_batch_callbacks_registered', 'wpcom_amp_extract_image_dimensions_batch_add_custom_callbacks' );
|
114 |
+
function wpcom_amp_extract_image_dimensions_batch_add_custom_callbacks() {
|
115 |
+
// If images are being served from Photon or WP.com files, try extracting the size using querystring.
|
116 |
+
add_action( 'amp_extract_image_dimensions_batch', 'wpcom_amp_extract_image_dimensions_from_querystring', 9, 1 ); // Hook in before the default extractors.
|
117 |
+
|
118 |
+
// Uses a special wpcom lib (wpcom_getimagesize) to extract dimensions as a last resort if we weren't able to figure them out.
|
119 |
+
add_action( 'amp_extract_image_dimensions_batch', 'wpcom_amp_extract_image_dimensions_from_getimagesize', 99, 1 ); // Our last resort, so run late
|
120 |
+
|
121 |
+
// The wpcom override obviates this one, so take it out.
|
122 |
+
remove_filter( 'amp_extract_image_dimensions_batch', array( 'AMP_Image_Dimension_Extractor', 'extract_by_downloading_images' ), 999, 1 );
|
123 |
+
}
|
124 |
+
|
125 |
+
function wpcom_amp_extract_image_dimensions_from_querystring( $dimensions ) {
|
126 |
+
foreach ( $dimensions as $url => $value ) {
|
127 |
+
|
128 |
+
if ( is_array( $value ) ) {
|
129 |
+
continue;
|
130 |
+
}
|
131 |
+
|
132 |
+
$host = parse_url( $url, PHP_URL_HOST );
|
133 |
+
if ( ! wp_endswith( $host, '.wp.com' ) || ! wp_endswith( $host, '.files.wordpress.com' ) ) {
|
134 |
+
continue;
|
135 |
+
}
|
136 |
+
|
137 |
+
parse_str( parse_url( $url, PHP_URL_QUERY ), $query );
|
138 |
+
$w = isset( $query['w'] ) ? absint( $query['w'] ) : false;
|
139 |
+
$h = isset( $query['h'] ) ? absint( $query['h'] ) : false;
|
140 |
+
|
141 |
+
if ( false !== $w && false !== $h ) {
|
142 |
+
$dimensions[ $url ] = array(
|
143 |
+
'width' => $w,
|
144 |
+
'height' => $h,
|
145 |
+
);
|
146 |
+
}
|
147 |
+
}
|
148 |
+
return $dimensions;
|
149 |
+
}
|
150 |
+
|
151 |
+
function wpcom_amp_extract_image_dimensions_from_getimagesize( $dimensions ) {
|
152 |
+
if ( ! function_exists( 'require_lib' ) ) {
|
153 |
+
return $dimensions;
|
154 |
+
}
|
155 |
+
require_lib( 'wpcom/imagesize' );
|
156 |
+
|
157 |
+
foreach ( $dimensions as $url => $value ) {
|
158 |
+
if ( is_array( $value ) ) {
|
159 |
+
continue;
|
160 |
+
}
|
161 |
+
$result = wpcom_getimagesize( $url );
|
162 |
+
if ( is_array( $result ) ) {
|
163 |
+
$dimensions[ $url ] = array(
|
164 |
+
'width' => $result[0],
|
165 |
+
'height' => $result[1],
|
166 |
+
);
|
167 |
+
}
|
168 |
+
}
|
169 |
+
|
170 |
+
return $dimensions;
|
171 |
+
}
|
wpcom/class-amp-polldaddy-embed.php
ADDED
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class WPCOM_AMP_Polldaddy_Embed
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class WPCOM_AMP_Polldaddy_Embed
|
10 |
+
*/
|
11 |
+
class WPCOM_AMP_Polldaddy_Embed extends AMP_Base_Embed_Handler {
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Register embed.
|
15 |
+
*/
|
16 |
+
public function register_embed() {
|
17 |
+
add_shortcode( 'polldaddy', array( $this, 'shortcode' ) );
|
18 |
+
add_filter( 'embed_oembed_html', array( $this, 'filter_embed_oembed_html' ), 10, 3 );
|
19 |
+
}
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Unregister embed.
|
23 |
+
*/
|
24 |
+
public function unregister_embed() {
|
25 |
+
remove_shortcode( 'polldaddy' );
|
26 |
+
remove_filter( 'embed_oembed_html', array( $this, 'filter_embed_oembed_html' ), 10 );
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Shortcode.
|
31 |
+
*
|
32 |
+
* @param array $attr Shortcode attributes.
|
33 |
+
* @return string Shortcode.
|
34 |
+
* @global WP_Embed $wp_embed
|
35 |
+
*/
|
36 |
+
public function shortcode( $attr ) {
|
37 |
+
global $wp_embed;
|
38 |
+
|
39 |
+
$output = '';
|
40 |
+
$url = 'https://polldaddy.com/';
|
41 |
+
if ( ! empty( $attr['poll'] ) ) {
|
42 |
+
$url .= 'poll/' . $attr['poll'] . '/';
|
43 |
+
} elseif ( ! empty( $attr['survey'] ) ) {
|
44 |
+
$url .= 's/' . $attr['survey'] . '/';
|
45 |
+
}
|
46 |
+
|
47 |
+
if ( ! empty( $attr['title'] ) ) {
|
48 |
+
$output = $this->render_link( $url, $attr['title'] );
|
49 |
+
} elseif ( $url ) {
|
50 |
+
$output = $wp_embed->shortcode( $attr, $url );
|
51 |
+
}
|
52 |
+
|
53 |
+
return $output;
|
54 |
+
}
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Filter oEmbed HTML for PollDaddy to for AMP output.
|
58 |
+
*
|
59 |
+
* @param string $cache Cache for oEmbed.
|
60 |
+
* @param string $url Embed URL.
|
61 |
+
* @param array $attr Shortcode attributes.
|
62 |
+
* @return string Embed.
|
63 |
+
*/
|
64 |
+
public function filter_embed_oembed_html( $cache, $url, $attr ) {
|
65 |
+
$parsed_url = wp_parse_url( $url );
|
66 |
+
if ( false === strpos( $parsed_url['host'], 'polldaddy.com' ) ) {
|
67 |
+
return $cache;
|
68 |
+
}
|
69 |
+
|
70 |
+
$output = '';
|
71 |
+
|
72 |
+
// Poll oEmbed responses include noscript.
|
73 |
+
if ( preg_match( '#<noscript>(.+?)</noscript>#', $cache, $matches ) ) {
|
74 |
+
$output = $matches[1];
|
75 |
+
}
|
76 |
+
|
77 |
+
if ( empty( $output ) ) {
|
78 |
+
if ( ! empty( $attr['title'] ) ) {
|
79 |
+
$name = $attr['title'];
|
80 |
+
} elseif ( false !== strpos( $url, 'polldaddy.com/s' ) ) {
|
81 |
+
$name = __( 'View Survey', 'amp' );
|
82 |
+
} else {
|
83 |
+
$name = __( 'View Poll', 'amp' );
|
84 |
+
}
|
85 |
+
$output = $this->render_link( $url, $name );
|
86 |
+
}
|
87 |
+
|
88 |
+
return $output;
|
89 |
+
}
|
90 |
+
|
91 |
+
/**
|
92 |
+
* Render poll/survey link.
|
93 |
+
*
|
94 |
+
* @param string $url Link URL.
|
95 |
+
* @param string $title Link Text.
|
96 |
+
* @return string Link.
|
97 |
+
*/
|
98 |
+
private function render_link( $url, $title ) {
|
99 |
+
return sprintf( '<p><a href="' . esc_url( $url ) . '">' . esc_html( $title ) . '</a></p>' );
|
100 |
+
}
|
101 |
+
}
|
wpcom/shortcodes.php
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Shortcode functions for WordPress.com.
|
4 |
+
*
|
5 |
+
* @package AMP
|
6 |
+
*/
|
7 |
+
|
8 |
+
_deprecated_file( __FILE__, '0.6' );
|
9 |
+
|
10 |
+
/**
|
11 |
+
* Add custom embeds for WordPress.com.
|
12 |
+
*
|
13 |
+
* @deprecated Now PollDaddy is supported in core AMP.
|
14 |
+
* @param array $embed_handler_classes Embed handler classes.
|
15 |
+
* @return mixed
|
16 |
+
*/
|
17 |
+
function wpcom_amp_add_custom_embeds( $embed_handler_classes ) {
|
18 |
+
_deprecated_function( __FUNCTION__, '0.6' );
|
19 |
+
return $embed_handler_classes;
|
20 |
+
}
|