Generate image size, based on the image-orientation

Here is my working solution.
The code is documented, so it should be clear what each function does.

I pretty much use the wp_generate_attachment_metadata filter to create the needed images after the image has been uploaded.

The generated images are listed in the metadata too, like any other intermediate image size. That way you can pretty much work with them like with any other image size.

Another important part is to use the delete_attachment filter to delte the generated images.

// ==========================
// Custom Image Size Handling
// ==========================

/**
 * Removes default and plugin generated image sizes.
 * This is optional!
 */
function r21_remove_image_sizes($sizes) {
  unset($sizes['thumbnail']);
  unset($sizes['medium']);
  unset($sizes['large']);

  return $sizes;
}
add_filter('intermediate_image_sizes', 'r21_remove_image_sizes');
add_filter('intermediate_image_sizes_advanced', 'r21_remove_image_sizes');


/**
 * Generate a handle for thumbnail regeneration tools.
 * The custom images will always be regenerated after one of
 * the site wide image sizes have been regenerated.
 * The problem here is, that if there are no site wide image sizes
 * defined, you can not regenerate any custom size images.
 * To avoid this we create a 1x1 px image that works as handle, if there
 * are no other imge sizes.
 */
add_image_size( 'cstm-img-regeneration-handle' , 1, 1, array( 'left', 'top' ));


/**
 * Delete unneeded generated images and their metadata.
 * Also deletes images, generated in the filter, this is why
 * this function has to be used before the image generation function.
 *
 * @param array $attachment_meta
 * @return array
 */
function r21_remove_old_image_sizes($attachment_meta) {

  foreach ($attachment_meta['sizes'] as $size_name => $size_data) {
    // Ceck if image size is currently an active intermediate image size
    if (array_key_exists($size_name, get_intermediate_image_sizes())) { continue; }

    // Delete file
    @ unlink(path_join(r21_get_attachment_path_by('meta', $attachment_meta), $attachment_meta['sizes'][$size_name]['file']));

    // Delete metadata
    unset($attachment_meta['sizes'][$size_name]);
  }

  return $attachment_meta;
}
add_filter('wp_generate_attachment_metadata', 'r21_remove_old_image_sizes', 10, 1);


/**
 * Removes the the custom image regneration handle image, if existing.
 *
 * @return array Returns the metadata, without the handle image entry.
 */
function r21_remove_regeneration_hook_image($attachment_meta) {

  $name="cstm-img-regeneration-handle";

  // Check if image exists
  if (array_key_exists($name, $attachment_meta['sizes'])) {
    // Delete Image File
    @ unlink(path_join(r21_get_attachment_path_by('meta', $attachment_meta), $attachment_meta['sizes'][$name]['file']));

    // Delete Image Metadata
    unset($attachment_meta['sizes'][$name]);
  }

  return $attachment_meta;
}
add_filter('wp_generate_attachment_metadata', 'r21_remove_regeneration_hook_image', 10, 1);


/**
 * Generates custom image sizes, depending on the image orientation. Use the wp_generate_attachment_metadata hook!
 */
function r21_create_custom_image_sizes($meta) {

  // Initialize variables
  global $r21_image_sizes;
  $image_sizes="";

  // Generate the full file path for the image
  $image['path'] = path_join(wp_upload_dir()['basedir'], $meta['file']);

  // Get the dimensions of the original image
  list($image['width'], $image['height'], $image['type']) = getimagesize($image['path']);

  // Check the image orientation
  if ($image['width'] > $image['height']) {
    // Landscape
    $image_sizes = r21_filter_custom_image_sizes($r21_image_sizes, 'landscape', true);

  } else if ($image['width'] < $image['height']) {
    // Portrait
    $image_sizes = r21_filter_custom_image_sizes($r21_image_sizes, 'portrait', true);

  } else {
    // Square
    $image_sizes = r21_filter_custom_image_sizes($r21_image_sizes, 'square', true);
  }

  // Iterate through the sizes to be generated
  foreach ($image_sizes as $size_name => $size) {
    // TODO: Check if an image in the requested dimensions allready exists.

    // Create an instance of WP_Image_Editor for the original image
    $new_image = wp_get_image_editor($image['path']);

    // Check if there is an error
    if (is_wp_error($new_image)) { continue; }

    // Resize the image
    $new_image->resize($size['width'], $size['height'], $size['crop']);

    // Save new image and store new meta data in variable
    $new_image_meta = $new_image->save();

    // Reflect back new metadata
    $meta['sizes'][$size_name]['file'] = $new_image_meta['file'];
    $meta['sizes'][$size_name]['width'] = $new_image_meta['width'];
    $meta['sizes'][$size_name]['height'] = $new_image_meta['height'];
    $meta['sizes'][$size_name]['mime-type'] = $new_image_meta['mime-type'];
  }

  return $meta;
}
add_filter('wp_generate_attachment_metadata', 'r21_create_custom_image_sizes', 10, 1);


/**
 * Deletes images, generated by r21_create_custom_image_sizes(). Use the delete_attachment hook!
 */
function r21_delete_custom_image_size_files($post_id) {
  $meta = wp_get_attachment_metadata($post_id);

  foreach ($meta['sizes'] as $size) {
    // TODO: Add support for wp_delete_file hook here
    @ unlink(path_join(r21_get_attachment_path_by('meta', $meta), $size['file']));
  }
}
add_action('delete_attachment', 'r21_delete_custom_image_size_files');

Leave a Comment