Skip to content

Commit

Permalink
Closes #766: Add avif format to picture element (#781)
Browse files Browse the repository at this point in the history
  • Loading branch information
jeawhanlee authored Jan 16, 2024
1 parent fc76130 commit ec0bf15
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 26 deletions.
132 changes: 110 additions & 22 deletions classes/Webp/Picture/Display.php → classes/Picture/Display.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?php
namespace Imagify\Webp\Picture;
namespace Imagify\Picture;

defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );

Expand Down Expand Up @@ -259,24 +259,65 @@ protected function build_picture_tag( $image ) {
* @return string A <source> tag.
*/
protected function build_source_tag( $image ) {
$source = '';

foreach ( [ 'webp', 'avif' ] as $image_type ) {
$attributes = $this->build_source_attributes( $image, $image_type );

if ( empty( $attributes ) ) {
continue;
}

$source .= '<source' . $this->build_attributes( $attributes ) . "/>\n";
}

return $source;
}

/**
* Build the attribute for the source tag.
*
* @param array $image An array of data.
* @param string $image_type Type of image.
* @return array
*/
protected function build_source_attributes( array $image, string $image_type ): array {
$mime_type = '';
$url = '';

switch ( $image_type ) {
case 'webp':
$mime_type = 'image/webp';
$url = 'webp_url';
break;
case 'avif':
$mime_type = 'image/avif';
$url = 'avif_url';
break;
}

$srcset_source = ! empty( $image['srcset_attribute'] ) ? $image['srcset_attribute'] : $image['src_attribute'] . 'set';
$attributes = [
'type' => 'image/webp',
'type' => $mime_type,
$srcset_source => [],
];

if ( ! empty( $image['srcset'] ) ) {
foreach ( $image['srcset'] as $srcset ) {
if ( empty( $srcset['webp_url'] ) ) {
if ( empty( $srcset[ $url ] ) ) {
continue;
}

$attributes[ $srcset_source ][] = $srcset['webp_url'] . ' ' . $srcset['descriptor'];
$attributes[ $srcset_source ][] = $srcset[ $url ] . ' ' . $srcset['descriptor'];
}
}

if ( empty( $attributes[ $srcset_source ] ) && empty( $image['src'][ $url ] ) ) {
return [];
}

if ( empty( $attributes[ $srcset_source ] ) ) {
$attributes[ $srcset_source ][] = $image['src']['webp_url'];
$attributes[ $srcset_source ][] = $image['src'][ $url ];
}

$attributes[ $srcset_source ] = implode( ', ', $attributes[ $srcset_source ] );
Expand Down Expand Up @@ -309,7 +350,7 @@ protected function build_source_tag( $image ) {
*/
$attributes = apply_filters( 'imagify_picture_source_attributes', $attributes, $image );

return '<source' . $this->build_attributes( $attributes ) . "/>\n";
return $attributes;
}

/**
Expand Down Expand Up @@ -426,12 +467,23 @@ protected function get_images( $content ) {
}

foreach ( $images as $i => $image ) {
if ( empty( $image['src']['webp_exists'] ) || empty( $image['src']['webp_url'] ) ) {
if ( ( empty( $image['src']['webp_exists'] ) || empty( $image['src']['webp_url'] ) ) &&
( empty( $image['src']['avif_exists'] ) || empty( $image['src']['avif_url'] ) ) ) {

unset( $images[ $i ] );
continue;
}

if ( empty( $image['src']['webp_exists'] ) || empty( $image['src']['webp_url'] ) ) {
unset( $images[ $i ]['src']['webp_url'] );
}

if ( empty( $image['src']['avif_exists'] ) || empty( $image['src']['avif_url'] ) ) {
unset( $images[ $i ]['src']['avif_url'] );
}

unset( $images[ $i ]['src']['webp_path'], $images[ $i ]['src']['webp_exists'] );
unset( $images[ $i ]['src']['avif_path'], $images[ $i ]['src']['avif_exists'] );

if ( empty( $image['srcset'] ) || ! is_array( $image['srcset'] ) ) {
unset( $images[ $i ]['srcset'] );
Expand All @@ -443,11 +495,22 @@ protected function get_images( $content ) {
continue;
}

if ( ( empty( $srcset['webp_exists'] ) || empty( $srcset['webp_url'] ) ) &&
( empty( $srcset['avif_exists'] ) || empty( $srcset['avif_url'] ) ) ) {
unset( $images[ $i ]['srcset'][ $j ]['webp_url'] );
unset( $images[ $i ]['srcset'][ $j ]['avif_url'] );
}

if ( empty( $srcset['webp_exists'] ) || empty( $srcset['webp_url'] ) ) {
unset( $images[ $i ]['srcset'][ $j ]['webp_url'] );
}

if ( empty( $srcset['avif_exists'] ) || empty( $srcset['avif_url'] ) ) {
unset( $images[ $i ]['srcset'][ $j ]['avif_url'] );
}

unset( $images[ $i ]['srcset'][ $j ]['webp_path'], $images[ $i ]['srcset'][ $j ]['webp_exists'] );
unset( $images[ $i ]['srcset'][ $j ]['avif_path'], $images[ $i ]['srcset'][ $j ]['avif_exists'] );
}
}

Expand Down Expand Up @@ -527,24 +590,21 @@ protected function process_image( $image ) {
return false;
}

$webp_url = imagify_path_to_webp( $src['src'] );
$webp_path = $this->url_to_path( $webp_url );
$webp_url .= ! empty( $src['query'] ) ? $src['query'] : '';

$data = [
'tag' => $image,
'attributes' => $attributes,
'src_attribute' => $src_source,
'src' => [
'url' => $attributes[ $src_source ],
'webp_url' => $webp_url,
'webp_path' => $webp_path,
'webp_exists' => $webp_path && $this->filesystem->exists( $webp_path ),
],
'srcset_attribute' => false,
'srcset' => [],
];

foreach ( $this->get_next_gen_image_data_set( $src ) as $key => $value ) {
$data['src'][ $key ] = $value;
}

// Deal with the srcset attribute.
$srcset_source = false;

Expand All @@ -556,6 +616,8 @@ protected function process_image( $image ) {
}

if ( $srcset_source ) {
$srcset_data = [];

$data['srcset_attribute'] = $srcset_source;

$srcset = explode( ',', $attributes[ $srcset_source ] );
Expand All @@ -582,17 +644,16 @@ protected function process_image( $image ) {
continue;
}

$webp_url = imagify_path_to_webp( $src['src'] );
$webp_path = $this->url_to_path( $webp_url );
$webp_url .= ! empty( $src['query'] ) ? $src['query'] : '';

$data['srcset'][] = [
$srcset_data = [
'url' => $srcs[0],
'descriptor' => $srcs[1],
'webp_url' => $webp_url,
'webp_path' => $webp_path,
'webp_exists' => $webp_path && $this->filesystem->exists( $webp_path ),
];

foreach ( $this->get_next_gen_image_data_set( $src ) as $key => $value ) {
$srcset_data[ $key ] = $value;
}

$data['srcset'][] = $srcset_data;
}
}

Expand All @@ -618,6 +679,33 @@ protected function process_image( $image ) {
return $data;
}

/**
* Get the next gen image(webp & avif) data set.
*
* @param array $src Array of url/path segments.
* @return array
*/
protected function get_next_gen_image_data_set( array $src ): array {
$webp_url = imagify_path_to_next_gen( $src['src'], 'webp' );
$webp_path = $this->url_to_path( $webp_url );

$avif_url = imagify_path_to_next_gen( $src['src'], 'avif' );
$avif_path = $this->url_to_path( $avif_url );
$query_string = ! empty( $src['query'] ) ? $src['query'] : '';

return [
// WebP data set.
'webp_url' => $webp_url . $query_string,
'webp_path' => $webp_path,
'webp_exists' => $webp_path && $this->filesystem->exists( $webp_path ),

// Avif data set.
'avif_url' => $avif_url . $query_string,
'avif_path' => $avif_path,
'avif_exists' => $avif_path && $this->filesystem->exists( $avif_path ),
];
}

/**
* Tell if a content is HTML.
*
Expand Down
3 changes: 2 additions & 1 deletion classes/Webp/Display.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

use Imagify\Notices\Notices;
use Imagify\Traits\InstanceGetterTrait;
use Imagify\Picture\Display as PictureDisplay;

/**
* Display WebP images on the site.
Expand Down Expand Up @@ -31,7 +32,7 @@ public function init() {
add_action( 'imagify_activation', [ $this, 'activate' ] );
add_action( 'imagify_deactivation', [ $this, 'deactivate' ] );

Picture\Display::get_instance()->init();
PictureDisplay::get_instance()->init();
RewriteRules\Display::get_instance()->init();
}

Expand Down
2 changes: 1 addition & 1 deletion inc/3rd-party/amazon-s3-and-cloudfront/classes/Main.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public function store_s3_settings( $as3cf ) {
* WebP images to display with a <picture> tag.
*
* @since 1.9
* @see \Imagify\Webp\Picture\Display->process_image()
* @see \Imagify\Picture\Display->process_image()
* @author Grégory Viguier
*
* @param array $data An array of data for this image.
Expand Down
2 changes: 1 addition & 1 deletion inc/classes/class-imagify-options.php
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ public function sanitize_and_validate_value( $key, $value, $default ) {
return $reset_values[ $key ];

case 'cdn_url':
$cdn_source = \Imagify\Webp\Picture\Display::get_instance()->get_cdn_source( $value );
$cdn_source = \Imagify\Picture\Display::get_instance()->get_cdn_source( $value );

if ( 'option' !== $cdn_source['source'] ) {
/**
Expand Down
1 change: 1 addition & 0 deletions inc/functions/attachments.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ function imagify_get_mime_types( $type = null ) {
'png' => 'image/png',
'gif' => 'image/gif',
'webp' => 'image/webp',
'avif' => 'image/avif',
];
}

Expand Down
26 changes: 26 additions & 0 deletions inc/functions/common.php
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,32 @@ function imagify_path_to_webp( $path ) {
return $path . '.webp';
}

/**
* Convert a path (or URL) to its next-gen version.
* To keep the function simple:
* - Not tested if it's an image.
* - File existance is not tested.
* - If an URL is given, make sure it doesn't contain query args.
*
* @since 2.2
*
* @param string $path A file path or URL.
* @param string $format format we are targeting.
* @return string
*/
function imagify_path_to_next_gen( $path, string $format ) {
switch ( $format ) {
case 'webp':
$path = $path . '.webp';
break;
case 'avif':
$path = $path . '.avif';
break;
}

return $path;
}

/**
* Tell if the current user can optimize custom folders.
*
Expand Down
2 changes: 1 addition & 1 deletion views/part-settings-webp.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use Imagify\Stats\OptimizedMediaWithoutWebp;
use Imagify\Webp\Display;
use Imagify\Webp\Picture\Display as PictureDisplay;
use Imagify\Picture\Display as PictureDisplay;

defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );

Expand Down

0 comments on commit ec0bf15

Please sign in to comment.