Skip to content

Instantly share code, notes, and snippets.

@janfabry
Created November 13, 2010 16:05
Show Gist options
  • Save janfabry/675439 to your computer and use it in GitHub Desktop.
Save janfabry/675439 to your computer and use it in GitHub Desktop.
WordPress Virtual intermediate images plugin (first public attempt)
<?php
/*
Plugin Name: Virtual intermediate images
Plugin URI: http://www.monkeyman.be
Description: Prevent creation of actual intermediate image sizes
Version: 0.1
Author: Jan Fabry
This plugin prevents the creation of actual intermediate image sizes. It does, however, fill in all metadata attributes as if the intermediate sizes exist. It is designed to work together with a plugin that can create these images on the fly, like monkeyman-on-demand-resizer.
The intermediate images are created by image_make_intermediate_size(). Because this function has no hook to prevent it from actually creating the file, we need to go one step back.
This function is called in two places (by core WordPress files): wp_generate_attachment_metadata() for the normal flow of uploading a new image, and by the image editor.
wp_generate_attachment_metadata() is intercepted by hooking into the `intermediate_image_sizes_advanced`. We save the passed sizes for later and return an empty array, preventing any actual intermediate sizes from being created. The output of this function is then filtered through `wp_generate_attachment_metadata`, so we use that to add the sizes back to the metadata as if nothing happened.
The URLs are constructed almost like normal size URLs, with one exception: crop information is added, by prepending a 'c'. We calculate the intermediate image sizes by using the same functions WordPress uses, but this requires we first read the original image size. Because we only get the final part of the upload path, we hook into the (seemingly unrelated) `_wp_relative_upload_path` filter to map the trimmed to the full paths.
The image editor is trickier because it modifies the images and the metadata on its own. I'm still finding out with hooks to use there. We already hook into `load_image_to_edit_path` to make sure it returns a existing and not a virtual file path. But probably the whole editor needs to be re-written for this to work.
If you think the variables have weird names ($idPost instead of $post_id), it's because I am trying to use "Apps Hungrarian" notation [ http://www.joelonsoftware.com/articles/Wrong.html ] to indicate the type of the value stored there. But I'm not consistent enough (and it clashes with WordPress coding standard), and maybe should rethink it.
*/
class Monkeyman_VirtualIntermediateImages
{
protected $trimmedPaths = array();
protected $intermediateSizes = null;
public function __construct()
{
// Save full paths for later
add_filter('_wp_relative_upload_path', array(&$this, 'storeTrimmedPath'), 10, 2);
// Save intermediate sizes for later (and return none)
add_filter('intermediate_image_sizes_advanced', array(&$this, 'storeIntermediateSizes'), 900);
// Generate "fake" metadata
add_filter('wp_generate_attachment_metadata', array(&$this, 'generateAttachmentMetadata'), 10, 2);
// Get an image for the editor
add_filter('load_image_to_edit_path', array(&$this, 'getEditorImage'), 10, 3);
}
public function storeTrimmedPath($trimmedPath, $origPath)
{
$this->trimmedPaths[$trimmedPath] = $origPath;
return $trimmedPath;
}
public function storeIntermediateSizes($intermediateSizes)
{
$this->intermediateSizes = $intermediateSizes;
return array();
}
public function generateAttachmentMetadata($metadata, $idAttachment)
{
$rootedImagePath = $this->trimmedPaths[$metadata['file']];
$fullImageSize = @getimagesize($rootedImagePath);
if (!$fullImageSize) {
return new WP_Error('invalid_image', __('Could not read image size'), $rootedImagePath);
}
$imagePathInfo = pathinfo($metadata['file']);
$metadata['sizes'] = array();
foreach ($this->intermediateSizes as $sizeName => $sizeInfo) {
$dims = image_resize_dimensions($fullImageSize[0], $fullImageSize[1], $sizeInfo['width'], $sizeInfo['height'], $sizeInfo['crop']);
if (!$dims) {
// The source image is probably smaller than the destination size, just skip it
continue;
}
list($dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) = $dims;
$suffix = '-';
if ($sizeInfo['crop']) {
$suffix .= 'c';
}
$suffix .= $dst_w . 'x' . $dst_h;
$metadata['sizes'][$sizeName] = array(
'file' => $imagePathInfo['filename'] . $suffix . '.' . $imagePathInfo['extension'],
'width' => $dst_w,
'height' => $dst_h,
);
}
return $metadata;
}
public function getEditorImage($filepath, $idPost, $size)
{
if (file_exists($filepath)) {
return $filepath;
}
$finalImagePath = get_post_meta($idPost, '_wp_attached_file', true);
$uploadInfo = wp_upload_dir();
// TODO: All kinds of backwards-compatible stuff
// See wp_get_attachment_url()
$filepath = $uploadInfo['basedir'] . '/' . $finalImagePath;
return $filepath;
}
}
$monkeyman_VirtualIntermediateImages_instance = new Monkeyman_VirtualIntermediateImages();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment