Skip to content

Commit

Permalink
Story block: Post Images support (#17198)
Browse files Browse the repository at this point in the history
* Support Story block in Jetpack_PostImages

* Skip attachment extraction for non-images

* Use the first good image for the open graph tag

* Move story image extraction to new function

* Use videopress poster images when available

* Use thumb metadata when available

* Revert "Use the first good image for the open graph tag"

This reverts commit 912f98f.

* Improve VideoPress on WP.com comment

* Add tests for post images extraction from Story block

* Consolidate get_attachment_data functions
  • Loading branch information
aforcier authored Oct 27, 2020
1 parent 4b2d3a0 commit 8446773
Show file tree
Hide file tree
Showing 2 changed files with 230 additions and 6 deletions.
46 changes: 40 additions & 6 deletions class.jetpack-post-images.php
Original file line number Diff line number Diff line change
Expand Up @@ -785,22 +785,44 @@ public static function get_attachment_data( $attachment_id, $post_url = '', $wid

$meta = wp_get_attachment_metadata( $attachment_id );

// The image must be larger than 200x200.
if ( ! isset( $meta['width'] ) || $meta['width'] < $width ) {
if ( empty( $meta ) ) {
return false;
}
if ( ! isset( $meta['height'] ) || $meta['height'] < $height ) {

if ( ! empty( $meta['videopress'] ) ) {
// Use poster image for VideoPress videos.
$url = $meta['videopress']['poster'];
$meta_width = $meta['videopress']['width'];
$meta_height = $meta['videopress']['height'];
} elseif ( ! empty( $meta['thumb'] ) ) {
// On WordPress.com, VideoPress videos have a 'thumb' property with the
// poster image filename instead.
$media_url = wp_get_attachment_url( $attachment_id );
$url = str_replace( wp_basename( $media_url ), $meta['thumb'], $media_url );
$meta_width = $meta['width'];
$meta_height = $meta['height'];
} elseif ( wp_attachment_is( 'video', $attachment_id ) ) {
// We don't have thumbnail images for non-VideoPress videos - skip them.
return false;
} else {
if ( ! isset( $meta['width'] ) || ! isset( $meta['height'] ) ) {
return false;
}
$url = wp_get_attachment_url( $attachment_id );
$meta_width = $meta['width'];
$meta_height = $meta['height'];
}

$url = wp_get_attachment_url( $attachment_id );
if ( $meta_width < $width || $meta_height < $height ) {
return false;
}

return array(
'type' => 'image',
'from' => 'attachment',
'src' => $url,
'src_width' => $meta['width'],
'src_height' => $meta['height'],
'src_width' => $meta_width,
'src_height' => $meta_height,
'href' => $post_url,
'alt_text' => self::get_alt_text( $attachment_id ),
);
Expand Down Expand Up @@ -859,6 +881,18 @@ private static function get_images_from_block( $images, $block, $html_info, $wid
foreach ( $block['attrs']['ids'] as $img_id ) {
$images[] = self::get_attachment_data( $img_id, $html_info['post_url'], $width, $height );
}
} elseif (
/**
* Parse content from Jetpack's Story block.
*/
'jetpack/story' === $block['blockName']
&& ! empty( $block['attrs']['mediaFiles'] )
) {
foreach ( $block['attrs']['mediaFiles'] as $media_file ) {
if ( ! empty( $media_file['id'] ) ) {
$images[] = self::get_attachment_data( $media_file['id'], $html_info['post_url'], $width, $height );
}
}
}

return $images;
Expand Down
190 changes: 190 additions & 0 deletions tests/php/media/test-class.jetpack-post-images.php
Original file line number Diff line number Diff line change
Expand Up @@ -404,4 +404,194 @@ public function test_from_columns_block_from_html_is_empty_array() {

$this->assertEmpty( $images );
}

/**
* Create a post with an image block containing a large image attached to another post.
*
* @since 9.1.0
*
* @param array $story_media A representative array of the media in the story. Each is one of 'image', 'video', or 'videopress'.
* @param bool $wpcom_mode If true, handles VideoPress videos the way WP.com does. Defaults to false.
* @return array $post_info {
* An array of information about our post.
* @type int $post_id Post ID.
* @type array $img_urls Image URLs we'll look to extract.
* }
*/
protected function get_post_with_story_block( $story_media, $wpcom_mode = false ) {
$media_items = array();
foreach ( $story_media as $story_media ) {
if ( 'image' === $story_media ) {
$media_items[] = array(
'name' => 'image.jpg',
'mime_type' => 'image/jpeg',
'type' => 'image',
);
} elseif ( 'videopress' === $story_media ) {
$media_items[] = array(
'name' => 'video.mp4',
'mime_type' => 'video/videopress',
'type' => 'video',
);
} elseif ( 'video' === $story_media ) {
$media_items[] = array(
'name' => 'video.mp4',
'mime_type' => 'video/mp4',
'type' => 'video',
);
}
}
$img_dimensions = array(
'width' => 1080,
'height' => 1920,
);

$post_id = $this->factory->post->create();

foreach ( $media_items as $key => $media ) {
$attachment_id = $this->factory->attachment->create_object(
$media['name'],
$post_id,
array(
'post_mime_type' => $media['mime_type'],
'post_type' => 'attachment',
)
);
wp_update_attachment_metadata( $attachment_id, $img_dimensions );

if ( 'video/videopress' === $media['mime_type'] ) {
if ( $wpcom_mode ) {
$videopress_meta = array(
'thumb' => str_replace( 'mp4', 'jpg', wp_basename( wp_get_attachment_url( $attachment_id ) ) ),
);
} else {
$videopress_meta = array(
'videopress' => array(
'poster' => str_replace( 'mp4', 'jpg', wp_get_attachment_url( $attachment_id ) ),
'width' => $img_dimensions['width'],
'height' => $img_dimensions['height'],
),
);
}

wp_update_attachment_metadata( $attachment_id, array_merge( $img_dimensions, $videopress_meta ) );
}

// Update our array to store attachment IDs. We'll need them later.
$media['attachment_id'] = $attachment_id;
$media['url'] = wp_get_attachment_url( $attachment_id );
unset( $media['name'] );
$media_items[ $key ] = $media;
}

$story_html = '<!-- wp:jetpack/story {"mediaFiles":[';
foreach ( $media_items as $media_item ) {
$story_html .= sprintf(
'{"alt":"","id":%1$d,"type":"%2$s","mime":"%3$s","caption":"","width":%4$d,"height":%5$d,"url":"%6$s"},',
$media_item['attachment_id'],
$media_item['type'],
$media_item['mime_type'],
$media_item['url'],
$img_dimensions['width'],
$img_dimensions['height']
);
}
$story_html = rtrim( $story_html, ',' );
$story_html .= ']} --><div class="wp-block-jetpack-story wp-story"></div><!-- /wp:jetpack/story -->';

// Create another post with that story.
$second_post_id = $this->factory->post->create( array( 'post_content' => $story_html ) );

$image_urls = array_map(
function( $element ) {
return $element['url'];
},
$media_items
);

return array(
'post_id' => $second_post_id,
'img_urls' => $image_urls,
);
}

/**
* Test if the array extracted from a Story block includes the correct image URLs.
*
* @covers Jetpack_PostImages::from_blocks
* @since 9.1.0
*/
public function test_from_story_block_from_post_id_is_correct_array_no_videopress() {
if ( ! function_exists( 'parse_blocks' ) ) {
$this->markTestSkipped( 'parse_blocks not available. Block editor not available' );
return;
}

$media_types = array( 'image', 'video' );
$post_info = $this->get_post_with_story_block( $media_types );

$images = Jetpack_PostImages::from_blocks( $post_info['post_id'] );

// We can't get a preview image for non-VideoPress video, so the video
// should have been skipped and only the image extracted.
$this->assertEquals( 1, count( $images ) );

$this->assertEquals( $post_info['img_urls'][0], $images[0]['src'] );
}

/**
* Test if the array extracted from a Story block includes the correct image URLs.
*
* For this test we simulate VideoPress being enabled for the site.
*
* @covers Jetpack_PostImages::from_blocks
* @since 9.1.0
*/
public function test_from_story_block_from_post_id_is_correct_array_videopress() {
if ( ! function_exists( 'parse_blocks' ) ) {
$this->markTestSkipped( 'parse_blocks not available. Block editor not available' );
return;
}

$media_types = array( 'image', 'videopress' );
$post_info = $this->get_post_with_story_block( $media_types );

$images = Jetpack_PostImages::from_blocks( $post_info['post_id'] );

$this->assertEquals( 2, count( $images ) );

$this->assertEquals( $post_info['img_urls'][0], $images[0]['src'] );

// The second media is a VideoPress video, so expect a poster URL.
$expected_poster_url = str_replace( 'mp4', 'jpg', $post_info['img_urls'][1] );
$this->assertEquals( $expected_poster_url, $images[1]['src'] );
}

/**
* Test if the array extracted from a Story block includes the correct image URLs.
*
* For this test we simulate 'WP.com mode' for VideoPress, which has a different structure for attachment meta.
*
* @covers Jetpack_PostImages::from_blocks
* @since 9.1.0
*/
public function test_from_story_block_from_post_id_is_correct_array_videopress_wpcom() {
if ( ! function_exists( 'parse_blocks' ) ) {
$this->markTestSkipped( 'parse_blocks not available. Block editor not available' );
return;
}

$media_types = array( 'image', 'videopress' );
$post_info = $this->get_post_with_story_block( $media_types, true );

$images = Jetpack_PostImages::from_blocks( $post_info['post_id'] );

$this->assertEquals( 2, count( $images ) );

$this->assertEquals( $post_info['img_urls'][0], $images[0]['src'] );

// The second media is a VideoPress video, so expect a poster URL.
$expected_poster_url = str_replace( 'mp4', 'jpg', $post_info['img_urls'][1] );
$this->assertEquals( $expected_poster_url, $images[1]['src'] );
}
} // end class

0 comments on commit 8446773

Please sign in to comment.