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.
I saw that your fixed code already in WordPress 5.7.2:
https://github.com/WordPress/WordPress/blob/master/wp-includes/class-wp-image-editor-imagick.php
but generate thumbnairs still not working:
Warning: chmod(): Google\Cloud\Storage\StreamWrapper::stream_metadata is not implemented! in /var/www/html/wp-includes/class-wp-image-editor-imagick.php on line 710
I have fixed by following code:
if ( !wp_is_stream( $filename ) ) {
// Set correct file permissions.
$stat = stat(dirname($filename));
$perms = $stat[‘mode’] & 0000666; // Same permissions as parent folder, strip off the executable bits.
chmod( $filename, $perms );
}