cache = CacheManager::for('images')->connectTo('post', 'attachment'); if (JVB_TESTING) { $this->cache->clear(); } } public function formatImage(int $ID, string $start = 'tiny', string $replace = 'large', bool $addLink = true, ?string $postSlug = null):string { $return = $this->cache->remember( ['ID' => $ID, 'start' => $start, 'replace' => $replace], function() use ($ID, $start, $replace) { // Define size order for progressive enhancement $sizeOrder = ['tiny', 'directory-preview', 'thumbnail', 'medium', 'large', 'full']; $startIndex = array_search($start, $sizeOrder); $replaceIndex = array_search($replace, $sizeOrder); // Fallback if invalid sizes provided if ($startIndex === false) $startIndex = 0; if ($replaceIndex === false) $replaceIndex = 2; // Get all images up to the replace size $images = []; for ($i = $startIndex; $i <= $replaceIndex; $i++) { $img = wp_get_attachment_image_src($ID, $sizeOrder[$i]); if ($img) { $images[$sizeOrder[$i]] = $img; } } if (empty($images)) return ''; // Use first available image as src $firstImage = reset($images); $alt = get_post_meta($ID, '_wp_attachment_image_alt', true); $alt = ($alt=='')? '' : ' alt="'.esc_attr($alt).'" '; // Build srcset only with images from start to replace $srcsetParts = []; foreach ($images as $img) { $srcsetParts[] = sprintf('%s %dw', $img[0], $img[1]); } $srcset = implode(', ', $srcsetParts); return sprintf( '', $firstImage[0], $alt, $srcset ); } ); if ($addLink) { if (!$postSlug) { global $post; $postSlug = $post->post_name; } $full = wp_get_attachment_image_src($ID, 'full'); $imgPost = get_post($ID); if (!$imgPost) return $return; $imgSlug = $imgPost->post_name; $galleryAttrs = sprintf( ' data-gallery="gallery-%s" data-focus="%s-%s" data-full="%s"', $postSlug, $postSlug, $imgSlug, $full[0] ); // Add gallery attributes to img tag $return = str_replace('