diff --git a/3rd-party/class.jetpack-amp-support.php b/3rd-party/class.jetpack-amp-support.php
index fd8007322be3b..71d35d820c6d3 100644
--- a/3rd-party/class.jetpack-amp-support.php
+++ b/3rd-party/class.jetpack-amp-support.php
@@ -37,6 +37,9 @@ public static function init() {
// Add post template metadata for legacy AMP.
add_filter( 'amp_post_template_metadata', array( 'Jetpack_AMP_Support', 'amp_post_template_metadata' ), 10, 2 );
+
+ // Filter photon image args for AMP Stories.
+ add_filter( 'jetpack_photon_post_image_args', array( 'Jetpack_AMP_Support', 'filter_photon_post_image_args_for_stories' ), 10, 2 );
}
/**
@@ -365,6 +368,74 @@ public static function amp_disable_sharedaddy_css( $enqueue ) {
return $enqueue;
}
+
+ /**
+ * Ensure proper Photon image dimensions for AMP Stories.
+ *
+ * @param array $args Array of Photon Arguments.
+ * @param array $details {
+ * Array of image details.
+ *
+ * @type string $tag Image tag (Image HTML output).
+ * @type string $src Image URL.
+ * @type string $src_orig Original Image URL.
+ * @type int|false $width Image width.
+ * @type int|false $height Image height.
+ * @type int|false $width_orig Original image width before constrained by content_width.
+ * @type int|false $height_orig Original Image height before constrained by content_width.
+ * @type string $transform_orig Original transform before constrained by content_width.
+ * }
+ * @return array Args.
+ */
+ public static function filter_photon_post_image_args_for_stories( $args, $details ) {
+ if ( ! is_singular( 'amp_story' ) ) {
+ return $args;
+ }
+
+ // Percentage-based dimensions are not allowed in AMP, so this shouldn't happen, but short-circuit just in case.
+ if ( false !== strpos( $details['width_orig'], '%' ) || false !== strpos( $details['height_orig'], '%' ) ) {
+ return $args;
+ }
+
+ $max_height = 1440; // See image size with the slug \AMP_Story_Post_Type::MAX_IMAGE_SIZE_SLUG.
+ $transform = $details['transform_orig'];
+ $width = $details['width_orig'];
+ $height = $details['height_orig'];
+
+ // If height is available, constrain to $max_height.
+ if ( false !== $height ) {
+ if ( $height > $max_height && false !== $height ) {
+ $width = ( $max_height * $width ) / $height;
+ $height = $max_height;
+ } elseif ( $height > $max_height ) {
+ $height = $max_height;
+ }
+ }
+
+ /*
+ * Set a height if none is found.
+ * If height is set in this manner and height is available, use `fit` instead of `resize` to prevent skewing.
+ */
+ if ( false === $height ) {
+ $height = $max_height;
+ if ( false !== $width ) {
+ $transform = 'fit';
+ }
+ }
+
+ // Build array of Photon args and expose to filter before passing to Photon URL function.
+ $args = array();
+
+ if ( false !== $width && false !== $height ) {
+ $args[ $transform ] = $width . ',' . $height;
+ } elseif ( false !== $width ) {
+ $args['w'] = $width;
+ } elseif ( false !== $height ) {
+ $args['h'] = $height;
+ }
+
+ return $args;
+ }
}
add_action( 'init', array( 'Jetpack_AMP_Support', 'init' ), 1 );
diff --git a/class.photon.php b/class.photon.php
index c7bf8a1341c7f..39c013ca68bff 100644
--- a/class.photon.php
+++ b/class.photon.php
@@ -239,7 +239,7 @@ public static function filter_photon_norezise_maybe_inject_sizes_api( $sizes, $a
public static function parse_images_from_html( $content ) {
$images = array();
- if ( preg_match_all( '#(?:]+?href=["|\'](?P[^\s]+?)["|\'][^>]*?>\s*)?(?P
]*?\s+?src=["|\'](?P[^\s]+?)["|\'].*?>){1}(?:\s*)?#is', $content, $images ) ) {
+ if ( preg_match_all( '#(?:]+?href=["|\'](?P[^\s]+?)["|\'][^>]*?>\s*)?(?P<(?:img|amp-img|amp-anim)[^>]*?\s+?src=["|\'](?P[^\s]+?)["|\'].*?>){1}(?:\s*)?#is', $content, $images ) ) {
foreach ( $images as $key => $unused ) {
// Simplify the output as much as possible, mostly for confirming test results.
if ( is_numeric( $key ) && $key > 0 )
@@ -419,6 +419,10 @@ public static function filter_the_content( $content ) {
list( $width, $height ) = Jetpack_Photon::parse_dimensions_from_filename( $src );
}
+ $width_orig = $width;
+ $height_orig = $height;
+ $transform_orig = $transform;
+
// If width is available, constrain to $content_width
if ( false !== $width && false === strpos( $width, '%' ) && is_numeric( $content_width ) ) {
if ( $width > $content_width && false !== $height && false === strpos( $height, '%' ) ) {
@@ -467,17 +471,21 @@ public static function filter_the_content( $content ) {
* @since 2.0.0
*
* @param array $args Array of Photon Arguments.
- * @param array $args {
- * Array of image details.
+ * @param array $details {
+ * Array of image details.
*
- * @type $tag Image tag (Image HTML output).
- * @type $src Image URL.
- * @type $src_orig Original Image URL.
- * @type $width Image width.
- * @type $height Image height.
+ * @type string $tag Image tag (Image HTML output).
+ * @type string $src Image URL.
+ * @type string $src_orig Original Image URL.
+ * @type int|false $width Image width.
+ * @type int|false $height Image height.
+ * @type int|false $width_orig Original image width before constrained by content_width.
+ * @type int|false $height_orig Original Image height before constrained by content_width.
+ * @type string $transform Transform.
+ * @type string $transform_orig Original transform before constrained by content_width.
* }
*/
- $args = apply_filters( 'jetpack_photon_post_image_args', $args, compact( 'tag', 'src', 'src_orig', 'width', 'height' ) );
+ $args = apply_filters( 'jetpack_photon_post_image_args', $args, compact( 'tag', 'src', 'src_orig', 'width', 'height', 'width_orig', 'height_orig', 'transform', 'transform_orig' ) );
$photon_url = jetpack_photon_url( $src, $args );
@@ -536,7 +544,9 @@ public static function filter_the_content( $content ) {
}
// Tag an image for dimension checking
- $new_tag = preg_replace( '#(\s?/)?>(\s*)?$#i', ' data-recalc-dims="1"\1>\2', $new_tag );
+ if ( ! self::is_amp_endpoint() ) {
+ $new_tag = preg_replace( '#(\s?/)?>(\s*)?$#i', ' data-recalc-dims="1"\1>\2', $new_tag );
+ }
// Replace original tag with modified version
$content = str_replace( $tag, $new_tag, $content );
@@ -1181,7 +1191,7 @@ public function noresize_intermediate_sizes( $sizes ) {
* @return null
*/
public function action_wp_enqueue_scripts() {
- if ( Jetpack_AMP_Support::is_amp_request() ) {
+ if ( self::is_amp_endpoint() ) {
return;
}
wp_enqueue_script(
@@ -1264,4 +1274,16 @@ public function cleanup_rest_photon_image_downsize( $response ) {
public function _override_image_downsize_in_rest_edit_context() {
return true;
}
+
+ /**
+ * Return whether the current page is AMP.
+ *
+ * This is only present for the sake of WordPress.com where the Jetpack_AMP_Support
+ * class does not yet exist. This mehod may only be called at the wp action or later.
+ *
+ * @return bool Whether AMP page.
+ */
+ private static function is_amp_endpoint() {
+ return class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request();
+ }
}
diff --git a/tests/php/test_class.jetpack_photon.php b/tests/php/test_class.jetpack_photon.php
index 56b1de6d21324..8e12fb7046bd6 100644
--- a/tests/php/test_class.jetpack_photon.php
+++ b/tests/php/test_class.jetpack_photon.php
@@ -804,6 +804,7 @@ public function test_photon_filter_the_content_does_not_have_width_height_when_a
$this->assertArrayNotHasKey( 'width', $attributes );
$this->assertArrayNotHasKey( 'height', $attributes );
+ $this->assertContains( 'data-recalc-dims', $filtered_content );
}
/**
@@ -815,9 +816,9 @@ public function test_photon_filter_the_content_does_not_have_width_height_when_a
public function test_photon_filter_the_content_width_height_attributes_when_image_args_filtered( $filter_callback, $has_attributes, $width, $height ) {
list( $sample_html ) = $this->get_photon_sample_content( 'a-tags-without-images.html' );
- add_filter( 'jetpack_photon_post_image_args', array( $this, $filter_callback ) );
+ add_filter( 'jetpack_photon_post_image_args', $filter_callback, 10, 2 );
$filtered_content = Jetpack_Photon::filter_the_content( $sample_html );
- remove_filter( 'jetpack_photon_post_image_args', array( $this, $filter_callback ) );
+ remove_filter( 'jetpack_photon_post_image_args', $filter_callback, 10, 2 );
$first_line = strtok( $filtered_content, "\n" ); // Should contain an image tag on the first line
$attributes = wp_kses_hair( $first_line, wp_allowed_protocols() );
@@ -836,27 +837,62 @@ public function test_photon_filter_the_content_width_height_attributes_when_imag
}
public function photon_attributes_when_filtered_data_provider() {
+ $that = $this; // For sake of PHP 5.3.
+
+ $assert_details = function ( $details ) use ( $that ) {
+ $that->assertInternalType( 'array', $details );
+ $that->assertArrayHasKey( 'tag', $details );
+ $that->assertArrayHasKey( 'src', $details );
+ $that->assertArrayHasKey( 'src_orig', $details );
+ $that->assertArrayHasKey( 'width', $details );
+ $that->assertArrayHasKey( 'width_orig', $details );
+ $that->assertArrayHasKey( 'height', $details );
+ $that->assertArrayHasKey( 'height_orig', $details );
+ $that->assertArrayHasKey( 'transform', $details );
+ $that->assertArrayHasKey( 'transform_orig', $details );
+ };
+
return array(
'photon_post_image_args_force_resize' => array(
- 'photon_post_image_args_force_resize',
+ function( $args, $details ) use ( $assert_details ) {
+ $assert_details( $details );
+ return array(
+ 'resize' => '300,250'
+ );
+ },
true,
300,
250
),
'photon_post_image_args_force_fit' => array(
- 'photon_post_image_args_force_fit',
+ function ( $args, $details ) use ( $assert_details ) {
+ $assert_details( $details );
+ return array(
+ 'fit' => '600,600'
+ );
+ },
true,
600,
600
),
'photon_post_image_args_force_lb' => array(
- 'photon_post_image_args_force_lb',
+ function ( $args, $details ) use ( $assert_details ) {
+ $assert_details( $details );
+ return array(
+ 'lb' => '800,100,000000'
+ );
+ },
true,
800,
100
),
'photon_post_image_args_force_width_only' => array(
- 'photon_post_image_args_force_width_only',
+ function ( $args, $details ) use ( $assert_details ) {
+ $assert_details( $details );
+ return array(
+ 'w' => '104'
+ );
+ },
false,
false,
false
@@ -864,28 +900,75 @@ public function photon_attributes_when_filtered_data_provider() {
);
}
- public function photon_post_image_args_force_resize() {
- return array(
- 'resize' => '300,250'
- );
+ /**
+ * @author westonruter
+ * @covers Jetpack_Photon::filter_the_content
+ * @dataProvider photon_attributes_when_amp_response
+ * @since 7.6.0
+ *
+ * @param string $sample_html Sample HTML.
+ * @param string $photon_src Photon URL suffix (after the subdomain).
+ */
+ public function test_photon_filter_the_content_for_amp_responses( $sample_html, $photon_src ) {
+ add_filter( 'jetpack_is_amp_request', '__return_true' );
+ $filtered_content = Jetpack_Photon::filter_the_content( $sample_html );
+ $attributes = wp_kses_hair( $filtered_content, wp_allowed_protocols() );
+ $this->assertStringEndsWith( $photon_src, html_entity_decode( $attributes['src']['value'] ) );
+ $this->assertArrayHasKey( 'width', $attributes );
+ $this->assertArrayHasKey( 'height', $attributes );
+ $this->assertNotContains( 'data-recalc-dims', $filtered_content );
}
- public function photon_post_image_args_force_fit() {
+ /**
+ * Data provider for testing AMP responses.
+ *
+ * @return array
+ */
+ public function photon_attributes_when_amp_response() {
return array(
- 'fit' => '600,600'
+ 'amp-img' => array(
+ '',
+ '.wp.com/www.fishmadman.com/pages/wp-content/uploads/2012/02/Rav-fra-2004-2009-11-1024x611.jpg?resize=102%2C61',
+ ),
+ 'amp-anim' => array(
+ '',
+ '.wp.com/example.com/lol.gif?resize=32%2C32&ssl=1',
+ ),
);
}
- public function photon_post_image_args_force_lb() {
- return array(
- 'lb' => '800,100,000000'
+ /**
+ * @author westonruter
+ * @covers Jetpack_Photon::filter_the_content
+ * @covers Jetpack_AMP_Support::filter_photon_post_image_args_for_stories
+ * @since 7.6.0
+ */
+ public function test_photon_filter_the_content_for_amp_story() {
+ $post_type = 'amp_story';
+ add_filter( 'jetpack_is_amp_request', '__return_true' );
+ register_post_type( $post_type, array( 'public' => true ) );
+ Jetpack_AMP_Support::init();
+ $post = $this->factory()->post->create_and_get( compact( 'post_type' ) );
+ $this->go_to( get_permalink( $post ) );
+ $this->assertTrue( is_singular( $post_type ) );
+
+ $content = implode(
+ "\n",
+ array(
+ '',
+ '',
+ '',
+ )
);
- }
- public function photon_post_image_args_force_width_only() {
- return array(
- 'w' => '104'
+ $filtered_content = apply_filters( 'the_content', $content, $post->ID );
+
+ $this->assertContains(
+ '.wp.com/example.com/wp-content/uploads/2019/06/huge.jpg?h=1440&ssl=1',
+ $filtered_content
);
+
+ unregister_post_type( $post_type );
}
/**