Skip to content

Instantly share code, notes, and snippets.

@erikyo
Last active September 10, 2024 20:47
Show Gist options
  • Select an option

  • Save erikyo/ebd78f0d5d1735175e5ab9ad1d4d0590 to your computer and use it in GitHub Desktop.

Select an option

Save erikyo/ebd78f0d5d1735175e5ab9ad1d4d0590 to your computer and use it in GitHub Desktop.
While uploading a media into WordPress media library this script automatically generate a webp copy of the uploaded media. Works with jpg, png and pdf previews, add the .webp extension after the original name
<?php
// README: you need GD installed
function myprefix_explode_filepath( $filepath, $attachment_id ) {
$uploads = wp_upload_dir();
if ( strpos( $filepath, "/" ) == false ) {
return array( $uploads['basedir'], "", $filepath );
} else {
list( $year, $month, $filename ) = explode( '/', $filepath );
return array( $uploads['basedir'], "$year/$month", $filename );
}
}
function myprefix_explode_filename( $filename ) {
$filename_parts = explode( '.', $filename );
$fext = $filename_parts[ count( $filename_parts ) - 1 ];
unset( $filename_parts[ count( $filename_parts ) - 1 ] );
$fname = implode( '.', $filename_parts );
return array( $fname, $fext );
}
function save_webp_copy( $metadata, $attachment_id ) {
// PHP GD is required
if ( ! extension_loaded( 'gd' ) ) return $metadata;
// if the attachment doesn't contain resizes it isn't an image or document with previews (like pdf)
if (empty($metadata['sizes'])) return $metadata;
list( $basedir, $path, $filename ) = myprefix_explode_filepath( $metadata['file'], $attachment_id );
list( $fname, $fext ) = myprefix_explode_filename( $filename );
if ( isset( $metadata['mime-type'] ) ) {
if ( $metadata['mime-type'] == 'pdf' ) {
$file_collection = array_column( $metadata['sizes'], 'file' );
} else {
return true;
}
} else {
$file_collection = array_merge( array( $fname . "." . $fext ), array_column( $metadata['sizes'], 'file' ) );
}
switch ( $fext ) {
case 'jpg':
foreach ( $file_collection as $value ) {
$image = imagecreatefromjpeg( $basedir . '/' . $path . '/' . $value );
imagewebp( $image, $basedir . '/' . $path . '/' . $value . '.webp', 95 );
imagedestroy( $image );
}
break;
case 'png':
foreach ( $file_collection as $value ) {
$image = imagecreatefrompng( $basedir . '/' . $path . '/' . $value );
imagepalettetotruecolor( $image );
imagealphablending( $image, true );
imagesavealpha( $image, true );
imagewebp( $image, $basedir . '/' . $path . '/' . $value . '.webp', 90 );
imagedestroy( $image );
}
break;
default:
return false;
}
return $metadata;
}
add_filter( 'wp_generate_attachment_metadata', 'save_webp_copy', 30, 2 );
function delete_webp_copy( $post_id ) {
// get the file path for the image being deleted
$metadata = wp_get_attachment_metadata( $post_id );
list( $basedir, $path, $filename ) = myprefix_explode_filepath( $metadata['file'], $post_id );
list( $fname, $fext ) = myprefix_explode_filename( $filename );
// create a fake metadata/size to add the main image to remove list
$metadata["sizes"]["full"]["file"] = $fname . "." . $fext;
// remove the webp copy from using the metadata sizes as iterator
foreach ( $metadata['sizes'] as $file ) {
if ( isset( $file['file'] ) && file_exists( $basedir . '/' . $path . '/' . $file['file'] . '.webp' ) ) {
wp_delete_file( $basedir . '/' . $path . '/' . $file['file'] . '.webp' );
}
}
return $post_id;
}
add_filter( 'delete_attachment', 'delete_webp_copy' );
@fredddie91
Copy link

Hello, I am not sure under which folder to upload this file? Thanks

@erikyo
Copy link
Author

erikyo commented Oct 26, 2022

You have to place it inside functions.php of your WordPress template. 😉

@fredddie91
Copy link

Ok, erikyo, thanks.

@jamesnr
Copy link

jamesnr commented Sep 10, 2024

Erik, this is great and nicely creates a ".webp" copy. Thank you. When you upload the image to the server, the "webp" version is created. How did you get round the "webp" version not displaying in the Media Libray? This I think needs an update to the wp_postmeta table in the database and an update to the "_wp_attached_file" entry to either add the "webp" version or overlay the jpg version. Thoughts?

@erikyo
Copy link
Author

erikyo commented Sep 10, 2024

Just use your webserver (nginx,apache...) to serve the file replacing the extension. take a look at this post for details:
https://modul-r.codekraft.it/2021/09/how-to-serve-automatically-webp-images-with-nginx/

@jamesnr
Copy link

jamesnr commented Sep 10, 2024

Thanks Erik for the fast response. Those instructions look like they are only applicable if you're running nginx. Unfortunately running Apache. I can server webp images, that's all set up. When the new webp image is stored ideally the postmeta is updated with the correct URL, however, I appreciate this needs a little thought. The other approach would be to write a rewrite rule to request the webp impage, if all jpegs etc are converted to webp and server the jpeg should the webp not be found for some reason.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment