0

Wordpress srcset is a great feature but there are occasions when it's important to control exactly which image sizes are included in the srcset code.

For example, on one of our sites we generate a custom image size which is ONLY intended for external use - this means an external sales portal collects this image automatically for display on their site. It is NOT intended for display anywhere on our site.

However, the Wordpress srcset functionality currently includes ALL image sizes. For example:

<img width="350" height="426" src="https://xxx/wp-content/uploads/omega-pink-gold-1235-1-350x426.jpg" class="attachment-shop_catalog size-shop_catalog" alt="xxx" srcset="https://xxx/.../omega-pink-gold-1235-1-350x426.jpg 350w, https://xxx/.../omega-pink-gold-1235-1-246x300.jpg 246w, https://xxx/.../omega-pink-gold-1235-1-768x935.jpg 768w, https://xxx/.../omega-pink-gold-1235-1-841x1024.jpg 841w, https://xxx/.../omega-pink-gold-1235-1-1051x1280.jpg 1051w, https://xxx/.../omega-pink-gold-1235-1-534x650.jpg 534w, https://xxx/.../omega-pink-gold-1235-1-104x127.jpg 104w, https://xxx/.../omega-pink-gold-1235-1-595x725.jpg 595w, https://xxx/.../omega-pink-gold-1235-1-680x828.jpg 680w" sizes="(max-width: 350px) 100vw, 350px" title="xxx">

How can we control this better?

Thanks in advance for any help!

  • srcset will only include images with a matching aspect ratio, so the image should just be the original image at a smaller size. What's the problem with it being used in the srcset if the browser finds it useful? – Jacob Peattie Jan 23 '18 at 9:00
  • Since you don't display the image on your own site and only make the full-res image available to a third-party site, there's no need to generate all other image sizes. That I get. But what does this have to do with srcset? Are you sending the full <img> tag to the external sales portal instead of just the image URL? – swissspidy Jan 23 '18 at 9:19
  • @JacobPeattie - the custom image size intended for external use is branded with a watermark and therefore should never display on our website, only on the external sales portal – Richard Tinkler Jan 23 '18 at 14:14
2

WordPress allows you to hook into wp_calculate_image_srcset

See Core file on Trac

This filter gives you 5 arguments:

  • $sources One or more arrays of source data to include in the 'srcset'
  • $size_array Array of width and height values in pixels (in that order).
  • $image_src The 'src' of the image.
  • $image_meta The image meta data as returned by 'wp_get_attachment_metadata()
  • $attachment_id the post_id from the image

Here is a sample code you can use within your themes function.php or plugin files to get started:

add_filter( 'wp_calculate_image_srcset', 'my_custom_image_srcset', 10, 5);

function my_custom_image_srcset($sources, $size_array, $image_src, $image_meta, $attachment_id) {
    // The following code is an adaption from wp-includes/media.php:1061-1180
    $image_sizes = $image_meta['sizes'];

    // Get the width and height of the image.
    $image_width = (int) $size_array[0];
    $image_height = (int) $size_array[1];

    $image_basename = wp_basename( $image_meta['file'] );

    /*
     * WordPress flattens animated GIFs into one frame when generating intermediate sizes.
     * To avoid hiding animation in user content, if src is a full size GIF, a srcset attribute is not generated.
     * If src is an intermediate size GIF, the full size is excluded from srcset to keep a flattened GIF from becoming animated.
     */
    if ( ! isset( $image_sizes['thumbnail']['mime-type'] ) || 'image/gif' !== $image_sizes['thumbnail']['mime-type'] ) {
        $image_sizes[] = array(
            'width'  => $image_meta['width'],
            'height' => $image_meta['height'],
            'file'   => $image_basename,
        );
    } elseif ( strpos( $image_src, $image_meta['file'] ) ) {
        return false;
    }

    // Retrieve the uploads sub-directory from the full size image.
    $dirname = _wp_get_attachment_relative_path( $image_meta['file'] );

    if ( $dirname ) {
        $dirname = trailingslashit( $dirname );
    }

    $upload_dir = wp_get_upload_dir();
    $image_baseurl = trailingslashit( $upload_dir['baseurl'] ) . $dirname;

    /*
     * If currently on HTTPS, prefer HTTPS URLs when we know they're supported by the domain
     * (which is to say, when they share the domain name of the current request).
     */
    if ( is_ssl() && 'https' !== substr( $image_baseurl, 0, 5 ) && parse_url( $image_baseurl, PHP_URL_HOST ) === $_SERVER['HTTP_HOST'] ) {
        $image_baseurl = set_url_scheme( $image_baseurl, 'https' );
    }

    /*
     * Images that have been edited in WordPress after being uploaded will
     * contain a unique hash. Look for that hash and use it later to filter
     * out images that are leftovers from previous versions.
     */
    $image_edited = preg_match( '/-e[0-9]{13}/', wp_basename( $image_src ), $image_edit_hash );

    /**
     * Filters the maximum image width to be included in a 'srcset' attribute.
     *
     * @since 4.4.0
     *
     * @param int   $max_width  The maximum image width to be included in the 'srcset'. Default '1600'.
     * @param array $size_array Array of width and height values in pixels (in that order).
     */
    $max_srcset_image_width = apply_filters( 'max_srcset_image_width', 1600, $size_array );

    // Array to hold URL candidates.
    $sources = array();

    /**
     * To make sure the ID matches our image src, we will check to see if any sizes in our attachment
     * meta match our $image_src. If no matches are found we don't return a srcset to avoid serving
     * an incorrect image. See #35045.
     */
    $src_matched = false;

    /*
     * Loop through available images. Only use images that are resized
     * versions of the same edit.
     */
    foreach ( $image_sizes as $identifier => $image ) {
        // Continue if identifier is unwanted
        if ($identifier === 'unwanted-identifier') {
            continue;
        }

        $is_src = false;

        // Check if image meta isn't corrupted.
        if ( ! is_array( $image ) ) {
            continue;
        }

        // If the file name is part of the `src`, we've confirmed a match.
        if ( ! $src_matched && false !== strpos( $image_src, $dirname . $image['file'] ) ) {
            $src_matched = $is_src = true;
        }

        // Filter out images that are from previous edits.
        if ( $image_edited && ! strpos( $image['file'], $image_edit_hash[0] ) ) {
            continue;
        }

        /*
         * Filters out images that are wider than '$max_srcset_image_width' unless
         * that file is in the 'src' attribute.
         */
        if ( $max_srcset_image_width && $image['width'] > $max_srcset_image_width && ! $is_src ) {
            continue;
        }

        // If the image dimensions are within 1px of the expected size, use it.
        if ( wp_image_matches_ratio( $image_width, $image_height, $image['width'], $image['height'] ) ) {
            // Add the URL, descriptor, and value to the sources array to be returned.
            $source = array(
                'url'        => $image_baseurl . $image['file'],
                'descriptor' => 'w',
                'value'      => $image['width'],
            );

            // The 'src' image has to be the first in the 'srcset', because of a bug in iOS8. See #35030.
            if ( $is_src ) {
                $sources = array( $image['width'] => $source ) + $sources;
            } else {
                $sources[ $image['width'] ] = $source;
            }
        }
    }
    return $sources;
}
  • good answer and ALMOST what I need. There are several thousand images on the site and their original sizes all differ. Therefore, I don't always know what the $sources['unwanted-size'] will be. If your answer would allow me to exclude by image_size identifier (eg 'my_custom_image_size') as defined in add_image_size(), that would be perfect :) – Richard Tinkler Jan 24 '18 at 12:01
  • when I print_r($sources), the array keys are the current width values of each image and NOT the identifier as defined in add_image_size() – Richard Tinkler Jan 24 '18 at 18:41
  • U r right, I look it up in core, but found a solution. Will update my answer. – iantsch Jan 24 '18 at 19:15
-2

WordPress adds scrset attributes via a filter attached the the the_content hook.

add_filter( 'the_content', 'wp_make_content_images_responsive' ); line 141 of wp-includes/default-filters.php.

You can remove this filter via the remove_filter function like so:

remove_filter( 'the_content', 'wp_make_content_images_responsive' );

The above will remove srcset attributes site-wide so you may want to look at using the template hierarchy or conditional tags to remove the filter only where needed.

  • This doesn't really answer the question of how to exclude certain image sizes. This completely disables responsive images instead. – swissspidy Jan 23 '18 at 13:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.