From 2fda05e4946a0e83fece3e36d7ad6356c086a132 Mon Sep 17 00:00:00 2001 From: Kaitlyn Date: Tue, 23 Jan 2018 00:06:49 -0400 Subject: [PATCH 01/16] Issuu, WP post, and WP plugin embed output updates. --- includes/amp-helper-functions.php | 1 + includes/class-amp-autoloader.php | 1 + includes/embeds/class-amp-issuu-embed.php | 83 +++++++++++++++++++++++ templates/style.php | 4 ++ 4 files changed, 89 insertions(+) create mode 100644 includes/embeds/class-amp-issuu-embed.php diff --git a/includes/amp-helper-functions.php b/includes/amp-helper-functions.php index 09db228b946..2456f694e7f 100644 --- a/includes/amp-helper-functions.php +++ b/includes/amp-helper-functions.php @@ -141,6 +141,7 @@ function amp_get_content_embed_handlers( $post = null ) { 'AMP_Vimeo_Embed_Handler' => array(), 'AMP_SoundCloud_Embed_Handler' => array(), 'AMP_Instagram_Embed_Handler' => array(), + 'AMP_Issuu_Embed_Handler' => array(), 'AMP_Vine_Embed_Handler' => array(), 'AMP_Facebook_Embed_Handler' => array(), 'AMP_Pinterest_Embed_Handler' => array(), diff --git a/includes/class-amp-autoloader.php b/includes/class-amp-autoloader.php index 05bbf021b9d..7d5248fd9c2 100644 --- a/includes/class-amp-autoloader.php +++ b/includes/class-amp-autoloader.php @@ -38,6 +38,7 @@ class AMP_Autoloader { 'AMP_Facebook_Embed_Handler' => 'includes/embeds/class-amp-facebook-embed', 'AMP_Gallery_Embed_Handler' => 'includes/embeds/class-amp-gallery-embed', 'AMP_Instagram_Embed_Handler' => 'includes/embeds/class-amp-instagram-embed', + 'AMP_Issuu_Embed_Handler' => 'includes/embeds/class-amp-issuu-embed', 'AMP_Pinterest_Embed_Handler' => 'includes/embeds/class-amp-pinterest-embed', 'AMP_SoundCloud_Embed_Handler' => 'includes/embeds/class-amp-soundcloud-embed', 'AMP_Twitter_Embed_Handler' => 'includes/embeds/class-amp-twitter-embed', diff --git a/includes/embeds/class-amp-issuu-embed.php b/includes/embeds/class-amp-issuu-embed.php new file mode 100644 index 00000000000..14482519714 --- /dev/null +++ b/includes/embeds/class-amp-issuu-embed.php @@ -0,0 +1,83 @@ +render( array( 'url' => $url ) ); + } + + /** + * Output the Issuu iframe. + * + * @param array $args parameters used for output. + */ + public function render( $args ) { + $args = wp_parse_args( $args, array( + 'url' => false, + ) ); + + if ( empty( $args['url'] ) ) { + return ''; + } + + return AMP_HTML_Utils::build_tag( + 'amp-iframe', + array( + 'width' => $this->args['width'], + 'height' => $this->args['height'], + 'src' => $args['url'], + 'sandbox' => 'allow-scripts allow-same-origin', + ) + ); + } +} + diff --git a/templates/style.php b/templates/style.php index a9ccc9a3a93..b1d16668674 100644 --- a/templates/style.php +++ b/templates/style.php @@ -99,6 +99,10 @@ padding: 16px; } +blockquote.wp-embedded-content { + display: none; +} + blockquote p:last-child { margin-bottom: 0; } From 754fe9756bcbe8d2bc35fde6d625f0d4bd1e1467 Mon Sep 17 00:00:00 2001 From: Kaitlyn Date: Tue, 23 Jan 2018 01:16:03 -0400 Subject: [PATCH 02/16] Reddit and Tumblr embeds added. --- includes/amp-helper-functions.php | 2 + includes/class-amp-autoloader.php | 2 + includes/embeds/class-amp-issuu-embed.php | 14 ---- includes/embeds/class-amp-reddit-embed.php | 98 ++++++++++++++++++++++ includes/embeds/class-amp-tumblr-embed.php | 71 ++++++++++++++++ 5 files changed, 173 insertions(+), 14 deletions(-) create mode 100644 includes/embeds/class-amp-reddit-embed.php create mode 100644 includes/embeds/class-amp-tumblr-embed.php diff --git a/includes/amp-helper-functions.php b/includes/amp-helper-functions.php index 2456f694e7f..ddb794295ee 100644 --- a/includes/amp-helper-functions.php +++ b/includes/amp-helper-functions.php @@ -145,6 +145,8 @@ function amp_get_content_embed_handlers( $post = null ) { 'AMP_Vine_Embed_Handler' => array(), 'AMP_Facebook_Embed_Handler' => array(), 'AMP_Pinterest_Embed_Handler' => array(), + 'AMP_Reddit_Embed_Handler' => array(), + 'AMP_Tumblr_Embed_Handler' => array(), 'AMP_Gallery_Embed_Handler' => array(), 'WPCOM_AMP_Polldaddy_Embed' => array(), ), diff --git a/includes/class-amp-autoloader.php b/includes/class-amp-autoloader.php index 7d5248fd9c2..cd1e6d83b48 100644 --- a/includes/class-amp-autoloader.php +++ b/includes/class-amp-autoloader.php @@ -40,7 +40,9 @@ class AMP_Autoloader { 'AMP_Instagram_Embed_Handler' => 'includes/embeds/class-amp-instagram-embed', 'AMP_Issuu_Embed_Handler' => 'includes/embeds/class-amp-issuu-embed', 'AMP_Pinterest_Embed_Handler' => 'includes/embeds/class-amp-pinterest-embed', + 'AMP_Reddit_Embed_Handler' => 'includes/embeds/class-amp-reddit-embed', 'AMP_SoundCloud_Embed_Handler' => 'includes/embeds/class-amp-soundcloud-embed', + 'AMP_Tumblr_Embed_Handler' => 'includes/embeds/class-amp-tumblr-embed', 'AMP_Twitter_Embed_Handler' => 'includes/embeds/class-amp-twitter-embed', 'AMP_Vimeo_Embed_Handler' => 'includes/embeds/class-amp-vimeo-embed', 'AMP_Vine_Embed_Handler' => 'includes/embeds/class-amp-vine-embed', diff --git a/includes/embeds/class-amp-issuu-embed.php b/includes/embeds/class-amp-issuu-embed.php index 14482519714..b50925c34d6 100644 --- a/includes/embeds/class-amp-issuu-embed.php +++ b/includes/embeds/class-amp-issuu-embed.php @@ -16,20 +16,6 @@ class AMP_Issuu_Embed_Handler extends AMP_Base_Embed_Handler { */ const URL_PATTERN = '#https?://(www\.)?issuu\.com/.+/docs/.+#i'; - /** - * Default width for Issuu embeds. - * - * @var int - */ - protected $DEFAULT_WIDTH = 525; - - /** - * Default height for Issuu embeds. - * - * @var int - */ - protected $DEFAULT_HEIGHT = 340; - /** * Register embed. */ diff --git a/includes/embeds/class-amp-reddit-embed.php b/includes/embeds/class-amp-reddit-embed.php new file mode 100644 index 00000000000..1c45f9eabee --- /dev/null +++ b/includes/embeds/class-amp-reddit-embed.php @@ -0,0 +1,98 @@ + self::$script_src ); + } + + /** + * Embed found with matching URL callback. + * + * @param array $matches URL regex matches. + * @param array $attr Additional parameters. + * @param array $url URL. + */ + public function oembed( $matches, $attr, $url ) { + return $this->render( array( 'url' => $url ) ); + } + + /** + * Output the Reddit amp element. + * + * @param array $args parameters used for output. + */ + public function render( $args ) { + $args = wp_parse_args( $args, array( + 'url' => false, + ) ); + + if ( empty( $args['url'] ) ) { + return ''; + } + + return AMP_HTML_Utils::build_tag( + 'amp-reddit', + array( + 'layout' => 'responsive', + 'data-embedtype' => 'post', + 'width' => $this->args['width'], + 'height' => $this->args['height'], + 'data-src' => $args['url'], + ) + ); + } +} + diff --git a/includes/embeds/class-amp-tumblr-embed.php b/includes/embeds/class-amp-tumblr-embed.php new file mode 100644 index 00000000000..1dbc8dd7564 --- /dev/null +++ b/includes/embeds/class-amp-tumblr-embed.php @@ -0,0 +1,71 @@ +render( array( 'url' => $url ) ); + } + + /** + * Output the Tumblr iframe. + * + * @param array $args parameters used for output. + */ + public function render( $args ) { + $args = wp_parse_args( $args, array( + 'url' => false, + ) ); + + if ( empty( $args['url'] ) ) { + return ''; + } + + // Must enforce https for amp-iframe, but editors can supply either on desktop. + $args['url'] = str_replace( 'http://', 'https://', $args['url'] ); + + return AMP_HTML_Utils::build_tag( + 'amp-iframe', + array( + 'width' => $this->args['width'], + 'height' => $this->args['height'], + 'src' => $args['url'], + ) + ); + } +} + From 657b227e41d2e6952f82639bd1cd65fc0a4526c8 Mon Sep 17 00:00:00 2001 From: Kaitlyn Date: Tue, 23 Jan 2018 01:40:28 -0400 Subject: [PATCH 03/16] New files to use correct comment formatting. --- includes/embeds/class-amp-issuu-embed.php | 6 +++--- includes/embeds/class-amp-reddit-embed.php | 10 +++++----- includes/embeds/class-amp-tumblr-embed.php | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/includes/embeds/class-amp-issuu-embed.php b/includes/embeds/class-amp-issuu-embed.php index b50925c34d6..441520770f1 100644 --- a/includes/embeds/class-amp-issuu-embed.php +++ b/includes/embeds/class-amp-issuu-embed.php @@ -1,14 +1,14 @@ Date: Tue, 23 Jan 2018 02:38:34 -0400 Subject: [PATCH 04/16] Update file names to follow class names. --- includes/class-amp-autoloader.php | 6 +++--- ...mp-issuu-embed.php => class-amp-issuu-embed-handler.php} | 6 +++--- ...-reddit-embed.php => class-amp-reddit-embed-handler.php} | 6 +++--- ...-tumblr-embed.php => class-amp-tumblr-embed-handler.php} | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) rename includes/embeds/{class-amp-issuu-embed.php => class-amp-issuu-embed-handler.php} (90%) rename includes/embeds/{class-amp-reddit-embed.php => class-amp-reddit-embed-handler.php} (93%) rename includes/embeds/{class-amp-tumblr-embed.php => class-amp-tumblr-embed-handler.php} (90%) diff --git a/includes/class-amp-autoloader.php b/includes/class-amp-autoloader.php index cd1e6d83b48..ce4037379fa 100644 --- a/includes/class-amp-autoloader.php +++ b/includes/class-amp-autoloader.php @@ -38,11 +38,11 @@ class AMP_Autoloader { 'AMP_Facebook_Embed_Handler' => 'includes/embeds/class-amp-facebook-embed', 'AMP_Gallery_Embed_Handler' => 'includes/embeds/class-amp-gallery-embed', 'AMP_Instagram_Embed_Handler' => 'includes/embeds/class-amp-instagram-embed', - 'AMP_Issuu_Embed_Handler' => 'includes/embeds/class-amp-issuu-embed', + 'AMP_Issuu_Embed_Handler' => 'includes/embeds/class-amp-issuu-embed-handler', 'AMP_Pinterest_Embed_Handler' => 'includes/embeds/class-amp-pinterest-embed', - 'AMP_Reddit_Embed_Handler' => 'includes/embeds/class-amp-reddit-embed', + 'AMP_Reddit_Embed_Handler' => 'includes/embeds/class-amp-reddit-embed-handler', 'AMP_SoundCloud_Embed_Handler' => 'includes/embeds/class-amp-soundcloud-embed', - 'AMP_Tumblr_Embed_Handler' => 'includes/embeds/class-amp-tumblr-embed', + 'AMP_Tumblr_Embed_Handler' => 'includes/embeds/class-amp-tumblr-embed-handler', 'AMP_Twitter_Embed_Handler' => 'includes/embeds/class-amp-twitter-embed', 'AMP_Vimeo_Embed_Handler' => 'includes/embeds/class-amp-vimeo-embed', 'AMP_Vine_Embed_Handler' => 'includes/embeds/class-amp-vine-embed', diff --git a/includes/embeds/class-amp-issuu-embed.php b/includes/embeds/class-amp-issuu-embed-handler.php similarity index 90% rename from includes/embeds/class-amp-issuu-embed.php rename to includes/embeds/class-amp-issuu-embed-handler.php index 441520770f1..b50925c34d6 100644 --- a/includes/embeds/class-amp-issuu-embed.php +++ b/includes/embeds/class-amp-issuu-embed-handler.php @@ -1,14 +1,14 @@ Date: Tue, 23 Jan 2018 02:46:36 -0400 Subject: [PATCH 05/16] Remove variable overrides and use inline to avoid updating all parent/child classes. --- .../embeds/class-amp-reddit-embed-handler.php | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/includes/embeds/class-amp-reddit-embed-handler.php b/includes/embeds/class-amp-reddit-embed-handler.php index aa8164ad7e6..8e18405bf12 100644 --- a/includes/embeds/class-amp-reddit-embed-handler.php +++ b/includes/embeds/class-amp-reddit-embed-handler.php @@ -16,20 +16,6 @@ class AMP_Reddit_Embed_Handler extends AMP_Base_Embed_Handler { */ const URL_PATTERN = '#https?://(www\.)?reddit\.com/r/[^/]+/comments/.*#i'; - /** - * Default width for Reddit embeds. - * - * @var int - */ - protected $DEFAULT_WIDTH = 596; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.MemberNotSnakeCase. - - /** - * Default height for Reddit embeds. - * - * @var int - */ - protected $DEFAULT_HEIGHT = 141; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.MemberNotSnakeCase. - /** * Script slug. * @@ -88,8 +74,8 @@ public function render( $args ) { array( 'layout' => 'responsive', 'data-embedtype' => 'post', - 'width' => $this->args['width'], - 'height' => $this->args['height'], + 'width' => '596', + 'height' => '141', 'data-src' => $args['url'], ) ); From eefdb70588deb032226fac9f8e20fc4778b0e322 Mon Sep 17 00:00:00 2001 From: Kaitlyn Date: Fri, 26 Jan 2018 17:56:53 -0400 Subject: [PATCH 06/16] Add @since to each new class doc, remove script include from Reddit embed, and use class vars for height/width. --- .../embeds/class-amp-issuu-embed-handler.php | 1 + .../embeds/class-amp-reddit-embed-handler.php | 25 ++++++++++--------- .../embeds/class-amp-tumblr-embed-handler.php | 1 + 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/includes/embeds/class-amp-issuu-embed-handler.php b/includes/embeds/class-amp-issuu-embed-handler.php index b50925c34d6..31826594ff4 100644 --- a/includes/embeds/class-amp-issuu-embed-handler.php +++ b/includes/embeds/class-amp-issuu-embed-handler.php @@ -3,6 +3,7 @@ * Class AMP_Issuu_Embed_Handler * * @package AMP + * @since 0.7 */ /** diff --git a/includes/embeds/class-amp-reddit-embed-handler.php b/includes/embeds/class-amp-reddit-embed-handler.php index 8e18405bf12..a9322ace5c9 100644 --- a/includes/embeds/class-amp-reddit-embed-handler.php +++ b/includes/embeds/class-amp-reddit-embed-handler.php @@ -3,6 +3,7 @@ * Class AMP_Reddit_Embed_Handler * * @package AMP + * @since 0.7 */ /** @@ -17,11 +18,18 @@ class AMP_Reddit_Embed_Handler extends AMP_Base_Embed_Handler { const URL_PATTERN = '#https?://(www\.)?reddit\.com/r/[^/]+/comments/.*#i'; /** - * Script slug. + * Default height. * - * @var string + * @var int */ - private static $script_src = 'https://cdn.ampproject.org/v0/amp-reddit-0.1.js'; + protected $DEFAULT_HEIGHT = 141; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.MemberNotSnakeCase + + /** + * Default width. + * + * @var int + */ + protected $DEFAULT_WIDTH = 596; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.MemberNotSnakeCase /** * Register embed. @@ -37,13 +45,6 @@ public function unregister_embed() { wp_embed_unregister_handler( 'amp-reddit' ); } - /** - * Include the required AMP Reddit scripts. - */ - public function get_scripts() { - return array( 'amp-reddit' => self::$script_src ); - } - /** * Embed found with matching URL callback. * @@ -74,8 +75,8 @@ public function render( $args ) { array( 'layout' => 'responsive', 'data-embedtype' => 'post', - 'width' => '596', - 'height' => '141', + 'width' => $this->args['width'], + 'height' => $this->args['height'], 'data-src' => $args['url'], ) ); diff --git a/includes/embeds/class-amp-tumblr-embed-handler.php b/includes/embeds/class-amp-tumblr-embed-handler.php index 1dbc8dd7564..f25bbd1db0d 100644 --- a/includes/embeds/class-amp-tumblr-embed-handler.php +++ b/includes/embeds/class-amp-tumblr-embed-handler.php @@ -3,6 +3,7 @@ * Class AMP_Tumblr_Embed_Handler * * @package AMP + * @since 0.7 */ /** From 6c9079f6a854a7c12d28edf80bb81af68c6a042d Mon Sep 17 00:00:00 2001 From: Kaitlyn Date: Fri, 26 Jan 2018 21:09:30 -0400 Subject: [PATCH 07/16] MeetUp embed class to help output the CSS returned from ombed. --- includes/amp-helper-functions.php | 1 + includes/class-amp-autoloader.php | 1 + .../embeds/class-amp-base-embed-handler.php | 2 +- .../embeds/class-amp-meetup-embed-handler.php | 72 +++++++++++++++++++ 4 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 includes/embeds/class-amp-meetup-embed-handler.php diff --git a/includes/amp-helper-functions.php b/includes/amp-helper-functions.php index d9ab456c758..5afb29567ce 100644 --- a/includes/amp-helper-functions.php +++ b/includes/amp-helper-functions.php @@ -182,6 +182,7 @@ function amp_get_content_embed_handlers( $post = null ) { 'AMP_SoundCloud_Embed_Handler' => array(), 'AMP_Instagram_Embed_Handler' => array(), 'AMP_Issuu_Embed_Handler' => array(), + 'AMP_MeetUp_Embed_Handler' => array(), 'AMP_Vine_Embed_Handler' => array(), 'AMP_Facebook_Embed_Handler' => array(), 'AMP_Pinterest_Embed_Handler' => array(), diff --git a/includes/class-amp-autoloader.php b/includes/class-amp-autoloader.php index 629a178e778..8da918a8142 100644 --- a/includes/class-amp-autoloader.php +++ b/includes/class-amp-autoloader.php @@ -40,6 +40,7 @@ class AMP_Autoloader { 'AMP_Gallery_Embed_Handler' => 'includes/embeds/class-amp-gallery-embed', 'AMP_Instagram_Embed_Handler' => 'includes/embeds/class-amp-instagram-embed', 'AMP_Issuu_Embed_Handler' => 'includes/embeds/class-amp-issuu-embed-handler', + 'AMP_MeetUp_Embed_Handler' => 'includes/embeds/class-amp-meetup-embed-handler', 'AMP_Pinterest_Embed_Handler' => 'includes/embeds/class-amp-pinterest-embed', 'AMP_Reddit_Embed_Handler' => 'includes/embeds/class-amp-reddit-embed-handler', 'AMP_SoundCloud_Embed_Handler' => 'includes/embeds/class-amp-soundcloud-embed', diff --git a/includes/embeds/class-amp-base-embed-handler.php b/includes/embeds/class-amp-base-embed-handler.php index 983cee4fab7..f46874b1974 100644 --- a/includes/embeds/class-amp-base-embed-handler.php +++ b/includes/embeds/class-amp-base-embed-handler.php @@ -30,7 +30,7 @@ function __construct( $args = array() ) { /** * Get mapping of AMP component names to AMP script URLs. * - * This is normally no longer needed because the wnitelist + * This is normally no longer needed because the whitelist * sanitizer will automatically detect the need for them via * the spec. * diff --git a/includes/embeds/class-amp-meetup-embed-handler.php b/includes/embeds/class-amp-meetup-embed-handler.php new file mode 100644 index 00000000000..fd7da919be4 --- /dev/null +++ b/includes/embeds/class-amp-meetup-embed-handler.php @@ -0,0 +1,72 @@ +render( array( 'url' => $url ) ); + } + + /** + * Extract the MeetUp CSS and output in header (otherwise stripped). + * Output the MeetUp oembed as usual. + * + * @param array $args parameters used for output. + */ + public function render( $args ) { + $args = wp_parse_args( $args, array( + 'url' => false, + ) ); + + if ( empty( $args['url'] ) ) { + return ''; + } + + $content = wp_oembed_get( $args['url'] ); + preg_match( '##', $content, $result ); + + // Outlying style tag from oembed. + if ( isset( $result[0] ) ) { + $css = str_replace( '#', $content, $result ); - // Outlying style tag from oembed. - if ( isset( $result[0] ) ) { - $css = str_replace( '#', '', $content ); return $content; } diff --git a/includes/embeds/class-amp-reddit-embed-handler.php b/includes/embeds/class-amp-reddit-embed-handler.php index 0f46cf8c415..6dc444c67fe 100644 --- a/includes/embeds/class-amp-reddit-embed-handler.php +++ b/includes/embeds/class-amp-reddit-embed-handler.php @@ -21,14 +21,14 @@ class AMP_Reddit_Embed_Handler extends AMP_Base_Embed_Handler { * Register embed. */ public function register_embed() { - wp_embed_register_handler( 'amp-reddit', self::URL_PATTERN, array( $this, 'oembed' ) ); + wp_embed_register_handler( 'amp-reddit', self::URL_PATTERN, array( $this, 'oembed' ), -1 ); } /** * Unregister embed. */ public function unregister_embed() { - wp_embed_unregister_handler( 'amp-reddit' ); + wp_embed_unregister_handler( 'amp-reddit', -1 ); } /** @@ -37,6 +37,7 @@ public function unregister_embed() { * @param array $matches URL regex matches. * @param array $attr Additional parameters. * @param array $url URL. + * @return string Embed. */ public function oembed( $matches, $attr, $url ) { return $this->render( array( 'url' => $url ) ); @@ -46,6 +47,7 @@ public function oembed( $matches, $attr, $url ) { * Output the Reddit amp element. * * @param array $args parameters used for output. + * @return string Rendered content. */ public function render( $args ) { $args = wp_parse_args( $args, array( diff --git a/includes/embeds/class-amp-tumblr-embed-handler.php b/includes/embeds/class-amp-tumblr-embed-handler.php index f25bbd1db0d..54106a59a02 100644 --- a/includes/embeds/class-amp-tumblr-embed-handler.php +++ b/includes/embeds/class-amp-tumblr-embed-handler.php @@ -21,14 +21,14 @@ class AMP_Tumblr_Embed_Handler extends AMP_Base_Embed_Handler { * Register embed. */ public function register_embed() { - wp_embed_register_handler( 'tumblr', self::URL_PATTERN, array( $this, 'oembed' ) ); + wp_embed_register_handler( 'tumblr', self::URL_PATTERN, array( $this, 'oembed' ), -1 ); } /** * Unregister embed. */ public function unregister_embed() { - wp_embed_unregister_handler( 'tumblr' ); + wp_embed_unregister_handler( 'tumblr', -1 ); } /** @@ -37,6 +37,7 @@ public function unregister_embed() { * @param array $matches URL regex matches. * @param array $attr Additional parameters. * @param array $url URL. + * @return string Embed. */ public function oembed( $matches, $attr, $url ) { return $this->render( array( 'url' => $url ) ); @@ -46,6 +47,7 @@ public function oembed( $matches, $attr, $url ) { * Output the Tumblr iframe. * * @param array $args parameters used for output. + * @return string Rendered content. */ public function render( $args ) { $args = wp_parse_args( $args, array( From e2cc3e1aeb5d6d1b6ea234adc286a38615ad6a50 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sat, 27 Jan 2018 20:10:30 -0800 Subject: [PATCH 10/16] Filter embed_oembed_html to capture CSS; move to amp-custom styles --- .../embeds/class-amp-meetup-embed-handler.php | 78 +++++++++++++------ 1 file changed, 53 insertions(+), 25 deletions(-) diff --git a/includes/embeds/class-amp-meetup-embed-handler.php b/includes/embeds/class-amp-meetup-embed-handler.php index dab578e7516..01ec4d67d01 100644 --- a/includes/embeds/class-amp-meetup-embed-handler.php +++ b/includes/embeds/class-amp-meetup-embed-handler.php @@ -18,54 +18,82 @@ class AMP_MeetUp_Embed_Handler extends AMP_Base_Embed_Handler { */ const URL_PATTERN = '#https?://(www\.)?meetu(\.ps|p\.com)/.*#i'; + /** + * CSS. + * + * @var string + */ + protected $captured_css; + + /** + * AMP_MeetUp_Embed_Handler constructor. + * + * @param array $args Args. + */ + public function __construct( array $args = array() ) { + parent::__construct( $args ); + add_filter( 'amp_custom_styles', array( $this, 'filter_amp_custom_styles' ) ); + add_action( 'amp_post_template_css', array( $this, 'do_action_amp_post_template_css' ) ); + } + /** * Register embed. */ public function register_embed() { - wp_embed_register_handler( 'meetup', self::URL_PATTERN, array( $this, 'oembed' ), -1 ); + add_filter( 'embed_oembed_html', array( $this, 'filter_embed_oembed_html' ), 10, 2 ); } /** * Unregister embed. */ public function unregister_embed() { - wp_embed_unregister_handler( 'meetup', -1 ); + remove_filter( 'embed_oembed_html', array( $this, 'filter_embed_oembed_html' ), 10 ); } /** - * Embed found with matching URL callback. + * Filter amp_custom_styles. * - * @param array $matches URL regex matches. - * @param array $attr Additional parameters. - * @param array $url URL. - * @return string Embed. + * @param string $css Amend CSS. + * @return string CSS. */ - public function oembed( $matches, $attr, $url ) { - return $this->render( array( 'url' => $url ) ); + public function filter_amp_custom_styles( $css ) { + if ( $this->captured_css ) { + $css .= wp_strip_all_tags( $this->captured_css ); + } + return $css; } /** - * Extract the MeetUp CSS and output in header (otherwise stripped). - * Output the MeetUp oEmbed as usual. - * - * @param array $args parameters used for output. - * @return string Rendered content. + * Add styles for AMP post template. */ - public function render( $args ) { - $args = wp_parse_args( $args, array( - 'url' => false, - ) ); - - if ( empty( $args['url'] ) ) { - return ''; + public function do_action_amp_post_template_css() { + if ( $this->captured_css ) { + echo wp_strip_all_tags( $this->captured_css ); // XSS OK. } + } - $content = wp_oembed_get( $args['url'] ); + /** + * Filter oEmbed HTML for SoundCloud to convert to AMP. + * + * @param string $cache Cache for oEmbed. + * @param string $url Embed URL. + * @return string Embed. + */ + public function filter_embed_oembed_html( $cache, $url ) { + $parsed_url = wp_parse_url( $url ); + if ( false === strpos( $parsed_url['host'], 'meetup.com' ) ) { + return $cache; + } + if ( preg_match( ':]*>(.+):s', $cache, $matches ) ) { + $this->captured_css = $matches[1]; - // Strip AMP-illegal style from response. - $content = preg_replace( '##', '', $content ); + // Eliminate illegal CSS. + $this->captured_css = str_replace( '!important', '', $this->captured_css ); - return $content; + // Remove CSS from embed. + $cache = str_replace( $matches[0], '', $cache ); + } + return $cache; } } From e1b74cdcfb03d5b33f5ef9ea7ece5fd44b6949a5 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sat, 27 Jan 2018 20:43:03 -0800 Subject: [PATCH 11/16] Mock soundcloud oEmbed response to speed up phpunit tests --- tests/test-amp-soundcloud-embed.php | 54 +++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/tests/test-amp-soundcloud-embed.php b/tests/test-amp-soundcloud-embed.php index 6cb271e64ab..cc7b1435478 100644 --- a/tests/test-amp-soundcloud-embed.php +++ b/tests/test-amp-soundcloud-embed.php @@ -12,6 +12,21 @@ */ class AMP_SoundCloud_Embed_Test extends WP_UnitTestCase { + /** + * The oEmbed URL. + * + * @var string + */ + protected $oembed_url = 'https://soundcloud.com/jack-villano-villano/mozart-requiem-in-d-minor'; + + /** + * Response for oEmbed request. + * + * @see AMP_SoundCloud_Embed_Test::$oembed_url + * @var string + */ + protected $oembed_response = '{"version":1.0,"type":"rich","provider_name":"SoundCloud","provider_url":"http://soundcloud.com","height":400,"width":500,"title":"Mozart - Requiem in D minor Complete Full by Jack Villano Villano","description":"mass in D Minor ","thumbnail_url":"http://i1.sndcdn.com/artworks-000046826426-o7i9ki-t500x500.jpg","html":"\u003Ciframe width=\"500\" height=\"400\" scrolling=\"no\" frameborder=\"no\" src=\"https://w.soundcloud.com/player/?visual=true\u0026url=https%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F90097394\u0026show_artwork=true\u0026maxwidth=500\u0026maxheight=750\u0026dnt=1\"\u003E\u003C/iframe\u003E","author_name":"Jack Villano Villano","author_url":"https://soundcloud.com/jack-villano-villano"}'; + /** * Set up. * @@ -34,6 +49,41 @@ public function setUp() { if ( function_exists( 'soundcloud_shortcode' ) ) { add_shortcode( 'soundcloud', 'soundcloud_shortcode' ); } + + add_filter( 'pre_http_request', array( $this, 'mock_http_request' ), 10, 3 ); + } + + /** + * After a test method runs, reset any state in WordPress the test method might have changed. + */ + public function tearDown() { + remove_filter( 'pre_http_request', array( $this, 'mock_http_request' ) ); + parent::tearDown(); + } + + /** + * Mock HTTP request. + * + * @param mixed $preempt Whether to preempt an HTTP request's return value. Default false. + * @param mixed $r HTTP request arguments. + * @param string $url The request URL. + * @return array Response data. + */ + public function mock_http_request( $preempt, $r, $url ) { + unset( $r ); + if ( false !== strpos( $url, 'soundcloud.com' ) ) { + return array( + 'body' => $this->oembed_response, + 'headers' => array(), + 'response' => array( + 'code' => 200, + 'message' => 'ok', + ), + 'cookies' => array(), + 'http_response' => null, + ); + } + return $preempt; } /** @@ -49,7 +99,7 @@ public function get_conversion_data() { ), 'url_simple' => array( - 'https://soundcloud.com/jack-villano-villano/mozart-requiem-in-d-minor' . PHP_EOL, + $this->oembed_url . PHP_EOL, '

' . PHP_EOL, ), ); @@ -111,7 +161,7 @@ public function get_scripts_data() { array(), ), 'converted' => array( - 'https://soundcloud.com/jack-villano-villano/mozart-requiem-in-d-minor' . PHP_EOL, + $this->oembed_url . PHP_EOL, array( 'amp-soundcloud' => 'https://cdn.ampproject.org/v0/amp-soundcloud-latest.js' ), ), ); From 509b74e641f068d11ea55ce4f8e66762a2fde2c7 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sat, 27 Jan 2018 22:57:42 -0800 Subject: [PATCH 12/16] Add support for sanitizing style elements --- includes/class-amp-theme-support.php | 39 ++------- .../embeds/class-amp-meetup-embed-handler.php | 55 +----------- .../sanitizers/class-amp-base-sanitizer.php | 20 ++++- .../sanitizers/class-amp-style-sanitizer.php | 67 ++++++++++++++- .../templates/class-amp-content-sanitizer.php | 41 ++++++--- tests/test-amp-style-sanitizer.php | 84 ++++++++++--------- 6 files changed, 170 insertions(+), 136 deletions(-) diff --git a/includes/class-amp-theme-support.php b/includes/class-amp-theme-support.php index c85bdd9f941..95141690144 100644 --- a/includes/class-amp-theme-support.php +++ b/includes/class-amp-theme-support.php @@ -26,20 +26,6 @@ class AMP_Theme_Support { */ const CUSTOM_STYLES_PLACEHOLDER = '/* AMP:CUSTOM_STYLES_PLACEHOLDER */'; - /** - * AMP Scripts. - * - * @var array - */ - protected static $amp_scripts = array(); - - /** - * AMP Styles. - * - * @var array - */ - protected static $amp_styles = array(); - /** * Sanitizer classes. * @@ -433,20 +419,14 @@ public static function add_amp_custom_style_placeholder() { /** * Get custom styles. * + * @param string[] $stylesheets Initial stylesheets. * @see wp_custom_css_cb() - * @return string Styles. + * @return string Concatenated stylesheets. */ - public static function get_amp_custom_styles() { + public static function get_amp_custom_styles( $stylesheets ) { $css = wp_styles()->print_code; - // Add styles gleaned from sanitizers. - foreach ( self::$amp_styles as $selector => $properties ) { - $css .= sprintf( - '%s{%s}', - $selector, - join( ';', $properties ) . ';' - ); - } + $css .= join( $stylesheets ); /** * Filters AMP custom CSS before it is injected onto the output buffer for the response. @@ -466,10 +446,10 @@ public static function get_amp_custom_styles() { /** * Determine required AMP scripts. * + * @param array $amp_scripts Initial scripts. * @return string Scripts to inject into the HEAD. */ - public static function get_amp_component_scripts() { - $amp_scripts = self::$amp_scripts; + public static function get_amp_component_scripts( $amp_scripts ) { foreach ( self::$embed_handlers as $embed_handler ) { $amp_scripts = array_merge( @@ -527,9 +507,6 @@ public static function finish_output_buffering( $output ) { $assets = AMP_Content_Sanitizer::sanitize_document( $dom, self::$sanitizer_classes, $args ); - self::$amp_scripts = array_merge( self::$amp_scripts, $assets['scripts'] ); - self::$amp_styles = array_merge( self::$amp_styles, $assets['styles'] ); - /* * @todo The sanitize method needs to be updated to sanitize the entire HTML element and not just the BODY. * This will require updating mandatory_parent_blacklist in amphtml-update.py to include elements that appear in the HEAD. @@ -547,7 +524,7 @@ public static function finish_output_buffering( $output ) { // Inject required scripts. $output = preg_replace( '#' . preg_quote( self::COMPONENT_SCRIPTS_PLACEHOLDER, '#' ) . '#', - self::get_amp_component_scripts(), + self::get_amp_component_scripts( $assets['scripts'] ), $output, 1 ); @@ -555,7 +532,7 @@ public static function finish_output_buffering( $output ) { // Inject styles. $output = preg_replace( '#' . preg_quote( self::CUSTOM_STYLES_PLACEHOLDER, '#' ) . '#', - self::get_amp_custom_styles(), + self::get_amp_custom_styles( $assets['stylesheets'] ), $output, 1 ); diff --git a/includes/embeds/class-amp-meetup-embed-handler.php b/includes/embeds/class-amp-meetup-embed-handler.php index 01ec4d67d01..7d2e2b3159d 100644 --- a/includes/embeds/class-amp-meetup-embed-handler.php +++ b/includes/embeds/class-amp-meetup-embed-handler.php @@ -18,24 +18,6 @@ class AMP_MeetUp_Embed_Handler extends AMP_Base_Embed_Handler { */ const URL_PATTERN = '#https?://(www\.)?meetu(\.ps|p\.com)/.*#i'; - /** - * CSS. - * - * @var string - */ - protected $captured_css; - - /** - * AMP_MeetUp_Embed_Handler constructor. - * - * @param array $args Args. - */ - public function __construct( array $args = array() ) { - parent::__construct( $args ); - add_filter( 'amp_custom_styles', array( $this, 'filter_amp_custom_styles' ) ); - add_action( 'amp_post_template_css', array( $this, 'do_action_amp_post_template_css' ) ); - } - /** * Register embed. */ @@ -51,29 +33,7 @@ public function unregister_embed() { } /** - * Filter amp_custom_styles. - * - * @param string $css Amend CSS. - * @return string CSS. - */ - public function filter_amp_custom_styles( $css ) { - if ( $this->captured_css ) { - $css .= wp_strip_all_tags( $this->captured_css ); - } - return $css; - } - - /** - * Add styles for AMP post template. - */ - public function do_action_amp_post_template_css() { - if ( $this->captured_css ) { - echo wp_strip_all_tags( $this->captured_css ); // XSS OK. - } - } - - /** - * Filter oEmbed HTML for SoundCloud to convert to AMP. + * Filter oEmbed HTML for MeetUp to prepare it for AMP. * * @param string $cache Cache for oEmbed. * @param string $url Embed URL. @@ -81,17 +41,10 @@ public function do_action_amp_post_template_css() { */ public function filter_embed_oembed_html( $cache, $url ) { $parsed_url = wp_parse_url( $url ); - if ( false === strpos( $parsed_url['host'], 'meetup.com' ) ) { - return $cache; - } - if ( preg_match( ':]*>(.+):s', $cache, $matches ) ) { - $this->captured_css = $matches[1]; - - // Eliminate illegal CSS. - $this->captured_css = str_replace( '!important', '', $this->captured_css ); + if ( false !== strpos( $parsed_url['host'], 'meetup.com' ) ) { - // Remove CSS from embed. - $cache = str_replace( $matches[0], '', $cache ); + // Supply the width/height so that we don't have to make requests to look them up later. + $cache = str_replace( 'get_styles() as $selector => $properties ) { + $stylesheet = sprintf( '%s { %s }', $selector, join( '; ', $properties ) . ';' ); + + $stylesheets[ md5( $stylesheet ) ] = $stylesheet; + } + + return $stylesheets; + } + /** * Get HTML body as DOMElement from DOMDocument received by the constructor. * diff --git a/includes/sanitizers/class-amp-style-sanitizer.php b/includes/sanitizers/class-amp-style-sanitizer.php index 9cb33aab8a8..4b40b89cd73 100644 --- a/includes/sanitizers/class-amp-style-sanitizer.php +++ b/includes/sanitizers/class-amp-style-sanitizer.php @@ -8,6 +8,7 @@ /** * Class AMP_Style_Sanitizer * + * @todo This needs to also run on the CSS that is gathered for amp-custom. * Collects inline styles and outputs them in the amp-custom stylesheet. */ class AMP_Style_Sanitizer extends AMP_Base_Sanitizer { @@ -21,12 +22,22 @@ class AMP_Style_Sanitizer extends AMP_Base_Sanitizer { */ private $styles = array(); + /** + * Stylesheets. + * + * Values are the CSS stylesheets. Keys are MD5 hashes of the stylesheets + * + * @since 0.7 + * @var string[] + */ + private $stylesheets = array(); + /** * Get list of CSS styles in HTML content of DOMDocument ($this->dom). * * @since 0.4 * - * @return string[] + * @return string[] Mapping CSS selectors to array of properties, or mapping of keys starting with 'stylesheet:' with value being the stylesheet. */ public function get_styles() { if ( ! $this->did_convert_elements ) { @@ -35,6 +46,16 @@ public function get_styles() { return $this->styles; } + /** + * Get stylesheets. + * + * @since 0.7 + * @returns array Values are the CSS stylesheets. Keys are MD5 hashes of the stylesheets. + */ + public function get_stylesheets() { + return array_merge( parent::get_stylesheets(), $this->stylesheets ); + } + /** * Sanitize CSS styles within the HTML contained in this instance's DOMDocument. * @@ -42,12 +63,50 @@ public function get_styles() { */ public function sanitize() { $body = $this->get_body_node(); + + $this->collect_style_elements(); + $this->collect_styles_recursive( $body ); $this->did_convert_elements = true; } /** - * Collect and store all CSS styles. + * Collect and sanitize all style elements. + */ + public function collect_style_elements() { + $style_elements = $this->dom->getElementsByTagName( 'style' ); + $nodes_to_remove = array(); + + foreach ( $style_elements as $style_element ) { + /** + * Style element. + * + * @var DOMElement $style_element + */ + + if ( 'head' === $style_element->parentNode->nodeName && ( $style_element->hasAttribute( 'amp-boilerplate' ) || $style_element->hasAttribute( 'amp-custom' ) ) ) { + continue; + } + + $nodes_to_remove[] = $style_element; + + // @todo This should perhaps be done in document order to ensure proper cascade. + $rules = trim( $style_element->textContent ); + + // @todo This needs proper CSS parser, and de-duplication with \AMP_Style_Sanitizer::filter_style(). + $rules = preg_replace( '/\s*!important\s*(?=\s*;|})/', '', $rules ); + $rules = preg_replace( '/overflow\s*:\s*(auto|scroll)\s*;?\s*/', '', $rules ); + + $this->stylesheets[ md5( $rules ) ] = $rules; + } + + foreach ( $nodes_to_remove as $node_to_remove ) { + $node_to_remove->parentNode->removeChild( $node_to_remove ); + } + } + + /** + * Collect and store all CSS style attributes. * * Collects the CSS styles from within the HTML contained in this instance's DOMDocument. * @@ -56,6 +115,7 @@ public function sanitize() { * @since 0.4 * * @note Uses recursion to traverse down the tree of DOMDocument nodes. + * @todo This could use XPath to more efficiently find all elements with style attributes. * * @param DOMNode $node Node. */ @@ -155,6 +215,7 @@ private function filter_style( $property, $value ) { /** * Remove overflow if value is `auto` or `scroll`; not allowed in AMP * + * @todo This removal needs to be reported. * @see https://www.ampproject.org/docs/reference/spec.html#properties */ if ( preg_match( '#^overflow#i', $property ) && preg_match( '#^(auto|scroll)$#i', $value ) ) { @@ -167,6 +228,8 @@ private function filter_style( $property, $value ) { /** * Remove `!important`; not allowed in AMP + * + * @todo This removal needs to be reported. */ if ( false !== strpos( $value, 'important' ) ) { $value = preg_replace( '/\s*\!\s*important$/', '', $value ); diff --git a/includes/templates/class-amp-content-sanitizer.php b/includes/templates/class-amp-content-sanitizer.php index ddf533091cd..d7b75c28ec3 100644 --- a/includes/templates/class-amp-content-sanitizer.php +++ b/includes/templates/class-amp-content-sanitizer.php @@ -16,20 +16,26 @@ class AMP_Content_Sanitizer { * Sanitize _content_. * * @since 0.4.1 + * @since 0.7 Passing return_styles=false in $global_args causes stylesheets to be returned instead of styles. * * @param string $content HTML content string or DOM document. * @param string[] $sanitizer_classes Sanitizer classes. * @param array $global_args Global args. - * @return array Tuple containing sanitized HTML, scripts array, and styles array. + * @return array Tuple containing sanitized HTML, scripts array, and styles array (or stylesheets, if return_styles=false is passed in $global_args). */ public static function sanitize( $content, array $sanitizer_classes, $global_args = array() ) { $dom = AMP_DOM_Utils::get_dom_from_content( $content ); + // For back-compat. + if ( ! isset( $global_args['return_styles'] ) ) { + $global_args['return_styles'] = true; + } + $results = self::sanitize_document( $dom, $sanitizer_classes, $global_args ); return array( AMP_DOM_Utils::get_content_from_dom( $dom ), $results['scripts'], - $results['styles'], + empty( $global_args['return_styles'] ) ? $results['stylesheets'] : $results['styles'], ); } @@ -40,18 +46,23 @@ public static function sanitize( $content, array $sanitizer_classes, $global_arg * * @param DOMDocument $dom HTML document. * @param string[] $sanitizer_classes Sanitizer classes. - * @param array $global_args Global args passed into . + * @param array $args Global args passed into sanitizers. * @return array { - * Scripts and styles needed by sanitizers. + * Scripts and stylesheets needed by sanitizers. * - * @type array $scripts Scripts. - * @type array $styles Styles. + * @type array $scripts Scripts. + * @type array $stylesheets Stylesheets. If $args['return_styles'] is empty. + * @type array $styles Styles. If $args['return_styles'] is not empty. For legacy purposes. * } */ - public static function sanitize_document( &$dom, $sanitizer_classes, $global_args ) { - $scripts = array(); - $styles = array(); - foreach ( $sanitizer_classes as $sanitizer_class => $args ) { + public static function sanitize_document( &$dom, $sanitizer_classes, $args ) { + $scripts = array(); + $stylesheets = array(); + $styles = array(); + + $return_styles = ! empty( $args['return_styles'] ); + unset( $args['return_styles'] ); + foreach ( $sanitizer_classes as $sanitizer_class => $sanitizer_args ) { if ( ! class_exists( $sanitizer_class ) ) { /* translators: %s is sanitizer class */ _doing_it_wrong( __METHOD__, sprintf( esc_html__( 'Sanitizer (%s) class does not exist', 'amp' ), esc_html( $sanitizer_class ) ), '0.4.1' ); @@ -63,7 +74,7 @@ public static function sanitize_document( &$dom, $sanitizer_classes, $global_arg * * @type AMP_Base_Sanitizer $sanitizer */ - $sanitizer = new $sanitizer_class( $dom, array_merge( $global_args, $args ) ); + $sanitizer = new $sanitizer_class( $dom, array_merge( $args, $sanitizer_args ) ); if ( ! is_subclass_of( $sanitizer, 'AMP_Base_Sanitizer' ) ) { /* translators: %s is sanitizer class */ @@ -74,10 +85,14 @@ public static function sanitize_document( &$dom, $sanitizer_classes, $global_arg $sanitizer->sanitize(); $scripts = array_merge( $scripts, $sanitizer->get_scripts() ); - $styles = array_merge( $styles, $sanitizer->get_styles() ); + if ( $return_styles ) { + $styles = array_merge( $styles, $sanitizer->get_styles() ); + } else { + $stylesheets = array_merge( $stylesheets, $sanitizer->get_stylesheets() ); + } } - return compact( 'scripts', 'styles' ); + return compact( 'scripts', 'styles', 'stylesheets' ); } } diff --git a/tests/test-amp-style-sanitizer.php b/tests/test-amp-style-sanitizer.php index 78448cf6885..e12a6d9bc4e 100644 --- a/tests/test-amp-style-sanitizer.php +++ b/tests/test-amp-style-sanitizer.php @@ -1,6 +1,20 @@ array( @@ -13,9 +27,7 @@ public function get_data() { 'This is green.', 'This is green.', array( - '.amp-wp-inline-ad0e57ab02197f7023aa5b93bcf6c97e' => array( - 'color:#00ff00', - ), + '.amp-wp-inline-ad0e57ab02197f7023aa5b93bcf6c97e { color:#00ff00; }', ), ), @@ -23,9 +35,7 @@ public function get_data() { 'This is green.', 'This is green.', array( - '.amp-wp-inline-ad0e57ab02197f7023aa5b93bcf6c97e' => array( - 'color:#00ff00', - ), + '.amp-wp-inline-ad0e57ab02197f7023aa5b93bcf6c97e { color:#00ff00; }', ), ), @@ -33,10 +43,7 @@ public function get_data() { 'This is green.', 'This is green.', array( - '.amp-wp-inline-58550689c128f3d396444313296e4c47' => array( - 'background-color:#000', - 'color:#00ff00', - ), + '.amp-wp-inline-58550689c128f3d396444313296e4c47 { background-color:#000; color:#00ff00; }', ), ), @@ -44,9 +51,7 @@ public function get_data() { '
', '
', array( - '.amp-wp-inline-2676cd1bfa7e8feb4f0e0e8086ae9ce4' => array( - 'max-width:300px', - ), + '.amp-wp-inline-2676cd1bfa7e8feb4f0e0e8086ae9ce4 { max-width:300px; }', ), ), @@ -66,9 +71,7 @@ public function get_data() { '!important not allowed.', '!important not allowed.', array( - '.amp-wp-inline-b370df7c42957a3192cac40a8ddcff79' => array( - 'margin:1px', - ), + '.amp-wp-inline-b370df7c42957a3192cac40a8ddcff79 { margin:1px; }', ), ), @@ -76,9 +79,7 @@ public function get_data() { '!important not allowed.', '!important not allowed.', array( - '.amp-wp-inline-5b88d03e432f20476a218314084d3a05' => array( - 'color:red', - ), + '.amp-wp-inline-5b88d03e432f20476a218314084d3a05 { color:red; }', ), ), @@ -86,10 +87,7 @@ public function get_data() { '!important not allowed.', '!important not allowed.', array( - '.amp-wp-inline-ef4329d562b6b3486a8a661df5c5280f' => array( - 'background:blue', - 'color:red', - ), + '.amp-wp-inline-ef4329d562b6b3486a8a661df5c5280f { background:blue; color:red; }', ), ), @@ -97,12 +95,8 @@ public function get_data() { 'This is red.', 'This is red.', array( - '.amp-wp-inline-ad0e57ab02197f7023aa5b93bcf6c97e' => array( - 'color:#00ff00', - ), - '.amp-wp-inline-f146f9bb819d875bbe5cf83e36368b44' => array( - 'color:#ff0000', - ), + '.amp-wp-inline-ad0e57ab02197f7023aa5b93bcf6c97e { color:#00ff00; }', + '.amp-wp-inline-f146f9bb819d875bbe5cf83e36368b44 { color:#ff0000; }', ), ), @@ -110,29 +104,43 @@ public function get_data() { '
', '
', array( - '.amp-wp-inline-3be9b2f79873ad78941ba2b3c03025a3' => array( - 'background:#000', - ), + '.amp-wp-inline-3be9b2f79873ad78941ba2b3c03025a3 { background:#000; }', ), ), + + 'inline_style_element_with_multiple_rules_containing_selectors_is_removed' => array( + '
bold!
', + '
bold!
', + array( + 'div > span { font-weight:bold; font-style: italic; }', + ), + ), ); } /** + * Test sanitizer. + * * @dataProvider get_data + * @param string $source Source. + * @param string $expected_content Expected content. + * @param string $expected_stylesheets Expected stylesheets. */ - public function test_sanitizer( $source, $expected_content, $expected_stylesheet ) { + public function test_sanitizer( $source, $expected_content, $expected_stylesheets ) { $dom = AMP_DOM_Utils::get_dom_from_content( $source ); + $sanitizer = new AMP_Style_Sanitizer( $dom ); $sanitizer->sanitize(); - // Test content + $whitelist_sanitizer = new AMP_Tag_And_Attribute_Sanitizer( $dom ); + $whitelist_sanitizer->sanitize(); + + // Test content. $content = AMP_DOM_Utils::get_content_from_dom( $dom ); $this->assertEquals( $expected_content, $content ); - // Test stylesheet - $stylesheet = $sanitizer->get_styles(); - $this->assertEquals( $expected_stylesheet, $stylesheet ); + // Test stylesheet. + $this->assertEquals( $expected_stylesheets, array_values( $sanitizer->get_stylesheets() ) ); } } From c6d625857f6bbf65ff20ce43453357fe2db967c6 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sun, 28 Jan 2018 00:03:14 -0800 Subject: [PATCH 13/16] Remove illegal wp_post_preview_js() from wp_head when AMP --- includes/class-amp-theme-support.php | 1 + 1 file changed, 1 insertion(+) diff --git a/includes/class-amp-theme-support.php b/includes/class-amp-theme-support.php index 95141690144..70db1c81fde 100644 --- a/includes/class-amp-theme-support.php +++ b/includes/class-amp-theme-support.php @@ -141,6 +141,7 @@ public static function register_paired_hooks() { public static function register_hooks() { // Remove core actions which are invalid AMP. + remove_action( 'wp_head', 'wp_post_preview_js', 1 ); remove_action( 'wp_head', 'locale_stylesheet' ); // Replaced below in add_amp_custom_style_placeholder() method. remove_action( 'wp_head', 'print_emoji_detection_script', 7 ); remove_action( 'wp_head', 'wp_print_styles', 8 ); // Replaced below in add_amp_custom_style_placeholder() method. From c2efa4735422ab9159242d58463d23d7b4c21521 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sun, 28 Jan 2018 00:40:20 -0800 Subject: [PATCH 14/16] Obtain issuu width/height via embed_oembed_html filter --- .../embeds/class-amp-issuu-embed-handler.php | 57 ++++++++----------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/includes/embeds/class-amp-issuu-embed-handler.php b/includes/embeds/class-amp-issuu-embed-handler.php index aa3da4d4f8c..e6235dd3fd1 100644 --- a/includes/embeds/class-amp-issuu-embed-handler.php +++ b/includes/embeds/class-amp-issuu-embed-handler.php @@ -21,52 +21,45 @@ class AMP_Issuu_Embed_Handler extends AMP_Base_Embed_Handler { * Register embed. */ public function register_embed() { - wp_embed_register_handler( 'issuu', self::URL_PATTERN, array( $this, 'oembed' ), -1 ); + add_filter( 'embed_oembed_html', array( $this, 'filter_embed_oembed_html' ), 10, 3 ); } /** * Unregister embed. */ public function unregister_embed() { - wp_embed_unregister_handler( 'issuu', -1 ); + remove_filter( 'embed_oembed_html', array( $this, 'filter_embed_oembed_html' ), 10 ); } /** - * Embed found with matching URL callback. + * Filter oEmbed HTML for MeetUp to prepare it for AMP. * - * @param array $matches URL regex matches. - * @param array $attr Additional parameters. - * @param array $url URL. + * @param mixed $return The shortcode callback function to call. + * @param string $url The attempted embed URL. + * @param array $attr An array of shortcode attributes. * @return string Embed. */ - public function oembed( $matches, $attr, $url ) { - return $this->render( array( 'url' => $url ) ); - } - - /** - * Output the Issuu iframe. - * - * @param array $args parameters used for output. - * @return string Rendered content. - */ - public function render( $args ) { - $args = wp_parse_args( $args, array( - 'url' => false, - ) ); + public function filter_embed_oembed_html( $return, $url, $attr ) { + $parsed_url = wp_parse_url( $url ); + if ( false !== strpos( $parsed_url['host'], 'issuu.com' ) ) { + if ( preg_match( '/width\s*:\s*(\d+)px/', $return, $matches ) ) { + $attr['width'] = $matches[1]; + } + if ( preg_match( '/height\s*:\s*(\d+)px/', $return, $matches ) ) { + $attr['height'] = $matches[1]; + } - if ( empty( $args['url'] ) ) { - return ''; + $return = AMP_HTML_Utils::build_tag( + 'amp-iframe', + array( + 'width' => $attr['width'], + 'height' => $attr['height'], + 'src' => $url, + 'sandbox' => 'allow-scripts allow-same-origin', + ) + ); } - - return AMP_HTML_Utils::build_tag( - 'amp-iframe', - array( - 'width' => $this->args['width'], - 'height' => $this->args['height'], - 'src' => $args['url'], - 'sandbox' => 'allow-scripts allow-same-origin', - ) - ); + return $return; } } From 708e577035731ade0dac2efa35e01977b341c13c Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sun, 28 Jan 2018 16:26:02 -0800 Subject: [PATCH 15/16] Restore visibility of blockquote.wp-embedded-content since iframe cannot be clicked --- includes/amp-helper-functions.php | 2 +- includes/class-amp-autoloader.php | 2 +- includes/embeds/class-amp-issuu-embed-handler.php | 2 +- includes/embeds/class-amp-meetup-embed-handler.php | 8 ++++---- templates/style.php | 4 ---- 5 files changed, 7 insertions(+), 11 deletions(-) diff --git a/includes/amp-helper-functions.php b/includes/amp-helper-functions.php index 6a17d70f16a..ef4a9cfa4f4 100644 --- a/includes/amp-helper-functions.php +++ b/includes/amp-helper-functions.php @@ -182,7 +182,7 @@ function amp_get_content_embed_handlers( $post = null ) { 'AMP_SoundCloud_Embed_Handler' => array(), 'AMP_Instagram_Embed_Handler' => array(), 'AMP_Issuu_Embed_Handler' => array(), - 'AMP_MeetUp_Embed_Handler' => array(), + 'AMP_Meetup_Embed_Handler' => array(), 'AMP_Vine_Embed_Handler' => array(), 'AMP_Facebook_Embed_Handler' => array(), 'AMP_Pinterest_Embed_Handler' => array(), diff --git a/includes/class-amp-autoloader.php b/includes/class-amp-autoloader.php index 94d3c816a43..b0904dd69e8 100644 --- a/includes/class-amp-autoloader.php +++ b/includes/class-amp-autoloader.php @@ -40,7 +40,7 @@ class AMP_Autoloader { 'AMP_Gallery_Embed_Handler' => 'includes/embeds/class-amp-gallery-embed', 'AMP_Instagram_Embed_Handler' => 'includes/embeds/class-amp-instagram-embed', 'AMP_Issuu_Embed_Handler' => 'includes/embeds/class-amp-issuu-embed-handler', - 'AMP_MeetUp_Embed_Handler' => 'includes/embeds/class-amp-meetup-embed-handler', + 'AMP_Meetup_Embed_Handler' => 'includes/embeds/class-amp-meetup-embed-handler', 'AMP_Pinterest_Embed_Handler' => 'includes/embeds/class-amp-pinterest-embed', 'AMP_Reddit_Embed_Handler' => 'includes/embeds/class-amp-reddit-embed-handler', 'AMP_SoundCloud_Embed_Handler' => 'includes/embeds/class-amp-soundcloud-embed', diff --git a/includes/embeds/class-amp-issuu-embed-handler.php b/includes/embeds/class-amp-issuu-embed-handler.php index e6235dd3fd1..6ffb38197ab 100644 --- a/includes/embeds/class-amp-issuu-embed-handler.php +++ b/includes/embeds/class-amp-issuu-embed-handler.php @@ -32,7 +32,7 @@ public function unregister_embed() { } /** - * Filter oEmbed HTML for MeetUp to prepare it for AMP. + * Filter oEmbed HTML for Meetup to prepare it for AMP. * * @param mixed $return The shortcode callback function to call. * @param string $url The attempted embed URL. diff --git a/includes/embeds/class-amp-meetup-embed-handler.php b/includes/embeds/class-amp-meetup-embed-handler.php index 7d2e2b3159d..9e037a49e6f 100644 --- a/includes/embeds/class-amp-meetup-embed-handler.php +++ b/includes/embeds/class-amp-meetup-embed-handler.php @@ -1,15 +1,15 @@ Date: Sun, 28 Jan 2018 17:35:37 -0800 Subject: [PATCH 16/16] Fix displaying Tumblr embeds on HTTPS --- .../embeds/class-amp-meetup-embed-handler.php | 7 -- .../embeds/class-amp-reddit-embed-handler.php | 1 + .../embeds/class-amp-tumblr-embed-handler.php | 64 ++++++++----------- 3 files changed, 26 insertions(+), 46 deletions(-) diff --git a/includes/embeds/class-amp-meetup-embed-handler.php b/includes/embeds/class-amp-meetup-embed-handler.php index 9e037a49e6f..2957850fd08 100644 --- a/includes/embeds/class-amp-meetup-embed-handler.php +++ b/includes/embeds/class-amp-meetup-embed-handler.php @@ -11,13 +11,6 @@ */ class AMP_Meetup_Embed_Handler extends AMP_Base_Embed_Handler { - /** - * Regex matched. - * - * @const string - */ - const URL_PATTERN = '#https?://(www\.)?meetu(\.ps|p\.com)/.*#i'; - /** * Register embed. */ diff --git a/includes/embeds/class-amp-reddit-embed-handler.php b/includes/embeds/class-amp-reddit-embed-handler.php index 6dc444c67fe..d80275cb3b8 100644 --- a/includes/embeds/class-amp-reddit-embed-handler.php +++ b/includes/embeds/class-amp-reddit-embed-handler.php @@ -58,6 +58,7 @@ public function render( $args ) { return ''; } + // @todo Sizing is not yet correct. See . return AMP_HTML_Utils::build_tag( 'amp-reddit', array( diff --git a/includes/embeds/class-amp-tumblr-embed-handler.php b/includes/embeds/class-amp-tumblr-embed-handler.php index 54106a59a02..75650849c9a 100644 --- a/includes/embeds/class-amp-tumblr-embed-handler.php +++ b/includes/embeds/class-amp-tumblr-embed-handler.php @@ -10,65 +10,51 @@ * Class AMP_Tumblr_Embed_Handler */ class AMP_Tumblr_Embed_Handler extends AMP_Base_Embed_Handler { - /** - * Regex matched to produce output amp-iframe. - * - * @const string - */ - const URL_PATTERN = '#https?://(.+)\.tumblr\.com/post/(.*)#i'; /** * Register embed. */ public function register_embed() { - wp_embed_register_handler( 'tumblr', self::URL_PATTERN, array( $this, 'oembed' ), -1 ); + add_filter( 'embed_oembed_html', array( $this, 'filter_embed_oembed_html' ), 10, 2 ); } /** * Unregister embed. */ public function unregister_embed() { - wp_embed_unregister_handler( 'tumblr', -1 ); + remove_filter( 'embed_oembed_html', array( $this, 'filter_embed_oembed_html' ), 10 ); } /** - * Embed found with matching URL callback. + * Filter oEmbed HTML for Tumblr to prepare it for AMP. * - * @param array $matches URL regex matches. - * @param array $attr Additional parameters. - * @param array $url URL. + * @param string $cache Cache for oEmbed. + * @param string $url Embed URL. * @return string Embed. */ - public function oembed( $matches, $attr, $url ) { - return $this->render( array( 'url' => $url ) ); - } - - /** - * Output the Tumblr iframe. - * - * @param array $args parameters used for output. - * @return string Rendered content. - */ - public function render( $args ) { - $args = wp_parse_args( $args, array( - 'url' => false, - ) ); - - if ( empty( $args['url'] ) ) { - return ''; + public function filter_embed_oembed_html( $cache, $url ) { + $parsed_url = wp_parse_url( $url ); + if ( false === strpos( $parsed_url['host'], 'tumblr.com' ) ) { + return $cache; } - // Must enforce https for amp-iframe, but editors can supply either on desktop. - $args['url'] = str_replace( 'http://', 'https://', $args['url'] ); + // @todo The iframe will not get sized properly. + if ( preg_match( '#data-href="(?Phttps://embed.tumblr.com/embed/post/\w+/\w+)"#', $cache, $matches ) ) { + $cache = AMP_HTML_Utils::build_tag( + 'amp-iframe', + array( + 'width' => $this->args['width'], + 'height' => $this->args['height'], + 'layout' => 'responsive', + 'sandbox' => 'allow-scripts allow-popups', // The allow-scripts is needed to allow the iframe to render; allow-popups needed to allow clicking. + 'src' => $matches['href'], + ), + sprintf( 'Tumblr', $url ) + ); + } - return AMP_HTML_Utils::build_tag( - 'amp-iframe', - array( - 'width' => $this->args['width'], - 'height' => $this->args['height'], - 'src' => $args['url'], - ) - ); + return $cache; } + }