WordPress GCS plugin broken thumbnails

The GCS plugin for WordPress lets you use Google Cloud Storage for WordPress’s media and other uploads. This is required on stateless environments like App Engine, where there’s no persistent writable filesystem to store uploads.

However, image thumbnailing and rescaling is broken by default when using the plugin, so while you can upload an image, the thumbnails that usually get automatically generated will never appear in the GCS bucket. So if you add high-resolution images to a post, load times will be massively increased, which is a particularly bad experience for low-resolution mobile devices.

I raised a WordPress ticket and attached a patch that fixes the issue. The patch needs to be applied to the core WordPress installation (rather than being a plugin), so may not be an option for WordPress admins that are using multisite hosting. I think a plugin-based fix would be possible (one that replaced the default image editor with a fixed one), but would involve duplicating a bunch of code from core WordPress.

The breakage is due to WordPress’s “image editor” (used for the automated rescaling/thumbnailing) not working correctly with PHP’s custom stream wrappers. In turn, this is because the PHP / imagick PHP extension functions that work with filenames don’t work with URLs/streams.

The realpath function returns FALSE for URLs:

var_dump(realpath("file://foo/bar/baz"));

The Imagick::readImage method does not work for URLs either, because it only accepts filenames.

I thought I could just fopen the URL and then call Imagick::readImageFile instead:

$fp = fopen($url, 'r');
$imagick->readImageFile($fp);
fclose($fp);

However, for GCS URLs, it produces errors like:

insufficient image data in file `/tmp/magick-xxx' @ error/jpeg.c/ReadJPEGImage/1117

Imagick::writeImage and Imagick::writeImageFile have similar issues when saving images.

The fix was to special-case streams in the image editor code so that paths are no longer normalized with realpath, and to use Imagick::readImageBlob and Imagick::getImageBlob and PHP’s built-in file functions to perform stream-friendly I/O.

Finally, WP-CLI’s media regenerate command was invaluable for regenerating all the missing thumbnails offline.

Leave a Reply

Your email address will not be published.