ShortPixel Image Optimizer - Version 5.1.4

Version Description

Release date November 28, 2022 * New: added a filter to force a file check for WebP/AVIF if they were manually deleted from disk; * Fix: if only small WebPs are available, include the JPG version in the picture tag to avoid blurry images; * Fix: the notification about unlisted thumbnails incorrectly reported WebP and AVIF files; * Fix: improved integration with WP Offload Media by including Retina images in virtual/offload file checks; * Fix: if the main file was optimized but some thumbnails did not have WebP/AVIF, it was not displayed correctly in the UI; * Fix: added a % margin when generating WebPs/AVIF, so that files that are only a few bytes larger are also generated; * Fix: when running WP-CLI, the percentage of finished items in the total was calculated incorrectly; * Fix: the settings page crashed in certain cases for new accounts; * Tweak: various CSS fixes and improvements on the Media Library, especially for cases with many thumbnails; * Language: 2 new strings added, 2 updated, 0 fuzzed, and 0 deprecated.

Download this release

Release Info

Developer petredobrescu
Plugin Icon 128x128 ShortPixel Image Optimizer
Version 5.1.4
Comparing to
See all releases

Code changes from version 5.1.3 to 5.1.4

build/shortpixel/replacer/src/Replacer.php CHANGED
@@ -38,11 +38,21 @@ class Replacer
38
  $this->source_url = $url;
39
  }
40
 
 
 
 
 
 
41
  public function setTarget($url)
42
  {
43
  $this->target_url = $url;
44
  }
45
 
 
 
 
 
 
46
  public function setSourceMeta($meta)
47
  {
48
  $this->source_metadata = $meta;
38
  $this->source_url = $url;
39
  }
40
 
41
+ public function getSource()
42
+ {
43
+ return $this->source_url;
44
+ }
45
+
46
  public function setTarget($url)
47
  {
48
  $this->target_url = $url;
49
  }
50
 
51
+ public function getTarget()
52
+ {
53
+ return $this->target_url;
54
+ }
55
+
56
  public function setSourceMeta($meta)
57
  {
58
  $this->source_metadata = $meta;
class/Controller/ApiController.php CHANGED
@@ -585,7 +585,7 @@ class ApiController
585
  $webpName = $originalFile->getFileBase() . '.webp';
586
  $webpDownloadResult = false;
587
 
588
- if ($fileData->$webpTypeSize > $checkFileSize) // if file is bigger.
589
  {
590
  $results[$imageName]['webp'] = $this->returnOk(self::STATUS_OPTIMIZED_BIGGER, __('Special file type bigger than core file','shortpixel-image-optimiser'));
591
  }
@@ -608,7 +608,7 @@ class ApiController
608
  {
609
  $avifName = $originalFile->getFileBase() . '.avif';
610
 
611
- if ($fileData->$avifTypeSize > $checkFileSize) // if file is bigger.
612
  {
613
  $results[$imageName]['avif'] = $this->returnOk(self::STATUS_OPTIMIZED_BIGGER, __('Special file type bigger than core file','shortpixel-image-optimiser'));
614
  }
@@ -879,6 +879,26 @@ class ApiController
879
  return $result;
880
  }
881
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
882
 
883
 
884
  } // class
585
  $webpName = $originalFile->getFileBase() . '.webp';
586
  $webpDownloadResult = false;
587
 
588
+ if (false === $this->checkFileSizeMargin($checkFileSize, $fileData->$webpTypeSize)) // if file is bigger.
589
  {
590
  $results[$imageName]['webp'] = $this->returnOk(self::STATUS_OPTIMIZED_BIGGER, __('Special file type bigger than core file','shortpixel-image-optimiser'));
591
  }
608
  {
609
  $avifName = $originalFile->getFileBase() . '.avif';
610
 
611
+ if ($this->checkFileSizeMargin($checkFileSize, $fileData->$avifTypeSize)) // if file is bigger.
612
  {
613
  $results[$imageName]['avif'] = $this->returnOk(self::STATUS_OPTIMIZED_BIGGER, __('Special file type bigger than core file','shortpixel-image-optimiser'));
614
  }
879
  return $result;
880
  }
881
 
882
+ private function checkFileSizeMargin($fileSize, $resultSize)
883
+ {
884
+ // This is ok.
885
+ if ($fileSize >= $resultSize)
886
+ return true;
887
+
888
+ $percentage = apply_filters('shortpixel/api/filesizeMargin', 5);
889
+
890
+ $increase = (($resultSize - $fileSize) / $fileSize) * 100;
891
+
892
+ if ($increase <= $percentage)
893
+ return true;
894
+
895
+ return false;
896
+
897
+
898
+
899
+
900
+ }
901
+
902
 
903
 
904
  } // class
class/Controller/FileSystemController.php CHANGED
@@ -59,6 +59,7 @@ Class FileSystemController extends \ShortPixel\Controller
59
  {
60
  self::$mediaItems[$id] = $imageObj;
61
  }
 
62
  return $imageObj;
63
  }
64
 
59
  {
60
  self::$mediaItems[$id] = $imageObj;
61
  }
62
+
63
  return $imageObj;
64
  }
65
 
class/Controller/OptimizeController.php CHANGED
@@ -985,8 +985,13 @@ class OptimizeController
985
  $perc = $object->stats->$key;
986
  }
987
  else
988
- $perc = round(($object->stats->$key + $value) / 2); //exceptionnes.
989
-
 
 
 
 
 
990
  $object->stats->$key = $perc;
991
  }
992
  elseif (is_numeric($object->stats->$key)) // add only if number.
985
  $perc = $object->stats->$key;
986
  }
987
  else
988
+ {
989
+ $total = $results->custom->stats->total + $results->media->stats->total;
990
+ $done = $results->custom->stats->done + $results->media->stats->done;
991
+ $fatal = $results->custom->stats->fatal_errors + $results->media->stats->fatal_errors;
992
+ $perc = round((100 / $total) * ($done + $fatal), 0, PHP_ROUND_HALF_DOWN);
993
+ // $perc = round(($object->stats->$key + $value) / 2); //exceptionnes.
994
+ }
995
  $object->stats->$key = $perc;
996
  }
997
  elseif (is_numeric($object->stats->$key)) // add only if number.
class/Controller/Queue/Queue.php CHANGED
@@ -352,7 +352,7 @@ abstract class Queue
352
  $stats->total = $stats->in_queue + $stats->fatal_errors + $stats->errors + $stats->done + $stats->in_process;
353
  if ($stats->total > 0)
354
  {
355
- $stats->percentage_done = round(round((100 / $stats->total) * ($stats->done + $stats->fatal_errors)), 0, PHP_ROUND_HALF_DOWN);
356
  }
357
  else
358
  $stats->percentage_done = 100; // no items means all done.
352
  $stats->total = $stats->in_queue + $stats->fatal_errors + $stats->errors + $stats->done + $stats->in_process;
353
  if ($stats->total > 0)
354
  {
355
+ $stats->percentage_done = round((100 / $stats->total) * ($stats->done + $stats->fatal_errors), 0, PHP_ROUND_HALF_DOWN);
356
  }
357
  else
358
  $stats->percentage_done = 100; // no items means all done.
class/Controller/StatsController.php CHANGED
@@ -68,9 +68,14 @@ class StatsController extends \ShortPixel\Controller
68
  $totalOptimized = $this->model->get('totalOptimized');
69
  $totalOriginal = $this->model->get('totalOriginal');
70
 
71
- return $totalOptimized > 0
72
- ? round(( 1 - ( $totalOptimized / $totalOriginal ) ) * 100, 2)
73
- : 0;
 
 
 
 
 
74
  }
75
 
76
  // This is not functional @todo
68
  $totalOptimized = $this->model->get('totalOptimized');
69
  $totalOriginal = $this->model->get('totalOriginal');
70
 
71
+ $average = 0;
72
+
73
+ if ($totalOptimized > 0 && $totalOriginal > 0)
74
+ {
75
+ $average = round(( 1 - ( $totalOptimized / $totalOriginal ) ) * 100, 2);
76
+ }
77
+
78
+ return $average;
79
  }
80
 
81
  // This is not functional @todo
class/Helper/UiHelper.php CHANGED
@@ -96,14 +96,32 @@ class UiHelper
96
 
97
  if (isset($improvements['thumbnails']))
98
  {
 
99
  $output .= '<div class="thumbnails optimized">';
100
  if ($thumbsTotal > $thumbsDone)
101
  $output .= '<div class="totals">' . sprintf(__('+%s of %s thumbnails optimized','shortpixel-image-optimiser'), self::formatNumber($thumbsDone,0), self::formatNumber($thumbsTotal,0)) . '</div>';
102
  elseif ($thumbsDone > 0)
103
  $output .= '<div class="totals">' . sprintf(__('+%s thumbnails optimized','shortpixel-image-optimiser'), self::formatNumber($thumbsDone, 0)) . '</div>';
104
 
105
-
106
  $improvs = array();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  // Quality Check
108
  foreach($improvements['thumbnails'] as $thumbName => $thumbStat)
109
  {
@@ -135,6 +153,10 @@ class UiHelper
135
  </div>";
136
 
137
  }
 
 
 
 
138
  $output .= "</div> <!-- /thumb-wrapper -->";
139
  }
140
  $output .= "</div> <!-- /thumb optimized -->";
@@ -152,21 +174,44 @@ class UiHelper
152
  {
153
  $output .= '<div class="filetype avif">' . sprintf(__('+%s Avif images ','shortpixel-image-optimiser') , $avifsTotal) . '</div>';
154
  }
 
155
  if ($imageObj->isOptimized() && $imageObj->isProcessable())
156
  {
157
  list($urls, $optimizable) = $imageObj->getCountOptimizeData('thumbnails');
158
  list($webpUrls, $webpCount) = $imageObj->getCountOptimizeData('webp');
159
  list($avifUrls, $avifCount) = $imageObj->getCountOptimizeData('avif');
 
 
 
160
  // Todo check if Webp / Acif is active, check for unoptimized items
161
  // $processWebp = ($imageObj->isProcessableFileType('webp')) ? true : false;
162
  // $processAvif = ($imageObj->isProcessableFileType('avif')) ? true : false;
163
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  if ($optimizable > 0)
165
  {
166
- $output .= '<div class="thumbs-todo"><h4>' . sprintf(__('%d to optimize', 'shortpixel-image-optimiser'), $optimizable) . '</h4>';
167
  $output .= "<span>";
168
  foreach($urls as $optObj)
169
  {
 
 
 
170
  $output .= substr($optObj, strrpos($optObj, '/')+1) . '<br>';
171
  }
172
  $output .= "</span>";
@@ -180,7 +225,10 @@ class UiHelper
180
  $output .= "<span>";
181
  foreach($webpUrls as $optObj)
182
  {
183
- $output .= self::convertImageTypeName(substr($optObj, strrpos($optObj, '/')+1), 'webp') . '<br>';
 
 
 
184
  }
185
  $output .= "</span>";
186
  $output .= '</div>';
96
 
97
  if (isset($improvements['thumbnails']))
98
  {
99
+
100
  $output .= '<div class="thumbnails optimized">';
101
  if ($thumbsTotal > $thumbsDone)
102
  $output .= '<div class="totals">' . sprintf(__('+%s of %s thumbnails optimized','shortpixel-image-optimiser'), self::formatNumber($thumbsDone,0), self::formatNumber($thumbsTotal,0)) . '</div>';
103
  elseif ($thumbsDone > 0)
104
  $output .= '<div class="totals">' . sprintf(__('+%s thumbnails optimized','shortpixel-image-optimiser'), self::formatNumber($thumbsDone, 0)) . '</div>';
105
 
 
106
  $improvs = array();
107
+
108
+ uasort($improvements['thumbnails'], function ($a, $b) {
109
+ //return $b[0] <=> $a[0]; // @todo Efficient code to use once PHP 5 support is done.
110
+ if ($a == $b) {
111
+ return 0;
112
+ }
113
+ return ($b < $a) ? -1 : 1;
114
+ });
115
+
116
+ $cutoff = false;
117
+ $thumbCount = count($improvements['thumbnails']);
118
+ if ($thumbCount > 20)
119
+ {
120
+ $improvements['thumbnails'] = array_slice($improvements['thumbnails'], 0, 15, true);
121
+ $cutoff = true;
122
+ }
123
+
124
+
125
  // Quality Check
126
  foreach($improvements['thumbnails'] as $thumbName => $thumbStat)
127
  {
153
  </div>";
154
 
155
  }
156
+ if (true === $cutoff)
157
+ {
158
+ $output .= '<div class="thumb"><span class="cutoff">' . sprintf(__('+ %d more', 'shortpixel-image-optimiser'), ($thumbCount - 15)) . '</span></div>';
159
+ }
160
  $output .= "</div> <!-- /thumb-wrapper -->";
161
  }
162
  $output .= "</div> <!-- /thumb optimized -->";
174
  {
175
  $output .= '<div class="filetype avif">' . sprintf(__('+%s Avif images ','shortpixel-image-optimiser') , $avifsTotal) . '</div>';
176
  }
177
+
178
  if ($imageObj->isOptimized() && $imageObj->isProcessable())
179
  {
180
  list($urls, $optimizable) = $imageObj->getCountOptimizeData('thumbnails');
181
  list($webpUrls, $webpCount) = $imageObj->getCountOptimizeData('webp');
182
  list($avifUrls, $avifCount) = $imageObj->getCountOptimizeData('avif');
183
+
184
+
185
+ $maxList = 10;
186
  // Todo check if Webp / Acif is active, check for unoptimized items
187
  // $processWebp = ($imageObj->isProcessableFileType('webp')) ? true : false;
188
  // $processAvif = ($imageObj->isProcessableFileType('avif')) ? true : false;
189
 
190
+ if (count($urls) > $maxList)
191
+ {
192
+ $urls = array_slice($urls, 0, $maxList, true);
193
+ $urls[] = '...';
194
+ }
195
+ if (count($webpUrls) > $maxList)
196
+ {
197
+ $webpUrls = array_slice($webpUrls, 0, $maxList, true);
198
+ $webpUrls[] = '...';
199
+ }
200
+ if (count($avifUrls) > $maxList)
201
+ {
202
+ $avifUrls = array_slice($avifUrls, 0, $maxList, true);
203
+ $avifUrls[] = '...';
204
+ }
205
+
206
  if ($optimizable > 0)
207
  {
208
+ $output .= '<div class="thumbs-todo"><h4>' . sprintf(__('%d images to optimize', 'shortpixel-image-optimiser'), $optimizable) . '</h4>';
209
  $output .= "<span>";
210
  foreach($urls as $optObj)
211
  {
212
+ if ($optObj === '...')
213
+ $output .= $optObj;
214
+ else
215
  $output .= substr($optObj, strrpos($optObj, '/')+1) . '<br>';
216
  }
217
  $output .= "</span>";
225
  $output .= "<span>";
226
  foreach($webpUrls as $optObj)
227
  {
228
+ if ($optObj === '...')
229
+ $output .= $optObj;
230
+ else
231
+ $output .= self::convertImageTypeName(substr($optObj, strrpos($optObj, '/')+1), 'webp') . '<br>';
232
  }
233
  $output .= "</span>";
234
  $output .= '</div>';
class/Model/AdminNotices/AvifNotice.php CHANGED
@@ -25,7 +25,6 @@ class AvifNotice extends \ShortPixel\Model\AdminNoticeModel
25
  if (apply_filters('shortpixel/avifcheck/override', false) === true)
26
  { return; }
27
 
28
- Log::addTemp('Checking Avif');
29
 
30
  if ($cache->getItem('avif_server_check')->exists() === false)
31
  {
@@ -33,7 +32,6 @@ class AvifNotice extends \ShortPixel\Model\AdminNoticeModel
33
  $headers = get_headers($url);
34
  $is_error = true;
35
 
36
- Log::addTemp('Avif check headers', $headers);
37
  $this->addData('headers', $headers);
38
  // Defaults.
39
  $this->error_message = __('AVIF server test failed. Your server may not be configured to display AVIF files correctly. Serving AVIF might cause your images not to load. Check your images, disable the AVIF option, or update your web server configuration.', 'shortpixel-image-optimiser');
@@ -56,8 +54,6 @@ Log::addTemp('Avif check headers', $headers);
56
  }
57
  }
58
 
59
- Log::addTemp('ContentType', $contentType);
60
-
61
  // http not ok, redirect etc. Shouldn't happen.
62
  if (is_null($response) || strpos($response, '200') === false)
63
  {
25
  if (apply_filters('shortpixel/avifcheck/override', false) === true)
26
  { return; }
27
 
 
28
 
29
  if ($cache->getItem('avif_server_check')->exists() === false)
30
  {
32
  $headers = get_headers($url);
33
  $is_error = true;
34
 
 
35
  $this->addData('headers', $headers);
36
  // Defaults.
37
  $this->error_message = __('AVIF server test failed. Your server may not be configured to display AVIF files correctly. Serving AVIF might cause your images not to load. Check your images, disable the AVIF option, or update your web server configuration.', 'shortpixel-image-optimiser');
54
  }
55
  }
56
 
 
 
57
  // http not ok, redirect etc. Shouldn't happen.
58
  if (is_null($response) || strpos($response, '200') === false)
59
  {
class/Model/Image/ImageModel.php CHANGED
@@ -149,16 +149,16 @@ abstract class ImageModel extends \ShortPixel\Model\File\FileModel
149
  return false;
150
  }
151
 
152
- // Pdf, no special files.
153
- if ($this->getExtension() == 'pdf')
154
- return false;
155
-
156
- if ($type == 'webp' && ! $settings->createWebp)
157
  return false;
158
 
159
  if ($type == 'avif' && ! $settings->createAvif)
160
  return false;
161
 
 
 
 
 
162
  $imgObj = $this->getImageType($type);
163
 
164
  // if this image doesn't have webp / avif, it can be processed.
@@ -341,39 +341,22 @@ abstract class ImageModel extends \ShortPixel\Model\File\FileModel
341
  $count = 0;
342
  $urls = array();
343
  $i = 0;
344
- foreach($optimizeData['params'] as $sizeName => $data)
345
- {
346
 
347
- switch($param)
348
- {
349
- case 'thumbnails';
350
- if (isset($data['image']) && $data['image'] === true)
351
- {
352
- $count++;
353
- $urls[] = $optimizeData['paths'][$sizeName];
354
- }
355
- break;
356
- case 'webp';
357
- if (isset($data['webp']) && $data['webp'] === true)
358
- {
359
- $count++;
360
- $urls[] = $optimizeData['paths'][$sizeName];
361
- }
362
- break;
363
- case 'avif';
364
- if (isset($data['avif']) && $data['avif'] === true)
365
- {
366
- $count++;
367
- $urls[] = $optimizeData['paths'][$sizeName];
368
- }
369
- break;
370
 
371
- $i++;
372
- }
373
- }
374
 
 
 
375
 
 
 
 
 
 
376
  return array($urls, $count);
 
377
  }
378
 
379
  protected function getImageType($type = 'webp')
@@ -384,9 +367,15 @@ abstract class ImageModel extends \ShortPixel\Model\File\FileModel
384
 
385
  if (! is_null($this->getMeta($type)))
386
  {
 
 
387
  $filepath = $this->getFileDir() . $this->getMeta($type);
388
  $file = $fs->getFile($filepath);
389
- return $file;
 
 
 
 
390
  }
391
 
392
  if ($type == 'webp')
@@ -407,7 +396,7 @@ abstract class ImageModel extends \ShortPixel\Model\File\FileModel
407
  $file = $fs->getFile($filepath);
408
 
409
  // If double extension is enabled, but no file, check the alternative.
410
- if (! $file->exists() && ! $file->is_virtual())
411
  {
412
  if ($is_double)
413
  $file = $fs->getFile($filepath);
149
  return false;
150
  }
151
 
152
+ if ($type == 'webp' && ! $settings->createWebp)
 
 
 
 
153
  return false;
154
 
155
  if ($type == 'avif' && ! $settings->createAvif)
156
  return false;
157
 
158
+ // Pdf, no special files.
159
+ if ($this->getExtension() == 'pdf')
160
+ return false;
161
+
162
  $imgObj = $this->getImageType($type);
163
 
164
  // if this image doesn't have webp / avif, it can be processed.
341
  $count = 0;
342
  $urls = array();
343
  $i = 0;
 
 
344
 
345
+ $params = $optimizeData['params'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346
 
347
+ if ($param == 'thumbnails')
348
+ $param = 'image';
 
349
 
350
+ // Take the optimizeData and take key - param column, then check if the param (image/webp/avif) is true (filter) .
351
+ $combinedArray = array_filter(array_combine(array_keys($params), array_column($params, $param)));
352
 
353
+ $count = count($combinedArray);
354
+ foreach($combinedArray as $sizeName => $unneeded)
355
+ {
356
+ $urls[] = $optimizeData['paths'][$sizeName];
357
+ }
358
  return array($urls, $count);
359
+
360
  }
361
 
362
  protected function getImageType($type = 'webp')
367
 
368
  if (! is_null($this->getMeta($type)))
369
  {
370
+ // Filter to disable assumption(s) on the file basis of imageType. Active when something has manually been deleted.
371
+ $metaCheck = apply_filters('shortpixel/image/filecheck', false);
372
  $filepath = $this->getFileDir() . $this->getMeta($type);
373
  $file = $fs->getFile($filepath);
374
+
375
+ if ($metaCheck === false)
376
+ {
377
+ return $file;
378
+ }
379
  }
380
 
381
  if ($type == 'webp')
396
  $file = $fs->getFile($filepath);
397
 
398
  // If double extension is enabled, but no file, check the alternative.
399
+ if (! $file->is_virtual() && ! $file->exists())
400
  {
401
  if ($is_double)
402
  $file = $fs->getFile($filepath);
class/Model/Image/MediaLibraryModel.php CHANGED
@@ -316,7 +316,8 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
316
 
317
  if ($main)
318
  {
319
- $this->retinas[$this->mainImageKey] = $main; // on purpose not a string, but number to prevent any custom image sizes to get overwritten.
 
320
  }
321
  }
322
 
@@ -324,7 +325,10 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
324
  {
325
  $retscaled = $this->original_file->getRetina();
326
  if ($retscaled)
 
 
327
  $this->retinas[$this->originalImageKey] = $retscaled; //see main
 
328
  }
329
 
330
  foreach ($this->thumbnails as $thumbname => $thumbObj)
@@ -515,9 +519,6 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
515
  $resultObj = $files[$sizeName];
516
  $thumbnail = $thumbObjs[$sizeName];
517
 
518
- //Log::addTemp('Handle Optimize thumbnail', $thumbnail);
519
- //Log::add
520
-
521
  $thumbnail->handleOptimizedFileType($resultObj); // check for webps /etc
522
 
523
  if ($thumbnail->isOptimized())
@@ -1223,6 +1224,10 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
1223
 
1224
  if ($bool === true) // Is Processable just needs one job
1225
  return true;
 
 
 
 
1226
  }
1227
 
1228
  }
@@ -2058,7 +2063,7 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
2058
  $adminNotices->invokeLegacyNotice();
2059
  }
2060
 
2061
- Log::addDebug("Conversion of legacy: ", array($metadata));
2062
 
2063
  $type = isset($data['type']) ? $this->legacyConvertType($data['type']) : '';
2064
 
@@ -2463,7 +2468,6 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
2463
  // Setting must be active.
2464
  /*if (! \wpSPIO()->settings()->optimizeUnlisted )
2465
  return; */
2466
-
2467
  $searchUnlisted = \wpSPIO()->settings()->optimizeUnlisted;
2468
 
2469
  // Don't check this more than once per run-time.
@@ -2576,13 +2580,7 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
2576
  $thumbs = array_values(preg_grep($pattern, $all_files));
2577
  if (count($thumbs) > 0)
2578
  $unlisted = array_merge($unlisted, $thumbs);
2579
- // $thumbs = array_merge($thumbs, self::getFilesByPattern($dirPath, $pattern));
2580
 
2581
- /*foreach($thumbsCandidates as $th) {
2582
- if(preg_match($pattern, $th)) {
2583
- $thumbs[]= $th;
2584
- }
2585
- } */
2586
  }
2587
  }
2588
  }
@@ -2592,10 +2590,7 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
2592
  // Quality check on the thumbs. Must exist, must be same extension.
2593
  $added = false;
2594
 
2595
- if ($check_only === true)
2596
- {
2597
- return $unlisted;
2598
- }
2599
 
2600
  foreach($unlisted as $unName)
2601
  {
@@ -2610,12 +2605,19 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
2610
  }
2611
  elseif ($thumbObj->is_readable()) // exclude webps
2612
  {
2613
- $thumbObj->setName($unName);
2614
- $thumbObj->setMeta('originalWidth', $thumbObj->get('width'));
2615
- $thumbObj->setMeta('originalHeight', $thumbObj->get('height'));
2616
- $thumbObj->setMeta('file', $thumbObj->getFileName() );
2617
- $this->thumbnails[$unName] = $thumbObj;
2618
- $added = true;
 
 
 
 
 
 
 
2619
  }
2620
  else
2621
  {
@@ -2623,9 +2625,10 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
2623
  }
2624
  }
2625
 
2626
- //if ($added)
2627
- // $this->saveMeta(); // Save it when we are adding images.
2628
-
 
2629
  self::$unlistedChecked[] = $this->get('id');
2630
  }
2631
 
316
 
317
  if ($main)
318
  {
319
+ $main->setName($this->mainImageKey);
320
+ $this->retinas[$this->mainImageKey] = $main; // to prevent any custom image sizes to get overwritten.
321
  }
322
  }
323
 
325
  {
326
  $retscaled = $this->original_file->getRetina();
327
  if ($retscaled)
328
+ {
329
+ $retscaled->setName($this->originalImageKey);
330
  $this->retinas[$this->originalImageKey] = $retscaled; //see main
331
+ }
332
  }
333
 
334
  foreach ($this->thumbnails as $thumbname => $thumbObj)
519
  $resultObj = $files[$sizeName];
520
  $thumbnail = $thumbObjs[$sizeName];
521
 
 
 
 
522
  $thumbnail->handleOptimizedFileType($resultObj); // check for webps /etc
523
 
524
  if ($thumbnail->isOptimized())
1224
 
1225
  if ($bool === true) // Is Processable just needs one job
1226
  return true;
1227
+
1228
+ if ($thumbnail->isOptimized() && true === $thumbnail->isProcessableAnyFileType())
1229
+ return true;
1230
+
1231
  }
1232
 
1233
  }
2063
  $adminNotices->invokeLegacyNotice();
2064
  }
2065
 
2066
+ Log::addDebug("Conversion of legacy: " . $this->get('id'), array($metadata));
2067
 
2068
  $type = isset($data['type']) ? $this->legacyConvertType($data['type']) : '';
2069
 
2468
  // Setting must be active.
2469
  /*if (! \wpSPIO()->settings()->optimizeUnlisted )
2470
  return; */
 
2471
  $searchUnlisted = \wpSPIO()->settings()->optimizeUnlisted;
2472
 
2473
  // Don't check this more than once per run-time.
2580
  $thumbs = array_values(preg_grep($pattern, $all_files));
2581
  if (count($thumbs) > 0)
2582
  $unlisted = array_merge($unlisted, $thumbs);
 
2583
 
 
 
 
 
 
2584
  }
2585
  }
2586
  }
2590
  // Quality check on the thumbs. Must exist, must be same extension.
2591
  $added = false;
2592
 
2593
+ $foundUnlisted = array(); // found and ready. Used for notice / check only
 
 
 
2594
 
2595
  foreach($unlisted as $unName)
2596
  {
2605
  }
2606
  elseif ($thumbObj->is_readable()) // exclude webps
2607
  {
2608
+ if (true === $check_only)
2609
+ {
2610
+ $foundUnlisted[] = $unName;
2611
+ }
2612
+ else {
2613
+ $thumbObj->setName($unName);
2614
+ $thumbObj->setMeta('originalWidth', $thumbObj->get('width'));
2615
+ $thumbObj->setMeta('originalHeight', $thumbObj->get('height'));
2616
+ $thumbObj->setMeta('file', $thumbObj->getFileName() );
2617
+ $this->thumbnails[$unName] = $thumbObj;
2618
+ $added = true;
2619
+ }
2620
+
2621
  }
2622
  else
2623
  {
2625
  }
2626
  }
2627
 
2628
+ if (true === $check_only)
2629
+ {
2630
+ return $foundUnlisted;
2631
+ }
2632
  self::$unlistedChecked[] = $this->get('id');
2633
  }
2634
 
class/Model/Image/MediaLibraryThumbnailModel.php CHANGED
@@ -68,9 +68,21 @@ class MediaLibraryThumbnailModel extends \ShortPixel\Model\Image\ImageModel
68
 
69
  public function getRetina()
70
  {
71
- $filebase = $this->getFileBase();
72
- $filepath = (string) $this->getFileDir();
73
- $extension = $this->getExtension();
 
 
 
 
 
 
 
 
 
 
 
 
74
 
75
  $retina = new MediaLibraryThumbnailModel($filepath . $filebase . '@2x.' . $extension, $this->id, $this->size); // mind the dot in after 2x
76
  $retina->setName($this->size);
68
 
69
  public function getRetina()
70
  {
71
+ if ($this->is_virtual())
72
+ {
73
+ $fs = \wpSPIO()->filesystem();
74
+ $filepath = apply_filters('shortpixel/file/virtual/translate', $this->getFullPath(), $this);
75
+ $virtualFile = $fs->getFile($filepath);
76
+
77
+ $filebase = $virtualFile->getFileBase();
78
+ $filepath = (string) $virtualFile->getFileDir();
79
+ $extension = $virtualFile->getExtension();
80
+ }
81
+ else {
82
+ $filebase = $this->getFileBase();
83
+ $filepath = (string) $this->getFileDir();
84
+ $extension = $this->getExtension();
85
+ }
86
 
87
  $retina = new MediaLibraryThumbnailModel($filepath . $filebase . '@2x.' . $extension, $this->id, $this->size); // mind the dot in after 2x
88
  $retina->setName($this->size);
class/external/uncode.php CHANGED
@@ -29,7 +29,6 @@ class UncodeController
29
 
30
  // Check Webp
31
  $webpObj = $fs->getFile( (string) $fileObj->getFileDir() . $fileObj->getFileBase() . '.webp');
32
- Log::addTemp('Webp file path ' . $webpObj->getFullPath(), $webpObj);
33
  if ($webpObj->exists())
34
  $webpObj->delete();
35
 
29
 
30
  // Check Webp
31
  $webpObj = $fs->getFile( (string) $fileObj->getFileDir() . $fileObj->getFileBase() . '.webp');
 
32
  if ($webpObj->exists())
33
  $webpObj->delete();
34
 
class/external/wp-cli/wp-cli-base.php CHANGED
@@ -391,7 +391,7 @@ class SpioCommandBase
391
  protected function displayStatsLine($name, $stats)
392
  {
393
 
394
- $line = sprintf('Current Status for %s : (%s\%s) Done (%s%%), %s awaiting %s errors --', $name, $stats->done, $stats->total, $stats->percentage_done, ( $stats->awaiting ), $stats->fatal_errors);
395
 
396
  \WP_CLI::line($line);
397
  }
@@ -445,6 +445,7 @@ class SpioCommandBase
445
 
446
  \WP_CLI::Line("--- Current Status ---");
447
  \WP_CLI\Utils\format_items('table', $items, $fields);
 
448
  }
449
 
450
  /**
391
  protected function displayStatsLine($name, $stats)
392
  {
393
 
394
+ $line = sprintf('Current Status for %s : (%s\%s) Done (%s%%), %s awaiting %s errors --', $name, ($stats->done + $stats->fatal_errors), $stats->total, $stats->percentage_done, ( $stats->awaiting ), $stats->fatal_errors);
395
 
396
  \WP_CLI::line($line);
397
  }
445
 
446
  \WP_CLI::Line("--- Current Status ---");
447
  \WP_CLI\Utils\format_items('table', $items, $fields);
448
+ \WP_CLI::Line($this->displayStatsLine('Total', $startupData->total->stats));
449
  }
450
 
451
  /**
class/front/img-to-picture-webp.php CHANGED
@@ -18,6 +18,7 @@ class ShortPixelImgToPictureWebp
18
  }
19
 
20
  $new_content = $this->testPictures($content);
 
21
  if ($new_content !== false)
22
  {
23
  $content = $new_content;
@@ -128,7 +129,6 @@ class ShortPixelImgToPictureWebp
128
  protected function convertImage($match)
129
  {
130
  $fs = \wpSPIO()->filesystem();
131
-
132
  // Do nothing with images that have the 'sp-no-webp' class.
133
  if (strpos($match[0], 'sp-no-webp') || strpos($match[0], 'rev-sildebg')) {
134
  Log::addInfo('SPDBG convertImage skipped, sp-no-webp found');
@@ -136,7 +136,6 @@ class ShortPixelImgToPictureWebp
136
  }
137
 
138
  $img = $this->get_attributes($match[0]);
139
-
140
  if(isset($img['style']) && strpos($img['style'], 'background') !== false) {
141
  //don't replace for <img>'s that have background
142
  return $match[0];
@@ -162,7 +161,7 @@ class ShortPixelImgToPictureWebp
162
  $imageBase = apply_filters( 'shortpixel_webp_image_base', $this->getImageBase($srcInfo['value']), $srcInfo['value']);
163
 
164
  if($imageBase === false) {
165
- Log::addInfo('SPDBG baseurl doesn\'t match ' . $srcInfo['value'], array($imageBase) );
166
  return $match[0]; // . (isset($_GET['SHORTPIXEL_DEBUG']) ? '<!-- SPDBG baseurl doesn\'t match ' . $src . ' -->' : '');
167
  }
168
 
@@ -204,7 +203,7 @@ class ShortPixelImgToPictureWebp
204
  }
205
 
206
  // $defs = explode(",", $srcset);
207
- $mime = ''; // inint
208
 
209
  foreach ($definitions as $item) {
210
  $parts = preg_split('/\s+/', trim($item));
@@ -251,6 +250,9 @@ class ShortPixelImgToPictureWebp
251
  $srcsetWebP[] = $fileurl_base . $thisfile->getFileName() . $condition;
252
  break;
253
  }
 
 
 
254
  }
255
 
256
  //@todo This will not work with offloaded avifs.
@@ -264,8 +266,8 @@ class ShortPixelImgToPictureWebp
264
 
265
 
266
  if (count($srcsetWebP) == 0 && count($srcsetAvif) == 0) {
 
267
  return $match[0]; //. (isset($_GET['SHORTPIXEL_DEBUG']) ? '<!-- SPDBG no srcsetWebP found (' . $srcsetWebP . ') -->' : '');
268
- Log::addInfo(' SPDBG no srcsetWebP found (' . $srcsetWebP . ')');
269
  }
270
 
271
  //add the exclude class so if this content is processed again in other filter, the img is not converted again in picture
@@ -288,7 +290,6 @@ class ShortPixelImgToPictureWebp
288
 
289
  // $srcsetWebP = implode(',', $srcsetWebP);
290
 
291
-
292
  $output = '<picture ' . $this->create_attributes($imgpicture) . '>';
293
 
294
  if (is_array($srcsetAvif) && count($srcsetAvif) > 0)
@@ -305,7 +306,6 @@ class ShortPixelImgToPictureWebp
305
  .'<img ' . $srcPrefix . 'src="' . $src . '" ' . $this->create_attributes($img) . $idAttr . $altAttr . $heightAttr . $widthAttr
306
  . (strlen($srcset) ? ' srcset="' . $srcset . '"': '') . (strlen($sizes) ? ' sizes="' . $sizes . '"': '') . '>'
307
  .'</picture>';
308
-
309
  return $output;
310
  }
311
 
18
  }
19
 
20
  $new_content = $this->testPictures($content);
21
+
22
  if ($new_content !== false)
23
  {
24
  $content = $new_content;
129
  protected function convertImage($match)
130
  {
131
  $fs = \wpSPIO()->filesystem();
 
132
  // Do nothing with images that have the 'sp-no-webp' class.
133
  if (strpos($match[0], 'sp-no-webp') || strpos($match[0], 'rev-sildebg')) {
134
  Log::addInfo('SPDBG convertImage skipped, sp-no-webp found');
136
  }
137
 
138
  $img = $this->get_attributes($match[0]);
 
139
  if(isset($img['style']) && strpos($img['style'], 'background') !== false) {
140
  //don't replace for <img>'s that have background
141
  return $match[0];
161
  $imageBase = apply_filters( 'shortpixel_webp_image_base', $this->getImageBase($srcInfo['value']), $srcInfo['value']);
162
 
163
  if($imageBase === false) {
164
+ Log::addDebug('SPDBG baseurl doesn\'t match ' . $srcInfo['value'], array($imageBase) );
165
  return $match[0]; // . (isset($_GET['SHORTPIXEL_DEBUG']) ? '<!-- SPDBG baseurl doesn\'t match ' . $src . ' -->' : '');
166
  }
167
 
203
  }
204
 
205
  // $defs = explode(",", $srcset);
206
+ $mime = ''; // is_infinite
207
 
208
  foreach ($definitions as $item) {
209
  $parts = preg_split('/\s+/', trim($item));
250
  $srcsetWebP[] = $fileurl_base . $thisfile->getFileName() . $condition;
251
  break;
252
  }
253
+ else {
254
+ $srcsetWebP[] = $fileurl . $condition;
255
+ }
256
  }
257
 
258
  //@todo This will not work with offloaded avifs.
266
 
267
 
268
  if (count($srcsetWebP) == 0 && count($srcsetAvif) == 0) {
269
+
270
  return $match[0]; //. (isset($_GET['SHORTPIXEL_DEBUG']) ? '<!-- SPDBG no srcsetWebP found (' . $srcsetWebP . ') -->' : '');
 
271
  }
272
 
273
  //add the exclude class so if this content is processed again in other filter, the img is not converted again in picture
290
 
291
  // $srcsetWebP = implode(',', $srcsetWebP);
292
 
 
293
  $output = '<picture ' . $this->create_attributes($imgpicture) . '>';
294
 
295
  if (is_array($srcsetAvif) && count($srcsetAvif) > 0)
306
  .'<img ' . $srcPrefix . 'src="' . $src . '" ' . $this->create_attributes($img) . $idAttr . $altAttr . $heightAttr . $widthAttr
307
  . (strlen($srcset) ? ' srcset="' . $srcset . '"': '') . (strlen($sizes) ? ' sizes="' . $sizes . '"': '') . '>'
308
  .'</picture>';
 
309
  return $output;
310
  }
311
 
class/view/bulk/part-selection.php CHANGED
@@ -141,7 +141,8 @@ $approx = $this->view->approx;
141
  <div class="option"><?php esc_html_e('The total number of AVIF images will be calculated in the next step.','shortpixel-image-optimiser'); ?></div>
142
  </div>
143
  <?php else : ?>
144
- <div class="option warning"><?php esc_html_e('The creation of AVIF files is not possible with this license type.','shortpixel-image-optimiser'); ?>
 
145
 
146
  </div>
147
  </div>
141
  <div class="option"><?php esc_html_e('The total number of AVIF images will be calculated in the next step.','shortpixel-image-optimiser'); ?></div>
142
  </div>
143
  <?php else : ?>
144
+ <div class="option warning"><?php printf(esc_html__('The creation of AVIF files is not possible with this license type. %s Read more %s ','shortpixel-image-optimiser'), '<a href="https://shortpixel.com/knowledge-base/article/555-how-does-the-unlimited-plan-work" target="_blank">', '</a>'); ?>
145
+
146
 
147
  </div>
148
  </div>
class/view/bulk/part-summary.php CHANGED
@@ -73,7 +73,12 @@ namespace ShortPixel;
73
  </div>
74
 
75
  </div>
76
- <?php if(!$quotaData->unlimited) { ?>
 
 
 
 
 
77
  <div class="credits">
78
  <p class='heading'><span><?php esc_html_e('Your ShortPixel Credits Available', 'shortpixel-image-optimiser'); ?></span>
79
  <span><?php echo esc_html($this->formatNumber($quotaData->total->remaining, 0)) ?></span>
@@ -110,7 +115,8 @@ namespace ShortPixel;
110
  ?></span>
111
  </div>
112
  <?php $this->loadView('snippets/part-upgrade-options'); ?>
113
- <?php } ?>
 
114
 
115
  <div class='no-images' data-check-visibility="false" data-control="data-check-total-total">
116
  <?php esc_html_e('The current selection contains no images. The bulk process cannot start.', 'shortpixel-image-optimiser'); ?>
73
  </div>
74
 
75
  </div>
76
+ <?php
77
+ if(true === $quotaData->unlimited): ?>
78
+ <div class='credits'>
79
+ <p><span><?php _e('This site is currently on the ShortPixel Unlimited plan, so you do not have to worry about credits. Enjoy!', 'shortpixel-image-optimiser'); ?></span></p>
80
+ </div>
81
+ <?php else: ?>
82
  <div class="credits">
83
  <p class='heading'><span><?php esc_html_e('Your ShortPixel Credits Available', 'shortpixel-image-optimiser'); ?></span>
84
  <span><?php echo esc_html($this->formatNumber($quotaData->total->remaining, 0)) ?></span>
115
  ?></span>
116
  </div>
117
  <?php $this->loadView('snippets/part-upgrade-options'); ?>
118
+ <?php endif;
119
+ ?>
120
 
121
  <div class='no-images' data-check-visibility="false" data-control="data-check-total-total">
122
  <?php esc_html_e('The current selection contains no images. The bulk process cannot start.', 'shortpixel-image-optimiser'); ?>
readme.txt CHANGED
@@ -4,7 +4,7 @@ Tags: convert webp, optimize images, image optimization, resize, compressor, ima
4
  Requires at least: 4.8.0
5
  Tested up to: 6.1
6
  Requires PHP: 5.6
7
- Stable tag: 5.1.3
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -12,7 +12,7 @@ Speed up your website & boost your SEO by compressing old & new images and PDFs.
12
 
13
  == Description ==
14
 
15
- **A freemium, easy to use, comprehensive, stable, and frequently updated image compression plugin supported by the friendly team that created it. :)**
16
 
17
  Increase your website's SEO ranking, number of visitors, and ultimately your sales by optimising any image or PDF document on your website.
18
  ShortPixel is an easy to use, lightweight, install-and-forget-about-it <a href="https://shortpixel.com" target="_blank">image optimization</a> plugin that can compress all your past images and PDF documents with a single click. New images are automatically resized/rescaled and optimized on the fly, in the background. It's also compatible with any gallery, slider or eCommerce plugin.
@@ -28,6 +28,12 @@ Optimized images mean better user experience, better PageSpeed Insights or GTmet
28
 
29
  Make an instant <a href="https://shortpixel.com/image-compression-test" target="_blank">image compression test</a> of your site or <a href="https://shortpixel.com/online-image-compression" target="_blank">compress some images</a> to test our optimization algorithms.
30
 
 
 
 
 
 
 
31
  **New! Smart Cropping**
32
 
33
  With this new feature, all thumbnails used on your website are not only optimized, but also regenerated to fully display the subject of the image.
@@ -278,9 +284,18 @@ filters the URLs that will be sent to optimisation, `$URLs` is a plain array;
278
  `apply_filters('shortpixel/db/chunk_size', $chunk);`
279
  the `$chunk` is the value ShortPixel chooses to use as the number of selected records in one query (based on total table size), some hosts work better with a different value;
280
 
 
 
281
  `apply_filters('shortpixel/backup/paths', $PATHs, $mainPath);`
282
  filters the array of paths of the images sent for backup and can be used to exclude certain paths/images/thumbs from being backed up, based on the image path. `$mainPath` is the path of the main image, while `$PATHs` is an array with all files to be backed up (including thumbnails);
283
 
 
 
 
 
 
 
 
284
  `apply_filters('shortpixel/settings/image_sizes', $sizes);`
285
  filters the array (`$sizes`) of image sizes that can be excluded from processing (displayed in the plugin Advanced settings);
286
 
@@ -306,6 +321,9 @@ add_filter('shortpixel/init/optimize_on_screens', function ($screens) {
306
  });
307
  `
308
 
 
 
 
309
  In order to define custom thumbnails to be picked up by the optimization you have two options, both comma separated defines:
310
 
311
  `define('SHORTPIXEL_CUSTOM_THUMB_SUFFIXES', '_tl,_tr');`
@@ -348,6 +366,19 @@ Add HTTP basic authentication credentials by defining these constants in wp-conf
348
 
349
  == Changelog ==
350
 
 
 
 
 
 
 
 
 
 
 
 
 
 
351
  = 5.1.3 =
352
  Release date November 9, 2022
353
  * Fix: a typo related to Custom Media that caused an error when adding a new Custom Media folder;
4
  Requires at least: 4.8.0
5
  Tested up to: 6.1
6
  Requires PHP: 5.6
7
+ Stable tag: 5.1.4
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
12
 
13
  == Description ==
14
 
15
+ **An easy-to-use, comprehensive, lightweight, stable and frequently updated freemium image compression plugin supported by the friendly team that created it.**
16
 
17
  Increase your website's SEO ranking, number of visitors, and ultimately your sales by optimising any image or PDF document on your website.
18
  ShortPixel is an easy to use, lightweight, install-and-forget-about-it <a href="https://shortpixel.com" target="_blank">image optimization</a> plugin that can compress all your past images and PDF documents with a single click. New images are automatically resized/rescaled and optimized on the fly, in the background. It's also compatible with any gallery, slider or eCommerce plugin.
28
 
29
  Make an instant <a href="https://shortpixel.com/image-compression-test" target="_blank">image compression test</a> of your site or <a href="https://shortpixel.com/online-image-compression" target="_blank">compress some images</a> to test our optimization algorithms.
30
 
31
+ **<a href="https://shortpixel.com/spio-unlimited/" target="_blank">New Plan: ShortPixel Unlimited</a>**
32
+
33
+ This is the perfect monthly plan for single website owners.
34
+ It allows you to optimize an unlimited number of images with ShortPixel Image Optimizer on your website.
35
+ Read more details on our <a href="https://shortpixel.com/knowledge-base/article/555-how-does-the-unlimited-plan-work" target="_blank">dedicated page</a>.
36
+
37
  **New! Smart Cropping**
38
 
39
  With this new feature, all thumbnails used on your website are not only optimized, but also regenerated to fully display the subject of the image.
284
  `apply_filters('shortpixel/db/chunk_size', $chunk);`
285
  the `$chunk` is the value ShortPixel chooses to use as the number of selected records in one query (based on total table size), some hosts work better with a different value;
286
 
287
+ For version 4.22.10 and earlier:
288
+
289
  `apply_filters('shortpixel/backup/paths', $PATHs, $mainPath);`
290
  filters the array of paths of the images sent for backup and can be used to exclude certain paths/images/thumbs from being backed up, based on the image path. `$mainPath` is the path of the main image, while `$PATHs` is an array with all files to be backed up (including thumbnails);
291
 
292
+ For version 5.0.0 and later:
293
+
294
+ `apply_filters('shortpixel/image/skip_backup', false, $this->getFullPath(), $this->is_main_file)`
295
+ filters the images that are skipped or not from the backup. Return true for the type of images to be skipped in the backup. If you check if `is_main_file` is true and return false (do not skip backup), while while otherwise returning true, the backup will be kept only for the main image. We suggest using it in conjuction with this action that fires right after the restore from backup is done (to cleanup the meta data from the database, regenerate thumbnails after restoring the main file, etc.):
296
+
297
+ `do_action('shortpixel/image/after_restore', $this, $this->id, $cleanRestore);`
298
+
299
  `apply_filters('shortpixel/settings/image_sizes', $sizes);`
300
  filters the array (`$sizes`) of image sizes that can be excluded from processing (displayed in the plugin Advanced settings);
301
 
321
  });
322
  `
323
 
324
+ `add_filter('shortpixel/image/filecheck', function () { return true; });`
325
+ This filter forces a file check for WebP/AVIF in case they were manually removed from disk.
326
+
327
  In order to define custom thumbnails to be picked up by the optimization you have two options, both comma separated defines:
328
 
329
  `define('SHORTPIXEL_CUSTOM_THUMB_SUFFIXES', '_tl,_tr');`
366
 
367
  == Changelog ==
368
 
369
+ = 5.1.4 =
370
+ Release date November 28, 2022
371
+ * New: added a filter to force a file check for WebP/AVIF if they were manually deleted from disk;
372
+ * Fix: if only small WebPs are available, include the JPG version in the `picture` tag to avoid blurry images;
373
+ * Fix: the notification about unlisted thumbnails incorrectly reported WebP and AVIF files;
374
+ * Fix: improved integration with WP Offload Media by including Retina images in virtual/offload file checks;
375
+ * Fix: if the main file was optimized but some thumbnails did not have WebP/AVIF, it was not displayed correctly in the UI;
376
+ * Fix: added a % margin when generating WebPs/AVIF, so that files that are only a few bytes larger are also generated;
377
+ * Fix: when running WP-CLI, the percentage of finished items in the total was calculated incorrectly;
378
+ * Fix: the settings page crashed in certain cases for new accounts;
379
+ * Tweak: various CSS fixes and improvements on the Media Library, especially for cases with many thumbnails;
380
+ * Language: 2 new strings added, 2 updated, 0 fuzzed, and 0 deprecated.
381
+
382
  = 5.1.3 =
383
  Release date November 9, 2022
384
  * Fix: a typo related to Custom Media that caused an error when adding a new Custom Media folder;
res/css/shortpixel-admin.css CHANGED
@@ -168,6 +168,9 @@
168
  .sp-column-info .thumbnails.optimized .thumb-wrapper .thumb .optimize-bar .point.checked {
169
  background: #1abdca;
170
  }
 
 
 
171
  .sp-column-info .thumbnails.optimized:hover .thumb-wrapper {
172
  display: block;
173
  }
168
  .sp-column-info .thumbnails.optimized .thumb-wrapper .thumb .optimize-bar .point.checked {
169
  background: #1abdca;
170
  }
171
+ .sp-column-info .thumbnails.optimized .thumb-wrapper .thumb .cutoff {
172
+ float: right;
173
+ }
174
  .sp-column-info .thumbnails.optimized:hover .thumb-wrapper {
175
  display: block;
176
  }
res/css/shortpixel-admin.css.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sourceRoot":"","sources":["../scss/view/_edit-media.scss","../scss/elements/_animation.scss","../scss/view/_other-media.scss","../scss/view/_list-item.scss","../scss/view/_modal.scss","../scss/view/_debug.scss","../scss/shortpixel-admin.scss"],"names":[],"mappings":"AAII;EAEG;EACA;;AAGH;EAEE;;AAEA;EAEE;EACA;;AAOA;EAEE;EACA;;AAIN;EAEE;EACA;;AAEA;EAGE;EACA;EACA;;;AAQP;EC/CC;EACI;EACA;EACA;EACA;ED6CH;;AC3CF;EACC;IAAM;IAA2B;;;AAGlC;EACC;IAAM;IAA8B;;;AAGrC;EACC;IAAM;IAA+B;;;AAGtC;EACC;IAAM;IAAmC;;;AAG1C;EACC;IAAM;IAAgC;;;;ADmCjC;EAEC;EACA;;AAEF;EACC;;AAUJ;EAAS;;AACT;EAAO;;;AEzEP;EAEG;EACA;EACA;;AAIL;EAEC;EACA;;AACA;EDdA;EACI;EACA;EACA;EACA;ECYF;;ADVH;EACC;IAAM;IAA2B;;;AAGlC;EACC;IAAM;IAA8B;;;AAGrC;EACC;IAAM;IAA+B;;;AAGtC;EACC;IAAM;IAAmC;;;AAG1C;EACC;IAAM;IAAgC;;;;AExBxC;EAEE;;AAEA;EAEE;;AAKA;EAEK;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACJ;;AACI;EAEI;EACA;;AAEL;EACC;EACA;EACA;EACA;;AAEI;EACK;EACA;EACA;EACA;EACA;EACA;;AAEC;EAEG;EACA;EAEA;EACA;;AAEA;EACE;;AAOhB;EACI;;AAKV;EAEG;EACA;EACA;;AAEH;EAEG;;AACA;EACI;;AAIJ;EAAkB;;AAGrB;EAAK;;AACL;EACI;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEG;EACA;EACA;;;AASP;EAEG;EACA;EACF;;AACA;EF1GD;EACI;EACA;EACA;EACA;EEwGF;;AFtGH;EACC;IAAM;IAA2B;;;AAGlC;EACC;IAAM;IAA8B;;;AAGrC;EACC;IAAM;IAA+B;;;AAGtC;EACC;IAAM;IAAmC;;;AAG1C;EACC;IAAM;IAAgC;;;;AGzBxC;EACI;AAAe;EACf;AAAiB;EACjB;AAAgB;EAChB;EACA;EACA;AAAa;EACb;AAAc;EACd;AAAgB;EAChB;AAAwB;EACxB;AAA6B;EAC7B;;;AAEJ;EACI;AACA;EACA;EACA;EACA;AAAY;EACZ;AAAkB;EAClB;AAAiB;EACjB;EACA;EACA;EACA;EACA;;AACA;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACI;EACA;EACA;;;AAKR;EACI;;;AAEJ;EACI;;;AC/CJ;EACE;;;AAGF;EAEC;;AACA;EACC;;AAED;EAEC;;;AAKF;EACC;EACA;EACA;EACA;EACA;EACA;EACC;EACA;EAED;EACA;EACA;EAEA;EAGA;EACA;;AAEA;EAEE;;AAGF;EACE;;AACA;EAAK;;AAGP;EACE;;AAIF;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACC;EACA;;AAIH;EACC;EAIA;;;AAKF;EAEE;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AC/FD;EACI;;;AAIJ;EAEE;;;AAGF;EAGC;EACA;EACA;;AAEA;EACC;;AAEA;EACC;;AAGF;EAAQ;;AACP;EAA0B;;AAC1B;EACC;EACA;;AAED;EACC;EACA;;AAED;EAAiC;;AAElC;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;EACH;EACA;;AAEE;EAAiB;;AACjB;EACC","file":"shortpixel-admin.css"}
1
+ {"version":3,"sourceRoot":"","sources":["../scss/view/_edit-media.scss","../scss/elements/_animation.scss","../scss/view/_other-media.scss","../scss/view/_list-item.scss","../scss/view/_modal.scss","../scss/view/_debug.scss","../scss/shortpixel-admin.scss"],"names":[],"mappings":"AAII;EAEG;EACA;;AAGH;EAEE;;AAEA;EAEE;EACA;;AAOA;EAEE;EACA;;AAIN;EAEE;EACA;;AAEA;EAGE;EACA;EACA;;;AAQP;EC/CC;EACI;EACA;EACA;EACA;ED6CH;;AC3CF;EACC;IAAM;IAA2B;;;AAGlC;EACC;IAAM;IAA8B;;;AAGrC;EACC;IAAM;IAA+B;;;AAGtC;EACC;IAAM;IAAmC;;;AAG1C;EACC;IAAM;IAAgC;;;;ADmCjC;EAEC;EACA;;AAEF;EACC;;AAUJ;EAAS;;AACT;EAAO;;;AEzEP;EAEG;EACA;EACA;;AAIL;EAEC;EACA;;AACA;EDdA;EACI;EACA;EACA;EACA;ECYF;;ADVH;EACC;IAAM;IAA2B;;;AAGlC;EACC;IAAM;IAA8B;;;AAGrC;EACC;IAAM;IAA+B;;;AAGtC;EACC;IAAM;IAAmC;;;AAG1C;EACC;IAAM;IAAgC;;;;AExBxC;EAEE;;AAEA;EAEE;;AAKA;EAEK;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACJ;;AACI;EAEI;EACA;;AAEL;EACC;EACA;EACA;EACA;;AAEI;EACK;EACA;EACA;EACA;EACA;EACA;;AAEC;EAEG;EACA;EAEA;EACA;;AAEA;EACE;;AAIjB;EACE;;AAKD;EACI;;AAKV;EAEG;EACA;EACA;;AAEH;EAEG;;AACA;EACI;;AAIJ;EAAkB;;AAGrB;EAAK;;AACL;EACI;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEG;EACA;EACA;;;AASP;EAEG;EACA;EACF;;AACA;EF7GD;EACI;EACA;EACA;EACA;EE2GF;;AFzGH;EACC;IAAM;IAA2B;;;AAGlC;EACC;IAAM;IAA8B;;;AAGrC;EACC;IAAM;IAA+B;;;AAGtC;EACC;IAAM;IAAmC;;;AAG1C;EACC;IAAM;IAAgC;;;;AGzBxC;EACI;AAAe;EACf;AAAiB;EACjB;AAAgB;EAChB;EACA;EACA;AAAa;EACb;AAAc;EACd;AAAgB;EAChB;AAAwB;EACxB;AAA6B;EAC7B;;;AAEJ;EACI;AACA;EACA;EACA;EACA;AAAY;EACZ;AAAkB;EAClB;AAAiB;EACjB;EACA;EACA;EACA;EACA;;AACA;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACI;EACA;EACA;;;AAKR;EACI;;;AAEJ;EACI;;;AC/CJ;EACE;;;AAGF;EAEC;;AACA;EACC;;AAED;EAEC;;;AAKF;EACC;EACA;EACA;EACA;EACA;EACA;EACC;EACA;EAED;EACA;EACA;EAEA;EAGA;EACA;;AAEA;EAEE;;AAGF;EACE;;AACA;EAAK;;AAGP;EACE;;AAIF;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACC;EACA;;AAIH;EACC;EAIA;;;AAKF;EAEE;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AC/FD;EACI;;;AAIJ;EAEE;;;AAGF;EAGC;EACA;EACA;;AAEA;EACC;;AAEA;EACC;;AAGF;EAAQ;;AACP;EAA0B;;AAC1B;EACC;EACA;;AAED;EACC;EACA;;AAED;EAAiC;;AAElC;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;EACH;EACA;;AAEE;EAAiB;;AACjB;EACC","file":"shortpixel-admin.css"}
res/scss/view/_list-item.scss CHANGED
@@ -53,6 +53,9 @@
53
  }
54
  }
55
  }
 
 
 
56
  }
57
  } // wrapper
58
  &:hover {
53
  }
54
  }
55
  }
56
+ .cutoff {
57
+ float:right;
58
+ }
59
  }
60
  } // wrapper
61
  &:hover {
wp-shortpixel.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: ShortPixel Image Optimizer
4
  * Plugin URI: https://shortpixel.com/
5
  * Description: ShortPixel optimizes images automatically, while guarding the quality of your images. Check your <a href="/wp-admin/options-general.php?page=wp-shortpixel-settings" target="_blank">Settings &gt; ShortPixel</a> page on how to start optimizing your image library and make your website load faster.
6
- * Version: 5.1.3
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  * GitHub Plugin URI: https://github.com/short-pixel-optimizer/shortpixel-image-optimiser
@@ -31,7 +31,7 @@ if (! defined('SHORTPIXEL_RESET_ON_ACTIVATE'))
31
  define('SHORTPIXEL_PLUGIN_FILE', __FILE__);
32
  define('SHORTPIXEL_PLUGIN_DIR', __DIR__);
33
 
34
- define('SHORTPIXEL_IMAGE_OPTIMISER_VERSION', "5.1.3");
35
 
36
  define('SHORTPIXEL_BACKUP', 'ShortpixelBackups');
37
  define('SHORTPIXEL_MAX_FAIL_RETRIES', 3);
3
  * Plugin Name: ShortPixel Image Optimizer
4
  * Plugin URI: https://shortpixel.com/
5
  * Description: ShortPixel optimizes images automatically, while guarding the quality of your images. Check your <a href="/wp-admin/options-general.php?page=wp-shortpixel-settings" target="_blank">Settings &gt; ShortPixel</a> page on how to start optimizing your image library and make your website load faster.
6
+ * Version: 5.1.4
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  * GitHub Plugin URI: https://github.com/short-pixel-optimizer/shortpixel-image-optimiser
31
  define('SHORTPIXEL_PLUGIN_FILE', __FILE__);
32
  define('SHORTPIXEL_PLUGIN_DIR', __DIR__);
33
 
34
+ define('SHORTPIXEL_IMAGE_OPTIMISER_VERSION', "5.1.4");
35
 
36
  define('SHORTPIXEL_BACKUP', 'ShortpixelBackups');
37
  define('SHORTPIXEL_MAX_FAIL_RETRIES', 3);