Im trying to generate responsive background images for my page header, using a modified version of this gist, but I cant get it to work correctly, and Im not sure if the issue is with wp_get_attachment_image_srcset
, wp_calculate_image_sizes
or the loop itself.
Here’s my code:
Responsive Image Size Attributes
function adjust_image_sizes_attr( $sizes, $size ) {
$width = $size[0];
if($width >= 1260){
$sizes="(max-width:575px) 575px, (max-width:767px) 767px, (max-width:991px) 991px, (max-width:1199px) 1199px, 1260px)";
}
elseif($width >= 900){
$sizes="(max-width:767px) 100vw, (max-width:991px) 631px, (max- width:1199px) 839px, 900px)";
}
elseif($width >= 600){
$sizes="(max-width:767px) 100vw, 600px";
}
else{
$sizes="(max-width: " . $width . 'px) 100vw, ' . $width . 'px';
}
return $sizes;
}
add_filter( 'wp_calculate_image_sizes', __NAMESPACE__ . '\\adjust_image_sizes_attr', 10 , 2 );
Generate Responsive Background Image CSS
function gsc_responsive_bg_images($attachment_id, $img_size, $selector)
{
$img_srcset = wp_get_attachment_image_srcset( $attachment_id, $img_size );
$sizes = explode( ", ", $img_srcset );
$css="";
$prev_size="";
foreach( $sizes as $size ) {
// Split up the size string, into an array with [0]=>img_url, [1]=>size
$split = explode( " ", $size );
if( !isset( $split[0], $split[1] ) )
continue;
$background_css=".gsc-page-title-bar {
background-image: url(" . esc_url( $split[0] ) . ')
}';
// Grab the previous image size as the min-width and/or add the background css to the main css string
if( !empty( $prev_size ) ) {
$css .= '@media only screen and (min-width: ' . $prev_size . ') {';
$css .= $background_css;
$css .= "}\n";
} else {
$css .= $background_css;
}
// Set the current image size as the "previous image" size, for use with media queries
$prev_size = str_replace( "w", "px", $split[1] );
}
return $css;
}
**My Output: (in shorthand) **
default.jpg (original dimensions: 1170w)
@min-width: 1170px -> 768w.jpg
@min-width: 768px -> 120w.jpg
@min-width: 120px -> 500w.jpg
@min-width: 500px -> 700w.jpg
@min-width: 700px -> 200w.jpg
@min-width: 400px -> 600w.jpg
@min-width: 600px -> 800w.jpg
I was expecting
Seeing this, Im left with a bunch of questions:
- Why is this the CSS code thats being returned? Shouldnt it be the smallest size being returned at the default breakpoint and the largest size at
@min-width:1170px
? Why does @min-width: 768px -> 120w.jpg
, and @min-width: 700px -> 200w.jpg
?
- Why are these the srcset images that are being generated? Shouldn’t they be 900px, 767px, 839px, 631px?
Any and all help appreciated!
I haven’t tested your code, but I recently spent a few hours hacking something together to solve the same issue — making background images set via the WordPress customizer load responsively. Feel free to use / modify the code below to your needs, and send any questions my way. I’m not a PHP expert by any measure, however.
3 things to note about the code below:
- I’m assuming you have already set up your customizer code, or are ok with just adding this CSS somewhere else via an echo / filter.
- This code uses a function to get an attachment’s ID based on its URL that was created by Micah Wood, who in turn credits this function developed by Andrey Savchenko (a.k.a. “Rarst”). I’ve included it as the second function below, but be sure to check out both links for more info.
- I’ve only targeted -webkit- with the pixel density, if you want to add other vendor prefixes (eg: -o-), that could be done.
Responsive Customizer Backgrounds
/**
* Create CSS Rules for Responsive BGs set via the WordPress Customizer.
*
* @uses get_attachment_id() Gets attachment id from $img_url
* @link https://wpscholar.com/blog/get-attachment-id-from-wp-image-url/
*
* @param string $selector The css selector set via customizer
* @param string $img_url The attachment url set via customizer
*
* @return string $responsive_css CSS rules on success, 0 on failure
*/
function responsive_customizer_bgs($selector="", $img_url="") {
// return var
$responsive_css = 0;
// get attachment id based on url (uses helper func)
$image_id = get_attachment_id( $img_url );
// get the src string from WP
$srcset_string = wp_get_attachment_image_srcset( $image_id, 'full' );
// parse srcset string into [url][int][width-or-pixel-density]
preg_match_all(
"/([^\s]*)\s(\d*)([w|x])/",
$srcset_string,
$srcset_matches,
PREG_SET_ORDER
);
// check if regex match was successful
if( is_array($srcset_matches) ) {
// cast int string into integer
for ($i=0; $i < count($srcset_matches); $i++) {
$srcset_matches[$i][2] = (int) $srcset_matches[$i][2];
}
// sort array of sizes by integer
usort($srcset_matches, function($a, $b) {
return $a[2] >= $b[2] ? -1 : 1;
});
// indexed loop to walk multi-dimensional array returned by regex
for ($i=0; $i < count($srcset_matches); $i++) {
// set media query statement based pixel size or pixel density
if ($srcset_matches[$i][3] === 'w') {
$media_query_match="max-width: " . $srcset_matches[$i][2] . 'px';
} else if ($srcset_matches[$i][3] === 'x') {
$media_query_match="-webkit-min-device-pixel-ratio: " . $srcset_matches[$i][2];
}
// create css rules and add to return string
$responsive_css .= PHP_EOL
. '@media only screen and (' . $media_query_match . ') {' . PHP_EOL
. ' ' . $selector . ' {' . PHP_EOL
. ' background-image: url(' . $srcset_matches[$i][1] . ');' . PHP_EOL
. ' }' . PHP_EOL
. '}';
}
// return that beautiful responsiveness
return $responsive_css;
}
}
Get Attachment ID Via URL
/**
* Get an attachment ID given a URL.
*
* @param string $url
*
* @return int Attachment ID on success, 0 on failure
*/
function get_attachment_id( $url ) {
$attachment_id = 0;
$dir = wp_upload_dir();
if ( false !== strpos( $url, $dir['baseurl'] . "https://wordpress.stackexchange.com/" ) ) { // Is URL in uploads directory?
$file = basename( $url );
$query_args = array(
'post_type' => 'attachment',
'post_status' => 'inherit',
'fields' => 'ids',
'meta_query' => array(
array(
'value' => $file,
'compare' => 'LIKE',
'key' => '_wp_attachment_metadata',
),
)
);
$query = new WP_Query( $query_args );
if ( $query->have_posts() ) {
foreach ( $query->posts as $post_id ) {
$meta = wp_get_attachment_metadata( $post_id );
$original_file = basename( $meta['file'] );
$cropped_image_files = wp_list_pluck( $meta['sizes'], 'file' );
if ( $original_file === $file || in_array( $file, $cropped_image_files ) ) {
$attachment_id = $post_id;
break;
}
}
}
}
return $attachment_id;
}