diff --git a/README.md b/README.md index 43e61aa..6d8816a 100644 --- a/README.md +++ b/README.md @@ -26,25 +26,26 @@ HappyPrime\ThemeImageBlock\register_theme_image( 'description' => 'The Happy Prime logo.', 'alt' => 'Happy Prime', 'path' => 'images/happy-prime-logo.svg', - 'width' => '', + 'width' => '300', 'height' => '', - 'sizes' => [ + 'variations' => [ 'small' => [ 'path' => 'images/happy-prime-logo-small.svg', - 'width' => 100, - 'height' => 100, + 'width' => '100', + 'height' => '100', ], 'medium' => [ 'path' => 'images/happy-prime-logo-medium.svg', - 'width' => 200, - 'height' => 200, + 'width' => '200', + 'height' => '200', ], 'large' => [ 'path' => 'images/happy-prime-logo-large.svg', - 'width' => 300, - 'height' => 300, + 'width' => '300', + 'height' => '300', ], ], + 'sizes' => '(max-width: 600px) 100vw, 300px', ] ); ``` @@ -63,9 +64,10 @@ Registers a theme image for use in the Theme Image block. - `description` (string, optional): Description of the image. - `alt` (string, optional): Default alt text for accessibility. - `path` (string, required): Path to the image file relative to the theme directory. - - `width` (string, optional): Default width value. - - `height` (string, optional): Default height value. - - `sizes` (array, optional): Array of size variations. + - `width` (string, optional): Width of the main image in pixels. Used to build the srcset attribute. + - `height` (string, optional): Height of the main image in pixels. + - `variations` (array, optional): Array of image variations with different sizes. Each variation should include `path`, `width`, and `height`. Used to build the srcset attribute. + - `sizes` (string, optional): Value for the HTML sizes attribute. Controls which image size the browser selects from srcset based on layout. Example: `(max-width: 600px) 100vw, 300px`. **Returns:** Boolean indicating success. @@ -83,7 +85,9 @@ Registers a theme image for use in the Theme Image block. ## Features - **PHP-based registration**: Register images from your theme or plugin code -- **Rich metadata**: Include titles, descriptions, alt text, and size variations +- **Rich metadata**: Include titles, descriptions, alt text, and image variations +- **Responsive images**: Automatic srcset generation from registered variations for optimal image loading +- **Custom sizes attribute**: Define custom sizes strings to control responsive image selection - **Flexible dimensions**: Support for all CSS units and functions (px, %, rem, clamp, calc, etc.) - **Inline SVG support**: Render SVG files inline for better styling control - **Link support**: Add links to images with target and rel options diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 315afa6..376be56 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -3,3 +3,4 @@ includes: parameters: level: 9 + treatPhpDocTypesAsCertain: false diff --git a/src/Block.php b/src/Block.php index 0bb0836..87f6d08 100644 --- a/src/Block.php +++ b/src/Block.php @@ -49,6 +49,34 @@ public static function render( $attributes, $content ): string { $width = isset( $attributes['width'] ) && ! empty( $attributes['width'] ) ? esc_attr( $attributes['width'] ) : ''; $height = isset( $attributes['height'] ) && ! empty( $attributes['height'] ) ? esc_attr( $attributes['height'] ) : ''; + // Build srcset from registered variations. + $srcset_parts = array(); + + // Add the main image if it has a width. + if ( ! empty( $image_data['width'] ) ) { + $srcset_parts[] = sprintf( + '%s %sw', + esc_url( get_template_directory_uri() . '/' . $image_data['path'] ), + (int) $image_data['width'] + ); + } + + // Add variations if they have width and path. + if ( ! empty( $image_data['variations'] ) && is_array( $image_data['variations'] ) ) { + foreach ( $image_data['variations'] as $variation ) { + if ( ! empty( $variation['width'] ) && ! empty( $variation['path'] ) ) { + $srcset_parts[] = sprintf( + '%s %sw', + esc_url( get_template_directory_uri() . '/' . $variation['path'] ), + (int) $variation['width'] + ); + } + } + } + + $srcset = ! empty( $srcset_parts ) ? implode( ', ', $srcset_parts ) : ''; + $sizes = ! empty( $image_data['sizes'] ) ? esc_attr( $image_data['sizes'] ) : ''; + // Construct the image path from the registered image data. $image_path = realpath( get_template_directory() . '/' . $image_data['path'] ); $theme_dir = realpath( get_template_directory() ); @@ -104,8 +132,19 @@ public static function render( $attributes, $content ): string { } } - if ( $html->next_tag( array( 'tag_name' => 'img' ) ) && ! empty( $inline_styles ) ) { - $html->set_attribute( 'style', implode( '; ', $inline_styles ) ); + // This seems to be the best way to rewind and seek again? Seems strange. + $html = new \WP_HTML_Tag_Processor( $html->get_updated_html() ); + + if ( $html->next_tag( array( 'tag_name' => 'img' ) ) ) { + if ( ! empty( $inline_styles ) ) { + $html->set_attribute( 'style', implode( '; ', $inline_styles ) ); + } + if ( ! empty( $srcset ) ) { + $html->set_attribute( 'srcset', $srcset ); + } + if ( ! empty( $sizes ) ) { + $html->set_attribute( 'sizes', $sizes ); + } } $content = $html->get_updated_html(); diff --git a/src/Registry.php b/src/Registry.php index ce8b554..3e02c46 100644 --- a/src/Registry.php +++ b/src/Registry.php @@ -21,7 +21,8 @@ class Registry { * path: string, * width: string, * height: string, - * sizes: array + * variations: array, + * sizes: string * }> */ private static array $images = array(); @@ -39,7 +40,8 @@ class Registry { * @type string $path Path to the image file relative to the theme directory (required). * @type string $width Default width value (optional). * @type string $height Default height value (optional). - * @type array $sizes Array of size variations (optional). + * @type array $variations Array of image variations for srcset (optional). + * @type string $sizes Value for the sizes attribute (optional). * } * * @return bool True if registered successfully, false otherwise. @@ -79,7 +81,8 @@ public static function register( string $slug, array $args ): bool { 'path' => '', 'width' => '', 'height' => '', - 'sizes' => array(), + 'variations' => array(), + 'sizes' => '', ); $args = wp_parse_args( $args, $defaults ); @@ -92,7 +95,8 @@ public static function register( string $slug, array $args ): bool { 'path' => sanitize_text_field( $args['path'] ), 'width' => sanitize_text_field( $args['width'] ), 'height' => sanitize_text_field( $args['height'] ), - 'sizes' => self::sanitize_sizes( $args['sizes'] ), + 'variations' => self::sanitize_variations( $args['variations'] ), + 'sizes' => sanitize_text_field( $args['sizes'] ), ); return true; @@ -108,7 +112,8 @@ public static function register( string $slug, array $args ): bool { * path: string, * width: string, * height: string, - * sizes: array + * variations: array, + * sizes: string * }> Registered images, keyed by image slug. */ public static function get_all(): array { @@ -127,7 +132,8 @@ public static function get_all(): array { * path: string, * width: string, * height: string, - * sizes: array + * variations: array, + * sizes: string * }|null Image data or null if not found. */ public static function get( string $slug ): ?array { @@ -184,6 +190,7 @@ public static function get_for_editor(): array { 'alt' => $data['alt'], 'width' => $data['width'], 'height' => $data['height'], + 'variations' => $data['variations'], 'sizes' => $data['sizes'], ); } @@ -192,20 +199,20 @@ public static function get_for_editor(): array { } /** - * Sanitize size variations. + * Sanitize image variations. * - * @param mixed $sizes Size variations. + * @param mixed $variations Image variations. * - * @return array Sanitized sizes. + * @return array Sanitized variations. */ - private static function sanitize_sizes( $sizes ): array { - if ( ! is_array( $sizes ) ) { + private static function sanitize_variations( $variations ): array { + if ( ! is_array( $variations ) ) { return array(); } $sanitized = array(); - foreach ( $sizes as $size => $data ) { + foreach ( $variations as $size => $data ) { if ( ! is_array( $data ) ) { continue; } diff --git a/theme-image-block.php b/theme-image-block.php index e195d51..c604b88 100644 --- a/theme-image-block.php +++ b/theme-image-block.php @@ -72,7 +72,8 @@ * @type string $path Path to the image file relative to the theme directory (required). * @type string $width Default width value (optional). * @type string $height Default height value (optional). - * @type array $sizes Array of size variations (optional). + * @type array $variations Array of image variations for srcset (optional). + * @type string $sizes Value for the sizes attribute (optional). * } * * @return bool True if registered successfully, false otherwise.