Jetpack: lazy load processing order using blacklisted class

Created on 14 Mar 2018  Â·  4Comments  Â·  Source: Automattic/jetpack

I am attempting to use the new lazy load blacklisted class to prevent certain images in our theme from having lazy load attributes. I understand that this can be done by adding the class skip-lazy to the image HTML. (or another custom class that you can define in a filter)

This is actually a problem for us in our image galleries. We have a custom gallery implementation. However, the galleries still use the built-in gallery_shortcode to generate each img element, so that part is actually not custom.

I added the following filter immediately prior to output of gallery_shortcode, then remove the filter immediately after.

function jetpack_lazy( $attr ) {
    $attr['class'] .= ' skip-lazy';
    return $attr;
}
add_filter( 'wp_get_attachment_image_attributes', 'jetpack_lazy' );

When I view source, addition of this filter successfully adds the class 'skip-lazy' to each image element in the image gallery.

However, Jetpack still applies lazy load processing to the image and changes the src to the transparent gif.

I'm fairly certain this might be an ordering issue with filter firing and priority, but I'm struggling to figure it out. Any pointers or documentation would be appreciated.

Lazy Images [Pri] Normal [Status] Invalid [Type] Bug

Most helpful comment

Indeed, the issue is to pay more attention to our own code! I missed that. Thanks for the help.

All 4 comments

Hello @kevinlisota 👋–

I've created a test in #9127 to verify that the gallery images shouldn't be processed by lazy images if the skip-lazy class is added via the wp_get_attachment_image_attributes filter.

Based on that, my gut feeling is that it likely is a timing issue, which you mention above. Would you be able to give us some more information about your gallery implementation? Alternatively, if you're able to tweak the logic in #9127 so that it mimics your implementation, I'm glad to dig in to that as well.

Our gallery implementation looks like this. It uses gallery_shortcode to generate image HTML. I wrapped the called to gallery_shortcode with an add_filter and remove_filter to add in the skip-lazy class.

add_shortcode('gallery', 'fotorama_gallery_shortcode');

function fotorama_gallery_shortcode($atts)
{
    if (!$atts) {
        $atts = array();
    }

    if ((array_key_exists('fotorama', $atts) && $atts['fotorama'] == 'false') || is_feed()) {
        return gallery_shortcode($atts);
    }

    $atts['link'] = 'file';
    $atts['itemtag'] = 'dl';
    $atts['icontag'] = 'dt';
    $atts['captiontag'] = 'dd';
    $atts['columns'] = 0;

    if (array_key_exists('orderby', $atts) && $atts['orderby'] == 'rand') {
        $atts['orderby'] = '';
        $atts['shuffle'] = 'true';
    }

    $atts['size'] = 'thumbnail';
    add_filter( 'wp_get_attachment_image_attributes', 'jetpack_lazy' );
    $gallery = gallery_shortcode($atts);
    remove_filter( 'wp_get_attachment_image_attributes', 'jetpack_lazy' );

    $width = array_key_exists('width', $atts) ? $atts['width'] : '';
    $height = array_key_exists('height', $atts) ? $atts['height'] : '';

    $atts['size'] = 'large';
    preg_match_all('/(<img[^<>]*>).*\n*.*<\/dt/', gallery_shortcode($atts), $images);
    preg_match_all('/href=(\'|")([^"\']+)(\'|").*\n*.*<\/dt/', $gallery, $hrefs);

    for ($i = 0, $l = count($images[0]); $i < $l; $i++) {
        $image = $images[1][$i];
        preg_match('/src=(\'|")([^"\']+)(\'|")/', $image, $src);

        if (!$i) {
            preg_match('/width=(\'|")([^"\']+)(\'|")/', $image, $__width);
            $_width = $__width[2];

            preg_match('/height=(\'|")([^"\']+)(\'|")/', $image, $__height);
            $_height = $__height[2];

            if (!$width) {
                $atts['width'] = $_width;
            }

            if (!$height) {
                $height = $_height;
            }
        }

        $quote = $hrefs[1][$i];
        $full = $hrefs[2][$i];

        $gallery = str_replace($quote . $full . $quote,
            $quote . $src[2] . $quote . ' data-full=' . $quote . $full . $quote,
            $gallery);
    }

    $atts['auto'] = 'false';
    $atts['max-width'] = '100%';
    $atts['ratio'] = array_key_exists('ratio', $atts) ? $atts['ratio'] : ($_width && $_height ? $_width / $_height : '');

    $data = '';
    foreach ($atts as $key => $value) {
        if ($key != 'fotorama') {
            $data .= "data-$key='$value'";
        }
    }

    return "<div class='fotorama--wp' $data>$gallery</div>";
}

function jetpack_lazy( $attr ) {
    $attr['class'] .= ' skip-lazy';
    return $attr;
}

The issue seems to be that you're calling gallery_shortcode() twice, and by the second time you've called it, you've already removed the filter. This seems to work for me:

add_shortcode('gallery', 'fotorama_gallery_shortcode');

function fotorama_gallery_shortcode($atts)
{
    if (!$atts) {
        $atts = array();
    }

    if ((array_key_exists('fotorama', $atts) && $atts['fotorama'] == 'false') || is_feed()) {
        return gallery_shortcode($atts);
    }

    $atts['link'] = 'file';
    $atts['itemtag'] = 'dl';
    $atts['icontag'] = 'dt';
    $atts['captiontag'] = 'dd';
    $atts['columns'] = 0;

    if (array_key_exists('orderby', $atts) && $atts['orderby'] == 'rand') {
        $atts['orderby'] = '';
        $atts['shuffle'] = 'true';
    }

    $atts['size'] = 'thumbnail';
    add_filter( 'wp_get_attachment_image_attributes', 'jetpack_lazy' );
    $gallery = gallery_shortcode($atts);

    $width = array_key_exists('width', $atts) ? $atts['width'] : '';
    $height = array_key_exists('height', $atts) ? $atts['height'] : '';

    $atts['size'] = 'large';
    preg_match_all('/(<img[^<>]*>).*\n*.*<\/dt/', gallery_shortcode($atts), $images);
    preg_match_all('/href=(\'|")([^"\']+)(\'|").*\n*.*<\/dt/', $gallery, $hrefs);

    remove_filter( 'wp_get_attachment_image_attributes', 'jetpack_lazy' );

    for ($i = 0, $l = count($images[0]); $i < $l; $i++) {
        $image = $images[1][$i];
        preg_match('/src=(\'|")([^"\']+)(\'|")/', $image, $src);

        if (!$i) {
            preg_match('/width=(\'|")([^"\']+)(\'|")/', $image, $__width);
            $_width = $__width[2];

            preg_match('/height=(\'|")([^"\']+)(\'|")/', $image, $__height);
            $_height = $__height[2];

            if (!$width) {
                $atts['width'] = $_width;
            }

            if (!$height) {
                $height = $_height;
            }
        }

        $quote = $hrefs[1][$i];
        $full = $hrefs[2][$i];

        $gallery = str_replace($quote . $full . $quote,
            $quote . $src[2] . $quote . ' data-full=' . $quote . $full . $quote,
            $gallery);
    }

    $atts['auto'] = 'false';
    $atts['max-width'] = '100%';
    $atts['ratio'] = array_key_exists('ratio', $atts) ? $atts['ratio'] : ($_width && $_height ? $_width / $_height : '');

    $data = '';
    foreach ($atts as $key => $value) {
        if ($key != 'fotorama') {
            $data .= "data-$key='$value'";
        }
    }

    return "<div class='fotorama--wp' $data>$gallery</div>";
}

function jetpack_lazy( $attr ) {
    $attr['class'] .= ' skip-lazy';
    return $attr;
}

Note that remove_filter( 'wp_get_attachment_image_attributes', 'jetpack_lazy' ); is after the second call to gallery_shortcode() which happens a few lines above with preg_match_all('/(<img[^<>]*>).*\n*.*<\/dt/', gallery_shortcode($atts), $images);.

I'm going to go ahead and close for now as it works for me, but I'm glad to reopen if moving that line doesn't fix the issue for you and you think it's an issue with our lazy images implementation.

Indeed, the issue is to pay more attention to our own code! I missed that. Thanks for the help.

Was this page helpful?
0 / 5 - 0 ratings