A quick and dirt way to make your site retroactively compatible with AVIF
Tags: wordpress
Published: 2024-04-04 14:21:45

(originally published on [Medium](https://phalkmin.medium.com/a-quick-and-dirt-way-to-make-your-site-retroactively-compatible-with-avif-352829299afe)) 

So, WordPress 6.5 is out, and with him finally .avif files are natively accepted, without the need for extra plugins or too complicated solutions. What this means, exactly? Smaller images, without the loss of quality that we see on JPEG compression. We are talking about a reduction from 900kb to 50kb without loss, which sometimes is even better than the already cool WEBP format!

And, as AVIF is a free format, it’s easy to implement and use. Most programs accept export to AVIF and you can even do it directly in the terminal if you use MacOS or Linux.

"Cool, but how do I use it?"

The WordPress documentation says that just this snippet on the theme or a plugin is enough to change all JPEGs and PNGs to AVIF during upload:

```
function filter_image_editor_output_format( $formats ) {
    $formats['image/jpeg'] = 'image/avif';
    $formats['image/png'] = 'image/avif';
    return $formats;
}
add_filter( 'image_editor_output_format', 'filter_image_editor_output_format' );
```

and you can even set the compression level using the snippet below:

```
// Use a quality setting of 75 for AVIF images.
function filter_avif_quality( $quality, $mime_type ) {
 if ( 'image/avif' === $mime_type ) {
  return 75;
 }
 return $quality;
}
add_filter( 'wp_editor_set_quality', 'filter_avif_quality', 10, 2 );
```

where 75 is the compression level. If you want a lossless conversion, just set it to 100.

But there is a small problem: how to deal with a large library of images that already exists on your site? Many plugins do bulk compression, but as most of them run first on PHP, they can hog some extra resources from the server. A faster alternative is to run the script below, if your server has ImageMagick installed it will work flawlessly:

```#!/bin/bash

# Set the path to your WordPress uploads directory
UPLOADS_DIR="/your/path/to/uploads/folder"

# List of image file extensions to convert
IMAGE_EXTENSIONS=("jpg" "jpeg" "png")

# Iterate through the uploads directory and convert images to AVIF format
for FILE in $(find $UPLOADS_DIR -type f); do
    FILENAME=$(basename -- "$FILE")
    EXTENSION="${FILENAME##*.}"
    if [[ " ${IMAGE_EXTENSIONS[@]} " =~ " $EXTENSION " ]]; then
        AVIF_FILENAME="${FILENAME%.*}.avif"
        if [ ! -f "$UPLOADS_DIR/$AVIF_FILENAME" ]; then
            # Convert the image to AVIF format using imagemagick
            convert "$FILE" "$UPLOADS_DIR/$AVIF_FILENAME"
            echo "Converted $FILE to AVIF format: $AVIF_FILENAME"
        else
            echo "AVIF version of $FILE already exists: $AVIF_FILENAME"
        fi
    fi
done
```

And… done. This script will scan your uploads folder for images and convert them to AVIF. Most of the time, just this is needed, but even after this it is possible that you will need to explicitly tell WordPress to load the new images, using the code below on your theme or a plugin:

```
function avif_replace_image_urls($content) {
    $uploads_dir = wp_upload_dir();
    $upload_path = $uploads_dir['basedir'];
    $upload_url = $uploads_dir['baseurl'];
    
    // Find image URLs in the content
    preg_match_all('/<img.*?src=["\'](.*?)["\'].*?>/i', $content, $matches);

    if (!empty($matches[1])) {
        foreach ($matches[1] as $image_url) {
            // Get the filename and extension
            $image_path = str_replace($upload_url, $upload_path, $image_url);
            $filename = basename($image_path);
            $extension = pathinfo($filename, PATHINFO_EXTENSION);

            // Check if AVIF version exists
            $avif_filename = str_replace('.' . $extension, '.avif', $filename);
            $avif_path = str_replace($filename, $avif_filename, $image_path);

            if (file_exists($avif_path)) {
                // Replace original image URL with AVIF version
                $avif_url = str_replace($upload_path, $upload_url, $avif_path);
                $content = str_replace($image_url, $avif_url, $content);
            }
        }
    }

    return $content;
}
add_filter('the_content', 'avif_replace_image_urls');
```
Remember that if your visitor uses some old browsers, the images won't load. In this case, it's better to use a plugin or a JS that does the check and loads the original image as a fallback. Also, as said in the title: quick and dirt method, there may be a need for adjustments if you want a cleaner solution :P