Skip to content

Commit 4a757e0

Browse files
committed
feat: disable image subsize generation with cdn image processing
1 parent feb2755 commit 4a757e0

File tree

4 files changed

+136
-79
lines changed

4 files changed

+136
-79
lines changed

src/Attachment/GDImageEditor.php

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ class GDImageEditor extends \WP_Image_Editor_GD
2222
{
2323
use ServiceLocatorTrait;
2424

25+
/**
26+
* Flag whether to disable creating image subsizes or not.
27+
*
28+
* @var bool
29+
*/
30+
private $disableImageSubsizes;
31+
2532
/**
2633
* The attachment file manager.
2734
*
@@ -34,6 +41,7 @@ class GDImageEditor extends \WP_Image_Editor_GD
3441
*/
3542
public function __construct($file)
3643
{
44+
$this->disableImageSubsizes = (bool) self::getService('ymir_cdn_image_processing_enabled');
3745
$this->fileManager = self::getService('file_manager');
3846

3947
if (!$this->fileManager instanceof AttachmentFileManager) {
@@ -50,9 +58,22 @@ public function __construct($file)
5058
/**
5159
* {@inheritdoc}
5260
*/
53-
public function save($destfilename = null, $mime_type = null)
61+
public function make_subsize($size)
62+
{
63+
return !$this->disableImageSubsizes || !is_array($size) || (!isset($size['height']) && !isset($size['width'])) ? parent::make_subsize($size) : [
64+
'file' => wp_basename($this->file),
65+
'width' => $size['width'],
66+
'height' => $size['height'],
67+
'mime-type' => $this->mime_type,
68+
];
69+
}
70+
71+
/**
72+
* {@inheritdoc}
73+
*/
74+
public function save($destFilename = null, $mimeType = null)
5475
{
55-
$savedImage = parent::save($destfilename, $mime_type);
76+
$savedImage = parent::save($destFilename, $mimeType);
5677

5778
// The "save" method changes the "file" property which is an issue with "multi_resize"
5879
// since we call the "save" method multiple times. So after the first save, the "file"
@@ -67,9 +88,9 @@ public function save($destfilename = null, $mime_type = null)
6788
/**
6889
* {@inheritdoc}
6990
*/
70-
protected function _save($image, $filename = null, $mime_type = null)
91+
protected function _save($image, $filename = null, $mimeType = null)
7192
{
72-
$savedImage = parent::_save($image, $filename, $mime_type);
93+
$savedImage = parent::_save($image, $filename, $mimeType);
7394

7495
if ($savedImage instanceof \WP_Error || empty($savedImage['path']) || !$this->fileManager->isInTempDirectory($savedImage['path'])) {
7596
return $savedImage;

src/Attachment/ImagickImageEditor.php

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ class ImagickImageEditor extends \WP_Image_Editor_Imagick
2222
{
2323
use ServiceLocatorTrait;
2424

25+
/**
26+
* Flag whether to disable creating image subsizes or not.
27+
*
28+
* @var bool
29+
*/
30+
private $disableImageSubsizes;
31+
2532
/**
2633
* The attachment file manager.
2734
*
@@ -34,6 +41,7 @@ class ImagickImageEditor extends \WP_Image_Editor_Imagick
3441
*/
3542
public function __construct($file)
3643
{
44+
$this->disableImageSubsizes = (bool) self::getService('ymir_cdn_image_processing_enabled');
3745
$this->fileManager = self::getService('file_manager');
3846

3947
if (!$this->fileManager instanceof AttachmentFileManager) {
@@ -50,9 +58,22 @@ public function __construct($file)
5058
/**
5159
* {@inheritdoc}
5260
*/
53-
public function save($destfilename = null, $mime_type = null)
61+
public function make_subsize($size)
62+
{
63+
return !$this->disableImageSubsizes || !is_array($size) || (!isset($size['height']) && !isset($size['width'])) ? parent::make_subsize($size) : [
64+
'file' => wp_basename($this->file),
65+
'width' => $size['width'],
66+
'height' => $size['height'],
67+
'mime-type' => $this->mime_type,
68+
];
69+
}
70+
71+
/**
72+
* {@inheritdoc}
73+
*/
74+
public function save($destFilename = null, $mimeType = null)
5475
{
55-
$savedImage = parent::save($destfilename, $mime_type);
76+
$savedImage = parent::save($destFilename, $mimeType);
5677

5778
// The "save" method changes the "file" property which is an issue with "multi_resize"
5879
// since we call the "save" method multiple times. So after the first save, the "file"
@@ -67,14 +88,14 @@ public function save($destfilename = null, $mime_type = null)
6788
/**
6889
* {@inheritdoc}
6990
*/
70-
protected function _save($image, $filename = null, $mime_type = null)
91+
protected function _save($image, $filename = null, $mimeType = null)
7192
{
7293
// Imagick by default can't handle ymir-public:// paths so have it save the file locally.
7394
if (is_string($filename) && $this->fileManager->isInUploadsDirectory($filename)) {
7495
$filename = $this->fileManager->getTempFilePath($filename);
7596
}
7697

77-
$savedImage = parent::_save($image, $filename, $mime_type);
98+
$savedImage = parent::_save($image, $filename, $mimeType);
7899

79100
if ($savedImage instanceof \WP_Error || empty($savedImage['path']) || !$this->fileManager->isInTempDirectory($savedImage['path'])) {
80101
return $savedImage;

src/Subscriber/ContentDeliveryNetworkImageProcessingSubscriber.php

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -82,22 +82,40 @@ public function __construct(array $baseImageSizes, bool $isMultisite, string $up
8282
public static function getSubscribedEvents(): array
8383
{
8484
return [
85-
'image_downsize' => ['generateScaledDownImage', 10, 3],
86-
'the_content' => ['rewriteContentImageUrls', 999999],
85+
'big_image_size_threshold' => 'disableScalingDownImages',
8786
'get_post_galleries' => ['rewriteGalleryImageUrls', 999999],
87+
'image_downsize' => ['generateScaledDownImage', 10, 3],
8888
'rest_after_insert_attachment' => ['maybeDisableImageDownsizeFilterForInsertAttachmentRestRequest', 10, 2],
8989
'rest_request_after_callbacks' => 'reEnableImageDownsizeFilter',
9090
'rest_request_before_callbacks' => ['maybeDisableImageDownsizeFilterForRestRequest', 10, 3],
91+
'the_content' => ['rewriteContentImageUrls', 999999],
9192
'wp_calculate_image_srcset' => ['rewriteImageSrcset', 10, 5],
93+
'wp_img_tag_add_width_and_height_attr' => ['disableAddingImageWidthAndHeightAttributes', 10, 2],
9294
];
9395
}
9496

97+
/**
98+
* Prevent WordPress from adding width and height attributes to images that the content delivery network will process.
99+
*/
100+
public function disableAddingImageWidthAndHeightAttributes($value, string $image): bool
101+
{
102+
return preg_match('#src=["|\']([^\s]+?)["|\']#i', $image, $matches) ? !$this->isProcessableImageUrl($matches[1]) : (bool) $value;
103+
}
104+
105+
/**
106+
* Prevent WordPress from creating scaled down versions of images.
107+
*/
108+
public function disableScalingDownImages(): bool
109+
{
110+
return false;
111+
}
112+
95113
/**
96114
* Generate the scaled down image array for the given size.
97115
*/
98116
public function generateScaledDownImage($image, $attachmentId, $size)
99117
{
100-
if (!$this->imageDownsizeFilterEnabled || is_admin() || !$this->isValidImageSize($size)) {
118+
if (!$this->imageDownsizeFilterEnabled || !$this->isValidImageSize($size)) {
101119
return $image;
102120
}
103121

@@ -368,20 +386,27 @@ private function getImageAttachmentSizeMetadata(int $attachmentId, $size): ?arra
368386
*/
369387
private function getImageSize(array $image): array
370388
{
371-
$height = null;
372-
$width = null;
389+
/*
390+
* Priority list for determining image size.
391+
*
392+
* 1. Parse width and height from the image source query string.
393+
* 2. Parse width and height from the image tag attributes.
394+
* 3. Parse width and height from the WordPress generated file name.
395+
* 4. Determine width and height from the WordPress image metadata.
396+
*/
397+
list($width, $height, $cropped) = $this->parseImageDimensionsFromImageSourceQueryString($image['image_src']);
373398

374-
// Start by trying to parse the dimension from the <img> tag.
375-
if (isset($image['image_tag'])) {
376-
list($width, $height) = $this->parseImageDimensionsFromImgTagAttributes($image['image_tag']);
399+
if (!$height && !$width) {
400+
list($width, $height, $cropped) = $this->parseImageDimensionsFromImageTagAttributes($image['image_tag']);
377401
}
378-
379-
// Next try to get the image dimensions using the filename.
380-
if (isset($image['image_src']) && !$height && !$width) {
381-
list($width, $height) = $this->parseImageDimensionsFromFilename($image['image_src']);
402+
if (!$height && !$width) {
403+
list($width, $height, $cropped) = $this->parseImageDimensionsFromFilename($image['image_src']);
404+
}
405+
if (!$height && !$width) {
406+
list($width, $height, $cropped) = $this->determineImageSizeUsingWordPressImageSizes($image);
382407
}
383408

384-
return ($height || $width) ? [$width, $height, $height && $width] : $this->determineImageSizeUsingWordPressImageSizes($image);
409+
return [$width, $height, $cropped];
385410
}
386411

387412
/**
@@ -449,35 +474,57 @@ private function isValidImageSize($size): bool
449474
*/
450475
private function parseImageDimensionsFromFilename(string $filename): array
451476
{
477+
$cropped = false;
452478
$height = null;
453479
$matches = [];
454480
$width = null;
455481

456482
if (preg_match(sprintf('#-(\d+)x(\d+)\.(?:%s)$#i', implode('|', self::SUPPORTED_EXTENSIONS)), $filename, $matches)) {
483+
$cropped = true;
457484
$height = (int) $matches[2];
458485
$width = (int) $matches[1];
459486
}
460487

461-
return [$width, $height];
488+
return [$width, $height, $cropped];
489+
}
490+
491+
/**
492+
* Parse the dimension of an image using the query strings in the image source.
493+
*/
494+
private function parseImageDimensionsFromImageSourceQueryString(string $imageSource): array
495+
{
496+
$cropped = (bool) preg_match('#\?.*cropped#i', $imageSource);
497+
$height = null;
498+
$matches = [];
499+
$width = null;
500+
501+
if (preg_match('#\?.*height=(\d+)#i', $imageSource, $matches)) {
502+
$height = (int) $matches[1];
503+
}
504+
if (preg_match('#\?.*width=(\d+)#i', $imageSource, $matches)) {
505+
$width = (int) $matches[1];
506+
}
507+
508+
return [$width, $height, $cropped];
462509
}
463510

464511
/**
465512
* Parse the dimension of an image using the <img> tag attributes.
466513
*/
467-
private function parseImageDimensionsFromImgTagAttributes(string $tag): array
514+
private function parseImageDimensionsFromImageTagAttributes(string $tag): array
468515
{
469516
$height = null;
470517
$matches = [];
471518
$width = null;
472519

473-
if (preg_match('#\sheight=["|\']?([\d]+)["|\']?#i', $tag, $matches)) {
520+
if (preg_match('#\sheight=["|\']?(\d+)["|\']?#i', $tag, $matches)) {
474521
$height = (int) $matches[1];
475522
}
476-
if (preg_match('#\swidth=["|\']?([\d]+)["|\']?#i', $tag, $matches)) {
523+
if (preg_match('#\swidth=["|\']?(\d+)["|\']?#i', $tag, $matches)) {
477524
$width = (int) $matches[1];
478525
}
479526

480-
return [$width, $height];
527+
return [$width, $height, $width && $height];
481528
}
482529

483530
/**

0 commit comments

Comments
 (0)