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

Lazy Images: Allow filtering out images via class and attributes #8787

Merged
merged 3 commits into from
Feb 13, 2018
Merged
Show file tree
Hide file tree
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
62 changes: 60 additions & 2 deletions modules/lazy-images/lazy-images.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,45 @@ public function add_image_placeholders( $content ) {
return $content;
}

/**
* Returns true when a given string of classes contains a class signifying lazy images
* should not process the image.
*
* @since 5.9.0
*
* @param string $classes A string of space-separated classes.
* @return bool
*/
public static function should_skip_image_with_blacklisted_class( $classes ) {
$blacklisted_classes = array(
'skip-lazy',
'gazette-featured-content-thumbnail',
);

/**
* Allow plugins and themes to tell lazy images to skip an image with a given class.
*
* @module lazy-images
*
* @since 5.9.0
*
* @param array An array of strings where each string is a class.
*/
$blacklisted_classes = apply_filters( 'jetpack_lazy_images_blacklisted_classes', $blacklisted_classes );

if ( ! is_array( $blacklisted_classes ) || empty( $blacklisted_classes ) ) {
return false;
}

foreach ( $blacklisted_classes as $class ) {
if ( false !== strpos( $classes, $class ) ) {
return true;
}
}

return false;
}

/**
* Processes images in content by acting as the preg_replace_callback
*
Expand All @@ -131,6 +170,12 @@ static function process_image( $matches ) {

$old_attributes = self::flatten_kses_hair_data( $old_attributes_kses_hair );
$new_attributes = self::process_image_attributes( $old_attributes );

// If we didn't add lazy attributes, just return the original image source.
if ( empty( $new_attributes['data-lazy-src'] ) ) {
return $matches[0];
}

$new_attributes_str = self::build_attributes_string( $new_attributes );

return sprintf( '<img %1$s><noscript>%2$s</noscript>', $new_attributes_str, $matches[0] );
Expand All @@ -151,8 +196,21 @@ static function process_image_attributes( $attributes ) {
return $attributes;
}

// check for gazette featured images, which are incompatible
if ( isset( $attributes['class'] ) && false !== strpos( $attributes['class'], 'gazette-featured-content-thumbnail' ) ) {
if ( ! empty( $attributes['class'] ) && self::should_skip_image_with_blacklisted_class( $attributes['class'] ) ) {
return $attributes;
}

/**
* Allow plugins and themes to conditionally skip processing an image via its attributes.
*
* @module-lazy-images
*
* @since 5.9.0
*
* @param bool Default to not skip processing the current image.
* @param array An array of attributes via wp_kses_hair() for the current image.
*/
if ( apply_filters( 'jetpack_lazy_images_skip_image_with_atttributes', false, $attributes ) ) {
return $attributes;
}

Expand Down
103 changes: 103 additions & 0 deletions tests/php/modules/lazy-images/test_class.lazy-images.php
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,105 @@ function test_compat_with_wp_kses_post() {
$this->assertContains( 'data-lazy-size', $with_lazy_sizes );
}

/**
* @dataProvider get_dont_process_images_with_classes_data
*/
function test_dont_process_images_with_classes( $input, $should_skip = true ) {
$instance = Jetpack_Lazy_Images::instance();
$output = $instance->add_image_placeholders( $input );

if ( $should_skip ) {
$this->assertNotContains( 'src="placeholder.jpg"', $output );
} else {
$this->assertContains( 'src="placeholder.jpg"', $output );
}
}

function get_dont_process_images_with_classes_data() {
return array(
'skip_lazy' => array(
'<img src="image.jpg" srcset="medium.jpg 1000w, large.jpg 2000w" class="skip-lazy"/>',
),
'gazette_theme_featured_image' => array(
'<img src="image.jpg" srcset="medium.jpg 1000w, large.jpg 2000w" class="attachment-gazette-featured-content-thumbnail wp-post-image"/>',
),
'does_not-skip' => array(
'<img src="image.jpg" srcset="medium.jpg 1000w, large.jpg 2000w" class="wp-post-image"/>',
false,
),
);
}

/**
* @dataProvider get_should_skip_image_with_blacklisted_class_data
*/
function test_should_skip_image_with_blacklisted_class( $expected, $input, $empty_blacklisted_classes = false ) {
$this->assertSame( $expected, Jetpack_Lazy_Images::should_skip_image_with_blacklisted_class( $input ) );
}

function get_should_skip_image_with_blacklisted_class_data() {
return array(
'wp-post-image' => array(
false,
'wp-post-image'
),
'skip-lazy' => array(
true,
'wp-post-image skip-lazy',
),
'gazette-feature' => array(
true,
'wp-post-image attachment-gazette-featured-content-thumbnail',
),
);
}

/**
* @dataProvider get_should_skip_image_with_filtered_empty_blacklist_data
*/
function test_should_skip_image_with_filtered_empty_blacklist( $classes ) {
$filter_callbacks = array(
'__return_empty_string',
'__return_empty_array',
);

foreach ( $filter_callbacks as $callback ) {
add_filter( 'jetpack_lazy_images_blacklisted_classes', $callback );
$this->assertSame( false, Jetpack_Lazy_Images::should_skip_image_with_blacklisted_class( $classes ) );
remove_filter( 'jetpack_lazy_images_blacklisted_classes', $callback );
}
}

function get_should_skip_image_with_filtered_empty_blacklist_data() {
return array(
'wp-post-image' => array(
'wp-post-image'
),
'skip-lazy' => array(
'wp-post-image skip-lazy',
),
'gazette-feature' => array(
'wp-post-image attachment-gazette-featured-content-thumbnail',
),
);
}

function test_jetpack_lazy_images_skip_image_with_atttributes_filter() {
$instance = Jetpack_Lazy_Images::instance();
$src = '<img src="image.jpg" srcset="medium.jpg 1000w, large.jpg 2000w" class="wp-post-image"/>';

$this->assertContains( 'src="placeholder.jpg"', $instance->add_image_placeholders( $src ) );

add_filter( 'jetpack_lazy_images_skip_image_with_atttributes', '__return_true' );
$this->assertNotContains( 'src="placeholder.jpg"', $instance->add_image_placeholders( $src ) );
remove_filter( 'jetpack_lazy_images_skip_image_with_atttributes', '__return_true' );

add_filter( 'jetpack_lazy_images_skip_image_with_atttributes', array( $this, '__skip_if_srcset' ), 10, 2 );
$this->assertNotContains( 'src="placeholder.jpg"', $instance->add_image_placeholders( $src ) );
$this->assertContains( 'src="placeholder.jpg"', $instance->add_image_placeholders( '<img src="image.jpg" />' ) );
remove_filter( 'jetpack_lazy_images_skip_image_with_atttributes', array( $this, '__skip_if_srcset' ), 10, 2 );
}

/*
* Helpers
*/
Expand Down Expand Up @@ -246,4 +345,8 @@ public function __get_output_content() {

return trim( $contents );
}

public function __skip_if_srcset( $should_skip, $attributes ) {
return isset( $attributes['srcset'] );
}
}