Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tiled Gallery block: Add server render srcset #11397

Merged
merged 7 commits into from
Apr 29, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 141 additions & 13 deletions extensions/blocks/tiled-gallery/tiled-gallery.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php
<?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName

/**
* Tiled Gallery block. Depends on the Photon module.
*
Expand All @@ -7,28 +8,131 @@
* @package Jetpack
*/

if (
( defined( 'IS_WPCOM' ) && IS_WPCOM ) ||
class_exists( 'Jetpack_Photon' ) && Jetpack::is_module_active( 'photon' )
) {
jetpack_register_block(
'jetpack/tiled-gallery',
array(
'render_callback' => 'jetpack_tiled_gallery_load_block_assets',
)
);
/**
* Jetpack Tiled Gallery Block class
*
* @since 7.3
*/
class Jetpack_Tiled_Gallery_Block {
sirreal marked this conversation as resolved.
Show resolved Hide resolved
/* Values for building srcsets */
const IMG_SRCSET_WIDTH_MAX = 2000;
sirreal marked this conversation as resolved.
Show resolved Hide resolved
const IMG_SRCSET_WIDTH_MIN = 600;
const IMG_SRCSET_WIDTH_STEP = 300;

/**
* Register the block
*/
public static function register() {
jetpack_register_block(
'jetpack/tiled-gallery',
array(
'render_callback' => array( __CLASS__, 'render' ),
)
);
}

/**
* Tiled gallery block registration/dependency declaration.
* Tiled gallery block registration
*
* @param array $attr Array containing the block attributes.
* @param string $content String containing the block content.
*
* @return string
*/
function jetpack_tiled_gallery_load_block_assets( $attr, $content ) {
sirreal marked this conversation as resolved.
Show resolved Hide resolved
public static function render( $attr, $content ) {
Jetpack_Gutenberg::load_assets_as_required( 'tiled-gallery' );

$is_squareish_layout = self::is_squareish_layout( $attr );

if ( preg_match_all( '/<img [^>]+>/', $content, $images ) ) {
/**
* This block processes all of the images that are found and builds $find and $replace.
*
* The original img is added to the $find array and the replacement is made and added
* to the $replace array. This is so that the same find and replace operations can be
* made on the entire $content.
*/
$find = array();
$replace = array();

foreach ( $images[0] as $image_html ) {
if (
preg_match( '/data-width="([0-9]+)"/', $image_html, $img_height )
&& preg_match( '/data-height="([0-9]+)"/', $image_html, $img_width )
&& preg_match( '/src="([^"]+)"/', $image_html, $img_src )
) {
// Drop img src query string so it can be used as a base to add photon params
// for the srcset.
$src_parts = explode( '?', $img_src[1], 2 );
$orig_src = $src_parts[0];
$orig_height = absint( $img_height[1] );
$orig_width = absint( $img_width[1] );

// Because URLs are already "photon", the photon function used short-circuits
// before ssl is added. Detect ssl and add is if necessary.
$is_ssl = ! empty( $src_parts[1] ) && false !== strpos( $src_parts[1], 'ssl=1' );

if ( ! $orig_width || ! $orig_height || ! $orig_src ) {
continue;
}

$srcset_parts = array();
if ( $is_squareish_layout ) {
Copy link
Member

@simison simison Apr 25, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't we at this point just see square images anyway since that's how they're saved from the editor, without even checking for the type of layout?

I'm hoping we would not need this if/else here at all and this section would be more simple.

This might be useful here, too: https://developer.wordpress.org/reference/functions/wp_constrain_dimensions/

That said, totally not a blocker and ok to merge as-is. :-)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the branch with a lot of very similar code is appealing, but also a fair bit of work for little benefit. I looked at it when implementing these changes and considered this was good enough.

I can take another look (or you're welcome to) if you think it's worth it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nah, merging and deploying is more fun than reworking this out. 👍

$min_width = min( self::IMG_SRCSET_WIDTH_MIN, $orig_width, $orig_height );
$max_width = min( self::IMG_SRCSET_WIDTH_MAX, $orig_width, $orig_height );

for ( $w = $min_width; $w <= $max_width; $w = min( $max_width, $w + self::IMG_SRCSET_WIDTH_STEP ) ) {
$srcset_src = add_query_arg(
array(
'resize' => $w . ',' . $w,
'strip' => 'all',
),
$orig_src
);
if ( $is_ssl ) {
$srcset_src = add_query_arg( 'ssl', '1', $srcset_src );
}
$srcset_parts[] = esc_url( $srcset_src ) . ' ' . $w . 'w';
if ( $w >= $max_width ) {
break;
}
}
} else {
$min_width = min( self::IMG_SRCSET_WIDTH_MIN, $orig_width );
$max_width = min( self::IMG_SRCSET_WIDTH_MAX, $orig_width );

for ( $w = $min_width; $w <= $max_width; $w = min( $max_width, $w + self::IMG_SRCSET_WIDTH_STEP ) ) {
$srcset_src = add_query_arg(
array(
'strip' => 'all',
'w' => $w,
),
$orig_src
);
if ( $is_ssl ) {
$srcset_src = add_query_arg( 'ssl', '1', $srcset_src );
}
$srcset_parts[] = esc_url( $srcset_src ) . ' ' . $w . 'w';
if ( $w >= $max_width ) {
break;
}
}
}

if ( ! empty( $srcset_parts ) ) {
$srcset = 'srcset="' . esc_attr( implode( ',', $srcset_parts ) ) . '"';
sirreal marked this conversation as resolved.
Show resolved Hide resolved

sirreal marked this conversation as resolved.
Show resolved Hide resolved
$find[] = $image_html;
$replace[] = str_replace( '<img', '<img ' . $srcset, $image_html );
}
}
}

if ( ! empty( $find ) ) {
$content = str_replace( $find, $replace, $content );
}
}

/**
* Filter the output of the Tiled Galleries content.
*
Expand All @@ -40,4 +144,28 @@ function jetpack_tiled_gallery_load_block_assets( $attr, $content ) {
*/
return apply_filters( 'jetpack_tiled_galleries_block_content', $content );
}

/**
* Determines whether a Tiled Gallery block uses square or circle images (1:1 ratio)
*
* Layouts are block styles and will be available as `is-style-[LAYOUT]` in the className
* attribute. The default (rectangular) will be omitted.
*
* @param {Array} $attr Attributes key/value array.
* @return {boolean} True if layout is squareish, otherwise false.
*/
private static function is_squareish_layout( $attr ) {
return isset( $attr['className'] )
&& (
'is-style-square' === $attr['className']
|| 'is-style-circle' === $attr['className']
);
}
}

if (
( defined( 'IS_WPCOM' ) && IS_WPCOM )
|| class_exists( 'Jetpack_Photon' ) && Jetpack::is_module_active( 'photon' )
) {
Jetpack_Tiled_Gallery_Block::register();
}