1. Task
In this post, we will use Gumlet PHP Image Resize library to compress images uploaded to WordPress and then move them to Amazon S3 in one work session.
a. Pros and Cons
- Pros: By using a PHP library, we don’t need to pay for or install extra plugins
- Cons: Have to code, follow the maintenance of the Gumlet library and if other plugins are using also Gumlet there might be conflicts
b. Pre-requisites
For user who wants to make this workflow, before continuing please check that:
- You can install libraries with composer,
- You have access and rights to modify your plugin / theme where you want to perform this compress,
- You have credentials for S3 buckets where to store the images
c. Scope
This post consider two situations of image upload:
- When user upload image via a front-end form, and image will be submitted via $_FILES,
- When user upload with Media handler from WordPress function.
2. How to resize images in WordPress with Gumlet
a. Install Gumlet
First of all, we need to install Gumlet PHP Image Resize library to our theme/plugin. From now on, I’ll refer to the theme / plugin where we want to make the resize as “project folder”.
Instructions in GitHub page (https://github.com/gumlet/php-image-resize) is quite straightforward. What we need to do, is to add the image resize library to our composer.json. If the project folder does not have this file yet, just create it.
The file will contain in the require block:
"gumlet/php-image-resize": "2.0.*"
And if it is a total new composer.json file, it will look like:
{
"require": {
"gumlet/php-image-resize": "2.0.1",
"ext-gd": "*"
}
}
Currently I am using version 2.0.1 and it works well with WordPress 6.0.3.
After adding the line, go to the Terminal / Command line of the project folder and install it
composer install
This process will create a new vendor folder in the project. If you already have a vendor folder, this installation will add in to the existing folders inside vendor a new folder called gumlet.
b. Use Gumlet to resize image when user uploads via Media
If user uses Media handler to upload images, even in front end or in admin area, we can hook into a WordPress filter and start resizing the images when it gets into the system.
In the beginning of the function file (depends on your use case it can be functions.php, a separate function file or plugin classes), state the use of Gumlet then hook it to wp_handle_upload_prefilter filter:
use \Gumlet\ImageResize;
use \Gumlet\ImageResizeException;
require __DIR__ . '/../vendor/autoload.php';
// Using Gumlet to resize all images to width 1280
add_filter( 'wp_handle_upload_prefilter', 'ak_resize_image' );
function ak_resize_image($file) {
$images = array('image/png', 'image/jpg', 'image/jpeg');
if(in_array($file['type'], $images)) {
try {
$resize_image = new ImageResize($file['tmp_name']);
$resize_image->resizeToWidth(1280);
$resize_image->save($file['tmp_name']);
} catch( ImageResizeException $e ) {
// Something you want to do with the error,
// for example signaling Sentry
}
}
return $file;
}
/**
* WordPress already compresses images,
* but we can change the value to be a bit lower,
* to have lighter file
*/
add_filter( 'jpeg_quality', 'ak_change_compression_quality');
function ak_change_compression_quality() {
return 80;
}
Uploading to S3
For the media upload to directly upload to S3, you can use a plugin that make the route from Media to S3 more convenient, for example S3 Uploads by humanmade or WP Offload Media by Delicious Brain.
Once the route to S3 is set, all images that uploaded via Media will fly straight to S3, and the images that were resized by Gumlet also follows this way.
If you would like to upload an image to a separate folder of S3 programmatically, read on to the c section.
c. Resize images uploaded via front end form and move to a separate folder in S3
Let’s skip the front end form part and jump straight to server handler. Here, supposes that we have the image via $_FILES, let’s continue from here.
Like the above code, we need to start by stating the use of Gumlet in the beginning of the file. The function below lets us resize the avatar uploaded via front end file to 300 by the shorter side, then upload to an S3 folder name “avatar”. In my use case, I return the final URL of the S3 destination for the file or a WP_Error. You can tweak it based on your needs.
use \Gumlet\ImageResize;
use \Gumlet\ImageResizeException;
require __DIR__ . '/../vendor/autoload.php';
/**
* Resize image to be 300 in width with Gumlet
* Upload image to S3, folder 'avatar'
*/
function ak_upload_user_avatar($image)
{
$upload_dir = wp_upload_dir();
$image_type = $image_info[1];
// Do a quick validation for image type and size
// Avatar should be small
if ($image['type']) {
$valid = ['image/jpeg', 'image/jpg', 'image/png'];
if ( ! in_array($image['type'], $valid) || $image['size'] > 512000) {
return new WP_Error('upload-user-avatar', 'Wrong image format or file size exceeds 500kB.');
}
}
// Resize and compressing image using Gumlet php-image-resize
try {
$resize_avatar = new ImageResize($image['tmp_name']);
$resize_avatar->resizeToShortSide(300);
$resize_avatar->save($image['tmp_name']);
} catch (ImageResizeException $e) {
return new WP_Error('upload-user-avatar', 'Error when resizing.');
}
$file_path = $upload_dir['basedir'] . '/avatar/' . $image['name'];
$success = true;
if ( ! $success) {
return new WP_Error('upload-user-avatar', 'Can not upload avatar.');
}
return { S3_BASE_URL } . 'avatar/' . $image['name'];
}
When using the function, we can call:
$image_url = ak_upload_user_avatar($_FILES['avatar']);
For different projects, the location and how those functions were placed will be different. Hopefully this post can help to visualize the route of resizing images with Gumlet.