0

I have written this function code for compressing and converting uploading images to WebP format using Imagick and adding them to media library and delete the original uploading file format.

I've written this function at WordPress Theme Functions (functions.php):

/*
 * Compress and convert to WebP for uploading images
 */
function compress_and_convert_images_to_webp($file) {
    // Check if file type is supported
    $supported_types = ['image/jpeg', 'image/jpg', 'image/png'];
    if (!in_array($file['type'], $supported_types)) {
        return $file;
    }

    // Get the path to the upload directory
    $wp_upload_dir = wp_upload_dir();

    // Set up the file paths
    $old_file_path = $file['file'];
    $file_name = basename($file['file']);
    $webp_file_path = $wp_upload_dir['path'] . '/' . pathinfo($file_name, PATHINFO_FILENAME) . '.webp';
    
    // Check if file is already a WebP image
    if (pathinfo($old_file_path, PATHINFO_EXTENSION) === 'webp') {
        return $file;
    }

    // Load the image using Imagick
    $image = new Imagick($old_file_path);

    // Compress the image
    $quality = 75; // Adjust this value to control the compression level
    $image->setImageCompressionQuality($quality);
    $image->stripImage(); // Remove all profiles and comments to reduce file size

    // Convert the image to WebP
    $image->setImageFormat('webp');
    $image->setOption('webp:lossless', 'false');
    $image->setOption('webp:method', '6'); // Adjust this value to control the compression level for WebP
    $image->writeImage($webp_file_path);
    
    // Allow WebP mime type
    add_filter('upload_mimes', function($mimes) {
        $mimes['webp'] = 'image/webp';
        return $mimes;
    });
    
    // Set file permissions to 0644
    chmod($webp_file_path, 0644);

    // Add the new WebP image to the media library
    $attachment_id = media_handle_upload(pathinfo($file_name, PATHINFO_FILENAME), 0, [
        'post_mime_type' => 'image/webp',
        'file' => $webp_file_path
    ]);
    
    if (is_wp_error($attachment_id)) {
        error_log("The Attachment ID Error is: " . $attachment_id->get_error_message());
    }

    // Delete the old image file
    unlink($old_file_path);

    // Update the attachment metadata with the WebP image URL
    update_post_meta($attachment_id, '_wp_attached_file', substr($webp_file_path, strlen($wp_upload_dir['basedir']) + 1));
    
    // Return the updated file information
    return [
        'file' => $webp_file_path,
        'url' => wp_get_attachment_url($attachment_id),
        'type' => 'image/webp',
    ];
}
add_filter('wp_handle_upload', 'compress_and_convert_images_to_webp');

This code works fine and compress and convert uploading image files and show them in media library and deletes uploading original format but it raise warnings every time I upload new file.

I've searched about warnings and they are about "$attachment_id" variable problem:

as you can see this variable uses "media_handle_upload" function for getting new attachment ID but it returns this error (WP_ERROR object):

"Specified file failed upload test.".

the warning messages are:

PHP Warning:  Trying to access array offset on value of type null in wp-admin/includes/file.php on line 906

PHP Deprecated:  is_uploaded_file(): Passing null to parameter #1 ($filename) of type string is deprecated in wp-admin/includes/file.php on line 906

PHP Warning:  Object of class WP_Error could not be converted to int in wp-includes/post.php on line 6590

What should I do?

Misagh Mi
  • 61
  • 1
  • 5

1 Answers1

1

Finally I've found out the problem:

as I said before, this function works fine but has some warnings. To resolve the warnings I omitted the parts that related to media_handle_upload and update_post_meta.

The final code is:

/**
 * Compress and convert to WebP for uploading images
 */
function compress_and_convert_images_to_webp($file) {
    // Check if file type is supported
    $supported_types = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp'];
    if (!in_array($file['type'], $supported_types)) {
        return $file;
    }

    // Get the path to the upload directory
    $wp_upload_dir = wp_upload_dir();

    // Set up the file paths
    $old_file_path = $file['file'];
    $file_name = basename($file['file']);
    $webp_file_path = $wp_upload_dir['path'] . '/' . pathinfo($file_name, PATHINFO_FILENAME) . '.webp';

    // Check if file is already a WebP image
    if (pathinfo($old_file_path, PATHINFO_EXTENSION) === 'webp') {
        return $file;
    }

    // Load the image using Imagick
    $image = new Imagick($old_file_path);

    // Compress the image
    $quality = 75; // Adjust this value to control the compression level
    $image->setImageCompressionQuality($quality);
    $image->stripImage(); // Remove all profiles and comments to reduce file size

    // Convert the image to WebP
    $image->setImageFormat('webp');
    $image->setOption('webp:lossless', 'false');
    $image->setOption('webp:method', '6'); // Adjust this value to control the compression level for WebP
    $image->writeImage($webp_file_path);

    // Delete the old image file
    unlink($old_file_path);

    // Return the updated file information
    return [
        'file' => $webp_file_path,
        'url' => $wp_upload_dir['url'] . '/' . basename($webp_file_path),
        'type' => 'image/webp',
    ];
}
add_filter('wp_handle_upload', 'compress_and_convert_images_to_webp');
Misagh Mi
  • 61
  • 1
  • 5
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community May 09 '23 at 20:40