Skip to content

Commit

Permalink
fix: improve image size replacement mapping for custom image sizes
Browse files Browse the repository at this point in the history
  • Loading branch information
selul committed Jan 21, 2019
1 parent 3378cc3 commit d816ccb
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 153 deletions.
2 changes: 0 additions & 2 deletions inc/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,6 @@ public function parse_settings( $new_settings ) {
$sanitized_value = $this->to_map_values( $value, array( 'enabled', 'disabled' ), 'enabled' );
break;
case 'max_width':
case 'max_height':
case 'max_height':
case 'max_height':
$sanitized_value = $this->to_bound_integer( $value, 100, 5000 );
break;
Expand Down
173 changes: 99 additions & 74 deletions inc/tag_replacer.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,24 @@ final class Optml_Tag_Replacer extends Optml_App_Replacer {
*/
protected static $instance = null;

/**
* Class instance method.
*
* @codeCoverageIgnore
* @static
* @since 1.0.0
* @access public
* @return Optml_Tag_Replacer
*/
public static function instance() {
if ( is_null( self::$instance ) ) {
self::$instance = new self();
add_action( 'after_setup_theme', array( self::$instance, 'init' ) );
}

return self::$instance;
}

/**
* The initialize method.
*/
Expand All @@ -36,34 +54,6 @@ public function init() {
}
}

/**
* Extract image dimensions from img tag.
*
* @param string $tag The HTML img tag.
* @param array $image_sizes WordPress supported image sizes.
* @param array $args Default args to use.
*
* @return array
*/
private function parse_dimensions_from_tag( $tag, $image_sizes, $args = array() ) {
if ( preg_match( '#width=["|\']?([\d%]+)["|\']?#i', $tag, $width_string ) ) {
$args['width'] = $width_string[1];
}
if ( preg_match( '#height=["|\']?([\d%]+)["|\']?#i', $tag, $height_string ) ) {
$args['height'] = $height_string[1];
}
if ( preg_match( '#class=["|\']?[^"\']*size-([^"\'\s]+)[^"\']*["|\']?#i', $tag, $size ) ) {
$size = array_pop( $size );
if ( false === $args['width'] && false === $args['height'] && 'full' != $size && array_key_exists( $size, $image_sizes ) ) {
$args['width'] = (int) $image_sizes[ $size ]['width'];
$args['height'] = (int) $image_sizes[ $size ]['height'];
$args['resize'] = $this->to_optml_crop( $image_sizes[ $size ]['crop'] );
}
}

return array( $args['width'], $args['height'], $args['resize'] );
}

/**
* Called by hook to replace image tags in content.
*
Expand All @@ -76,7 +66,7 @@ public function process_image_tags( $content, $images = array() ) {
$image_sizes = self::image_sizes();
foreach ( $images[0] as $index => $tag ) {
$width = $height = false;
$resize = array( );
$resize = array();
$new_tag = $tag;
$src = $tmp = wp_unslash( $images['img_url'][ $index ] );
if ( apply_filters( 'optml_ignore_image_link', false, $src ) ||
Expand All @@ -86,11 +76,19 @@ public function process_image_tags( $content, $images = array() ) {
continue; // @codeCoverageIgnore
}

list( $width, $height, $resize ) = self::parse_dimensions_from_tag( $images['img_tag'][ $index ], $image_sizes, array( 'width' => $width, 'height' => $height, 'resize' => $resize ) );
list( $width, $height, $resize ) = self::parse_dimensions_from_tag(
$images['img_tag'][ $index ],
$image_sizes,
array(
'width' => $width,
'height' => $height,
'resize' => $resize,
)
);
if ( false === $width && false === $height ) {
list( $width, $height ) = $this->parse_dimensions_from_filename( $tmp );
}
$optml_args = $this->to_optml_dimensions_bound( $width, $height, $this->max_width, $this->max_height );
$optml_args = [ 'width' => $width, 'height' => $height ];
$tmp = $this->strip_image_size_from_url( $tmp );
$optml_args = array_merge( $optml_args, $resize );

Expand All @@ -110,9 +108,38 @@ public function process_image_tags( $content, $images = array() ) {

$content = str_replace( $tag, $new_tag, $content );
}

return $content;
}

/**
* Extract image dimensions from img tag.
*
* @param string $tag The HTML img tag.
* @param array $image_sizes WordPress supported image sizes.
* @param array $args Default args to use.
*
* @return array
*/
private function parse_dimensions_from_tag( $tag, $image_sizes, $args = array() ) {
if ( preg_match( '#width=["|\']?([\d%]+)["|\']?#i', $tag, $width_string ) ) {
$args['width'] = $width_string[1];
}
if ( preg_match( '#height=["|\']?([\d%]+)["|\']?#i', $tag, $height_string ) ) {
$args['height'] = $height_string[1];
}
if ( preg_match( '#class=["|\']?[^"\']*size-([^"\'\s]+)[^"\']*["|\']?#i', $tag, $size ) ) {
$size = array_pop( $size );
if ( false === $args['width'] && false === $args['height'] && 'full' != $size && array_key_exists( $size, $image_sizes ) ) {
$args['width'] = (int) $image_sizes[ $size ]['width'];
$args['height'] = (int) $image_sizes[ $size ]['height'];
$args['resize'] = $this->to_optml_crop( $image_sizes[ $size ]['crop'] );
}
}

return array( $args['width'], $args['height'], $args['resize'] );
}

/**
* Replaces the tags by default.
*
Expand Down Expand Up @@ -142,7 +169,7 @@ public function filter_srcset_attr( $sources = array(), $size_array = array(), $
if ( ! is_array( $sources ) ) {
return $sources;
}

$original_url = null;
foreach ( $sources as $i => $source ) {
$url = $source['url'];
list( $width, $height ) = $this->parse_dimensions_from_filename( $url );
Expand All @@ -154,13 +181,13 @@ public function filter_srcset_attr( $sources = array(), $size_array = array(), $
if ( empty( $height ) ) {
$height = $image_meta['height'];
}

if ( ! empty( $attachment_id ) ) {
$url = wp_get_attachment_url( $attachment_id );
} else {
$url = $this->strip_image_size_from_url( $source['url'] );
if ( $original_url === null ) {
if ( ! empty( $attachment_id ) ) {
$original_url = wp_get_attachment_url( $attachment_id );
} else {
$original_url = $this->strip_image_size_from_url( $source['url'] );
}
}

$args = array();
if ( 'w' === $source['descriptor'] ) {
if ( $height && ( $source['value'] == $width ) ) {
Expand All @@ -170,7 +197,7 @@ public function filter_srcset_attr( $sources = array(), $size_array = array(), $
$args['width'] = $source['value'];
}
}
$sources[ $i ]['url'] = apply_filters( 'optml_content_url', $url, $args );
$sources[ $i ]['url'] = apply_filters( 'optml_content_url', $original_url, $args );
}

return $sources;
Expand All @@ -185,6 +212,7 @@ public function filter_srcset_attr( $sources = array(), $size_array = array(), $
* @return mixed An array of media query breakpoints.
*/
public function filter_sizes_attr( $sizes, $size ) {

if ( ! doing_filter( 'the_content' ) ) {
return $sizes;
}
Expand All @@ -197,7 +225,6 @@ public function filter_sizes_attr( $sizes, $size ) {
if ( ! $content_width ) {
$content_width = 1000;
}

if ( is_array( $size ) && $size[0] < $content_width ) {
return $sizes;
}
Expand All @@ -224,31 +251,47 @@ public function filter_image_downsize( $image, $attachment_id, $size ) {

$image_meta = wp_get_attachment_metadata( $attachment_id );
$image_args = self::image_sizes();

// default size
$sizes = array(
'width' => isset( $image_meta['width'] ) ? intval( $image_meta['width'] ) : 'auto',
'height' => isset( $image_meta['height'] ) ? intval( $image_meta['height'] ) : 'auto',
'width' => isset( $image_meta['width'] ) ? intval( $image_meta['width'] ) : false,
'height' => isset( $image_meta['height'] ) ? intval( $image_meta['height'] ) : false,
);

// in case there is a custom image size $size will be an array.
if ( is_array( $size ) ) {
switch ( $size ) {
case is_array( $size ):
$width = isset( $size[0] ) ? (int) $size[0] : false;
$height = isset( $size[1] ) ? (int) $size[1] : false;
if ( ! $width || ! $height ) {
break;
}
$image_resized = image_resize_dimensions( $sizes['width'], $sizes['height'], $width, $height );
if ( $image_resized ) {
$width = $image_resized[6];
$height = $image_resized[7];
} else {
$width = $image_meta['width'];
$height = $image_meta['height'];
}
list( $sizes['width'], $sizes['height'] ) = image_constrain_size_for_editor( $width, $height, $size );

$sizes['width'] = ( $size[0] < $sizes['width'] ? $size[0] : $sizes['width'] );
$sizes['height'] = ( $size[1] < $sizes['height'] ? $size[1] : $sizes['height'] );
break;
case 'full' !== $size && isset( $image_args[ $size ] ):
$image_resized = image_resize_dimensions( $sizes['width'], $sizes['height'], $image_args[ $size ]['width'], $image_args[ $size ]['height'], $image_args[ $size ]['crop'] );

} elseif ( 'full' !== $size && isset( $image_args[ $size ] ) ) { // overwrite if there a size
if ( $image_resized ) { // This could be false when the requested image size is larger than the full-size image.
$sizes['width'] = $image_resized[6];
$sizes['height'] = $image_resized[7];
}

$sizes['width'] = $image_args[ $size ]['width'] < $sizes['width'] ? $image_args[ $size ]['width'] : $sizes['width'];
$sizes['height'] = $image_args[ $size ]['height'] < $sizes['height'] ? $image_args[ $size ]['height'] : $sizes['height'];
$sizes['resize'] = $this->to_optml_crop( $image_args[ $size ]['crop'] );
}
$new_sizes = $this->to_optml_dimensions_bound( $sizes['width'], $sizes['height'], $this->max_width, $this->max_height );
list( $sizes['width'], $sizes['height'] ) = image_constrain_size_for_editor( $sizes['width'], $sizes['height'], $size, 'display' );

$new_sizes = array_merge( $sizes, $new_sizes );
$sizes['resize'] = $this->to_optml_crop( $image_args[ $size ]['crop'] );

break;
}
$image_url = $this->strip_image_size_from_url( $image_url );

$new_url = apply_filters( 'optml_content_url', $image_url, $new_sizes );
$new_url = apply_filters( 'optml_content_url', $image_url, $sizes );

if ( $new_url === $image_url ) {
return $image;
Expand All @@ -258,28 +301,10 @@ public function filter_image_downsize( $image, $attachment_id, $size ) {
$new_url,
$sizes['width'],
$sizes['height'],
true,
$size === 'full',
);
}

/**
* Class instance method.
*
* @codeCoverageIgnore
* @static
* @since 1.0.0
* @access public
* @return Optml_Tag_Replacer
*/
public static function instance() {
if ( is_null( self::$instance ) ) {
self::$instance = new self();
add_action( 'after_setup_theme', array( self::$instance, 'init' ) );
}

return self::$instance;
}

/**
* Throw error on object clone
*
Expand Down
73 changes: 20 additions & 53 deletions inc/traits/normalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public function to_bound_integer( $value, $min, $max ) {
* @return integer
*/
public function to_positive_integer( $value ) {
$integer = intval( $value );
$integer = (int) $value;

return ( $integer > 0 ) ? $integer : 0;
}
Expand Down Expand Up @@ -107,52 +107,6 @@ public function to_accepted_quality( $value ) {
return 60;
}

/**
* Normalize dimensions to bounds.
*
* @param mixed $width Width.
* @param mixed $height Height.
* @param integer $max_width Max width.
* @param integer $max_height Max height.
*
* @return array
*/
public function to_optml_dimensions_bound( $width, $height, $max_width, $max_height ) {
global $content_width;

if (
doing_filter( 'the_content' )
&& isset( $GLOBALS['content_width'] )
&& apply_filters( 'optml_imgcdn_allow_resize_images_from_content_width', false )
) {
$content_width = (int) $GLOBALS['content_width'];

if ( $max_width > $content_width ) {
$max_width = $content_width;
}
}

if ( $width > $max_width ) {
// we need to remember how much in percentage the width was rescaled and apply the same treatment to the height.
$percentWidth = ( 1 - $max_width / $width ) * 100;
$width = $max_width;
$height = round( $height * ( ( 100 - $percentWidth ) / 100 ), 0 );
}

// now for the height
if ( $height > $max_height ) {
$percentHeight = ( 1 - $max_height / $height ) * 100;
// if we reduce the height to max_height by $x percentage than we'll also reduce the width for the same amount.
$height = $max_height;
$width = round( $width * ( ( 100 - $percentHeight ) / 100 ), 0 );
}

return array(
'width' => $width,
'height' => $height,
);
}

/**
* Normalize arguments for crop.
*
Expand All @@ -170,12 +124,21 @@ public function to_optml_crop( $crop_args = array() ) {
if ( $crop_args === false || ! is_array( $crop_args ) || count( $crop_args ) != 2 ) {
return array();
}

$allowed_x = [
'left' => true,
'center' => true,
'right' => true,
];
$allowed_y = [
'top' => true,
'center' => true,
'bottom' => true,
];
$allowed_gravities = array(
'left' => Optml_Resize::GRAVITY_WEST,
'right' => Optml_Resize::GRAVITY_EAST,
'top' => Optml_Resize::GRAVITY_NORTH,
'bottom' => Optml_Resize::GRAVITY_SOUTH,
'left' => Optml_Resize::GRAVITY_WEST,
'right' => Optml_Resize::GRAVITY_EAST,
'top' => Optml_Resize::GRAVITY_NORTH,
'bottom' => Optml_Resize::GRAVITY_SOUTH,
'lefttop' => Optml_Resize::GRAVITY_NORTH_WEST,
'leftbottom' => Optml_Resize::GRAVITY_SOUTH_WEST,
'righttop' => Optml_Resize::GRAVITY_NORTH_EAST,
Expand All @@ -187,7 +150,11 @@ public function to_optml_crop( $crop_args = array() ) {
);

$gravity = Optml_Resize::GRAVITY_CENTER;
$key_search = ( $crop_args[0] === true ? '' : $crop_args[0] ) . ( $crop_args[1] === true ? '' : $crop_args[1] );
$key_search = ( $crop_args[0] === true ? '' :
( isset( $allowed_x[ $crop_args[0] ] ) ? $crop_args[0] : '' ) ) .
( $crop_args[1] === true ? '' :
( isset( $allowed_y[ $crop_args[1] ] ) ? $crop_args[1] : '' ) );

if ( array_key_exists( $key_search, $allowed_gravities ) ) {
$gravity = $allowed_gravities[ $key_search ];
}
Expand Down
Loading

0 comments on commit d816ccb

Please sign in to comment.